From f3f66ab06357c054de743b0d2d7920ba2fa0e0bf Mon Sep 17 00:00:00 2001 From: udx Date: Mon, 21 Sep 2026 14:21:07 +0800 Subject: [PATCH] Initial commit: AIGame Unity client with URP, HybridCLR, YooAsset and tooling. Co-authored-by: Cursor --- .claude/skills/unity-pipeline/SKILL.md | 173 + .cursor/rules/aigame-basics.mdc | 16 + .cursor/skills/unity-pipeline/SKILL.md | 173 + .gitignore | 53 + AIClient/.vsconfig | 6 + AIClient/Assets/Editor.meta | 8 + AIClient/Assets/Editor/SetupHybridClr.cs | 22 + AIClient/Assets/Editor/SetupHybridClr.cs.meta | 11 + AIClient/Assets/Editor/SetupUrp.cs | 72 + AIClient/Assets/Editor/SetupUrp.cs.meta | 11 + AIClient/Assets/Scenes.meta | 8 + AIClient/Assets/Scenes/SampleScene.unity | 267 + AIClient/Assets/Scenes/SampleScene.unity.meta | 7 + AIClient/Assets/Settings.meta | 8 + AIClient/Assets/Settings/URP.meta | 8 + .../URP/ForwardRenderer 0VeryLowQuality.asset | 386 + ...ForwardRenderer 0VeryLowQuality.asset.meta | 8 + .../URP/ForwardRenderer 1LowQuality.asset | 386 + .../ForwardRenderer 1LowQuality.asset.meta | 8 + .../URP/ForwardRenderer 2MediumQuality.asset | 386 + .../ForwardRenderer 2MediumQuality.asset.meta | 8 + .../URP/ForwardRenderer 3HighQuality.asset | 386 + .../ForwardRenderer 3HighQuality.asset.meta | 8 + .../ForwardRenderer 4VeryHighQuality.asset | 575 ++ ...orwardRenderer 4VeryHighQuality.asset.meta | 8 + .../URP/UniversalRP-0VeryLowQuality.asset | 114 + .../UniversalRP-0VeryLowQuality.asset.meta | 8 + .../URP/UniversalRP-1LowQuality.asset | 114 + .../URP/UniversalRP-1LowQuality.asset.meta | 8 + .../URP/UniversalRP-2MediumQuality.asset | 114 + .../URP/UniversalRP-2MediumQuality.asset.meta | 8 + .../URP/UniversalRP-3HighQuality.asset | 114 + .../URP/UniversalRP-3HighQuality.asset.meta | 8 + .../URP/UniversalRP-4VeryHighQuality.asset | 114 + .../UniversalRP-4VeryHighQuality.asset.meta | 8 + ...niversalRenderPipelineGlobalSettings.asset | 34 + ...salRenderPipelineGlobalSettings.asset.meta | 8 + AIClient/Assets/_PipelineRefresh.stamp.txt | 1 + .../Assets/_PipelineRefresh.stamp.txt.meta | 7 + .../com.unity.pipeline/.attestation.p7m | Bin 0 -> 10926 bytes .../.claude/skills/unity-pipeline/SKILL.md | 173 + .../Packages/com.unity.pipeline/.signature | 1 + .../Packages/com.unity.pipeline/CHANGELOG.md | 158 + .../com.unity.pipeline/CHANGELOG.md.meta | 7 + .../Packages/com.unity.pipeline/CLAUDE.md | 64 + .../com.unity.pipeline/CLAUDE.md.meta | 7 + .../Packages/com.unity.pipeline/CODEOWNERS | 2 + .../com.unity.pipeline/CODEOWNERS.meta | 7 + .../Packages/com.unity.pipeline/CodeGen.meta | 8 + .../CodeReloadInPlaceILPostProcessor.cs | 460 + .../CodeReloadInPlaceILPostProcessor.cs.meta | 11 + .../CodeGen/Unity.Pipeline.CodeGen.asmdef | 21 + .../Unity.Pipeline.CodeGen.asmdef.meta | 7 + .../Documentation~/TableOfContents.md | 28 + .../Documentation~/analytics.md | 138 + .../Documentation~/authoring-commands.md | 319 + .../Documentation~/code-reload.md | 177 + .../Documentation~/commands/animation.md | 191 + .../commands/assets-and-files.md | 150 + .../Documentation~/commands/baking.md | 140 + .../Documentation~/commands/batch.md | 102 + .../commands/build-and-compilation.md | 188 + .../Documentation~/commands/capture.md | 61 + .../editor-lifecycle-and-observability.md | 187 + .../commands/gameobjects-and-components.md | 169 + .../Documentation~/commands/materials.md | 55 + .../Documentation~/commands/navigation.md | 32 + .../commands/package-manager.md | 70 + .../Documentation~/commands/prefabs.md | 84 + .../commands/project-settings.md | 270 + .../Documentation~/commands/runtime.md | 213 + .../Documentation~/commands/scenes.md | 93 + .../Documentation~/commands/scripts.md | 111 + .../Documentation~/commands/wait.md | 169 + .../Documentation~/connectivity.md | 541 + .../Documentation~/creating-commands.md | 347 + .../Documentation~/filter.yml | 20 + .../images/codereload-watcher-panel.png | Bin 0 -> 45951 bytes .../Documentation~/index.md | 272 + .../Documentation~/runtime-setup.md | 80 + .../Documentation~/safety-and-mutations.md | 90 + .../Documentation~/testing.md | 95 + .../Packages/com.unity.pipeline/Editor.meta | 8 + .../com.unity.pipeline/Editor/Authoring.meta | 8 + .../Editor/Authoring/AuthoringUndoScope.cs | 58 + .../Authoring/AuthoringUndoScope.cs.meta | 11 + .../Editor/Authoring/ObjectResolver.cs | 256 + .../Editor/Authoring/ObjectResolver.cs.meta | 11 + .../Editor/Authoring/ProjectPaths.cs | 148 + .../Editor/Authoring/ProjectPaths.cs.meta | 11 + .../Editor/BuildProcessors.meta | 8 + .../CodeReloadLinkXmlGenerator.cs | 355 + .../CodeReloadLinkXmlGenerator.cs.meta | 11 + .../PipelineRuntimeBuildProcessor.cs | 375 + .../PipelineRuntimeBuildProcessor.cs.meta | 11 + .../Editor/CliEditorProgress.cs | 51 + .../Editor/CliEditorProgress.cs.meta | 10 + .../com.unity.pipeline/Editor/Commands.meta | 8 + .../Editor/Commands/Animation.meta | 8 + .../Animation/AnimationClipCommands.cs | 427 + .../Animation/AnimationClipCommands.cs.meta | 2 + .../Animation/AnimatorControllerCommands.cs | 891 ++ .../AnimatorControllerCommands.cs.meta | 2 + .../Commands/Animation/TimelineCommands.cs | 641 ++ .../Animation/TimelineCommands.cs.meta | 2 + .../Commands/Animation/TimelineGuard.cs | 58 + .../Commands/Animation/TimelineGuard.cs.meta | 2 + .../Editor/Commands/Assets.meta | 8 + .../Editor/Commands/Assets/AssetCommands.cs | 585 ++ .../Commands/Assets/AssetCommands.cs.meta | 2 + .../Commands/Assets/AssetImportCommands.cs | 660 ++ .../Assets/AssetImportCommands.cs.meta | 2 + .../Commands/Assets/FindAssetsResult.cs | 34 + .../Commands/Assets/FindAssetsResult.cs.meta | 2 + .../Editor/Commands/Assets/FolderCommands.cs | 51 + .../Commands/Assets/FolderCommands.cs.meta | 11 + .../Commands/Assets/TextFileCommands.cs | 126 + .../Commands/Assets/TextFileCommands.cs.meta | 2 + .../Editor/Commands/Authoring.meta | 8 + .../Authoring/AuthoringConfigCommands.cs | 29 + .../Authoring/AuthoringConfigCommands.cs.meta | 11 + .../Editor/Commands/AutoTickCommand.cs | 194 + .../Editor/Commands/AutoTickCommand.cs.meta | 11 + .../Editor/Commands/Baking.meta | 8 + .../Editor/Commands/Baking/BakeSceneGuard.cs | 42 + .../Commands/Baking/BakeSceneGuard.cs.meta | 11 + .../Commands/Baking/LightingBakeCommands.cs | 646 ++ .../Baking/LightingBakeCommands.cs.meta | 11 + .../Commands/Baking/NavMeshBakeCommands.cs | 430 + .../Baking/NavMeshBakeCommands.cs.meta | 11 + .../Commands/Baking/OcclusionBakeCommands.cs | 271 + .../Baking/OcclusionBakeCommands.cs.meta | 11 + .../Editor/Commands/Batch.meta | 8 + .../Editor/Commands/Batch/BatchCommand.cs | 660 ++ .../Commands/Batch/BatchCommand.cs.meta | 11 + .../Editor/Commands/Batch/BatchInput.cs | 43 + .../Editor/Commands/Batch/BatchInput.cs.meta | 11 + .../Commands/Batch/BatchReferenceResolver.cs | 175 + .../Batch/BatchReferenceResolver.cs.meta | 11 + .../Editor/Commands/Batch/BatchResult.cs | 101 + .../Editor/Commands/Batch/BatchResult.cs.meta | 11 + .../Editor/Commands/Build.meta | 8 + .../Editor/Commands/Build/BuildCommand.cs | 596 ++ .../Commands/Build/BuildCommand.cs.meta | 11 + .../Commands/Build/BuildConfigCommands.cs | 347 + .../Build/BuildConfigCommands.cs.meta | 2 + .../Editor/Commands/Build/BuildModels.cs | 271 + .../Editor/Commands/Build/BuildModels.cs.meta | 11 + .../Build/SwitchBuildTargetCommand.cs | 245 + .../Build/SwitchBuildTargetCommand.cs.meta | 2 + .../Editor/Commands/Capture.meta | 8 + .../Commands/Capture/CaptureCommands.cs | 428 + .../Commands/Capture/CaptureCommands.cs.meta | 11 + .../Commands/CaptureEditorElementCommand.cs | 78 + .../CaptureEditorElementCommand.cs.meta | 11 + .../Editor/Commands/EditorStatusCommand.cs | 63 + .../Commands/EditorStatusCommand.cs.meta | 11 + .../Editor/Commands/FocusEditorCommand.cs | 124 + .../Commands/FocusEditorCommand.cs.meta | 11 + .../Editor/Commands/GameObjects.meta | 8 + .../Commands/GameObjects/ComponentCommands.cs | 214 + .../GameObjects/ComponentCommands.cs.meta | 2 + .../GameObjects/ComponentPropertiesResult.cs | 25 + .../ComponentPropertiesResult.cs.meta | 2 + .../GameObjects/CreateGameObjectsResult.cs | 26 + .../CreateGameObjectsResult.cs.meta | 11 + .../GameObjects/FindGameObjectsResult.cs | 25 + .../GameObjects/FindGameObjectsResult.cs.meta | 2 + .../GameObjects/GameObjectCommands.cs | 538 + .../GameObjects/GameObjectCommands.cs.meta | 2 + .../SerializedPropertyConverter.cs | 224 + .../SerializedPropertyConverter.cs.meta | 2 + .../Commands/GameObjects/TypeResolver.cs | 82 + .../Commands/GameObjects/TypeResolver.cs.meta | 2 + .../Editor/Commands/Materials.meta | 8 + .../Commands/Materials/MaterialCommands.cs | 405 + .../Materials/MaterialCommands.cs.meta | 2 + .../Commands/Materials/MaterialResults.cs | 147 + .../Materials/MaterialResults.cs.meta | 2 + .../Materials/MaterialValueConverter.cs | 310 + .../Materials/MaterialValueConverter.cs.meta | 2 + .../Commands/Materials/ShaderCommands.cs | 188 + .../Commands/Materials/ShaderCommands.cs.meta | 2 + .../Editor/Commands/MenuItemCommand.cs | 249 + .../Editor/Commands/MenuItemCommand.cs.meta | 2 + .../Editor/Commands/Navigation.meta | 8 + .../Commands/Navigation/NavigationCommands.cs | 303 + .../Navigation/NavigationCommands.cs.meta | 11 + .../Editor/Commands/Observability.meta | 8 + .../Observability/PerformanceCommands.cs | 171 + .../Observability/PerformanceCommands.cs.meta | 11 + .../Editor/Commands/PackageManager.meta | 8 + .../PackageManager/PackageIdentifier.cs | 161 + .../PackageManager/PackageIdentifier.cs.meta | 11 + .../PackageManager/PackageManagerCommand.cs | 656 ++ .../PackageManagerCommand.cs.meta | 11 + .../PackageManager/PackageManifest.cs | 78 + .../PackageManager/PackageManifest.cs.meta | 11 + .../Commands/PackageManager/PackageModels.cs | 209 + .../PackageManager/PackageModels.cs.meta | 11 + .../Editor/Commands/PlayModeCommands.cs | 55 + .../Editor/Commands/PlayModeCommands.cs.meta | 11 + .../Editor/Commands/Prefabs.meta | 8 + .../Editor/Commands/Prefabs/PrefabCommands.cs | 416 + .../Commands/Prefabs/PrefabCommands.cs.meta | 2 + .../Editor/Commands/ProjectAudit.meta | 8 + .../ProjectAudit/ProjectAuditCommands.cs | 604 ++ .../ProjectAudit/ProjectAuditCommands.cs.meta | 11 + .../Editor/Commands/ProjectSettings.meta | 8 + .../ProjectSettings/AudioSettingsCommands.cs | 116 + .../AudioSettingsCommands.cs.meta | 11 + .../GraphicsSettingsCommands.cs | 87 + .../GraphicsSettingsCommands.cs.meta | 11 + .../ProjectSettings/InputSettingsCommands.cs | 150 + .../InputSettingsCommands.cs.meta | 11 + .../PhysicsSettingsCommands.cs | 98 + .../PhysicsSettingsCommands.cs.meta | 11 + .../ProjectSettings/PlayerSettingsCommands.cs | 122 + .../PlayerSettingsCommands.cs.meta | 11 + .../ProjectSettings/ProjectSettingsAsset.cs | 23 + .../ProjectSettingsAsset.cs.meta | 11 + .../ProjectSettings/ProjectSettingsCommand.cs | 145 + .../ProjectSettingsCommand.cs.meta | 11 + .../ProjectSettingsResponse.cs | 65 + .../ProjectSettingsResponse.cs.meta | 11 + .../QualitySettingsCommands.cs | 95 + .../QualitySettingsCommands.cs.meta | 11 + .../RuntimePipelineSettingsCommands.cs | 151 + .../RuntimePipelineSettingsCommands.cs.meta | 11 + .../ProjectSettings/TagsLayersCommands.cs | 143 + .../TagsLayersCommands.cs.meta | 11 + .../ProjectSettings/TimeSettingsCommands.cs | 80 + .../TimeSettingsCommands.cs.meta | 11 + .../Editor/Commands/PushReloadCommand.cs | 509 + .../Editor/Commands/PushReloadCommand.cs.meta | 11 + .../Editor/Commands/RecompileCommand.cs | 211 + .../Editor/Commands/RecompileCommand.cs.meta | 11 + .../Editor/Commands/Scenes.meta | 8 + .../Editor/Commands/Scenes/SceneCommands.cs | 395 + .../Commands/Scenes/SceneCommands.cs.meta | 2 + .../Editor/Commands/Scenes/SceneHierarchy.cs | 82 + .../Commands/Scenes/SceneHierarchy.cs.meta | 2 + .../Editor/Commands/ScreenshotCommand.cs | 198 + .../Editor/Commands/ScreenshotCommand.cs.meta | 2 + .../Editor/Commands/Scripts.meta | 8 + .../Commands/Scripts/AttachScriptCommand.cs | 139 + .../Scripts/AttachScriptCommand.cs.meta | 2 + .../Commands/Scripts/CreateScriptCommand.cs | 164 + .../Scripts/CreateScriptCommand.cs.meta | 2 + .../Commands/Scripts/RunScriptCommand.cs | 664 ++ .../Commands/Scripts/RunScriptCommand.cs.meta | 11 + .../Commands/Scripts/ScriptTypeResolver.cs | 161 + .../Scripts/ScriptTypeResolver.cs.meta | 2 + .../Scripts/SerializedFieldCommands.cs | 239 + .../Scripts/SerializedFieldCommands.cs.meta | 2 + .../Scripts/SerializedPropertyConverter.cs | 237 + .../SerializedPropertyConverter.cs.meta | 2 + .../Editor/Commands/TestCommands.cs | 219 + .../Editor/Commands/TestCommands.cs.meta | 11 + .../Editor/Commands/WaitConditionEvaluator.cs | 786 ++ .../Commands/WaitConditionEvaluator.cs.meta | 11 + .../Editor/Commands/WaitForCommands.cs | 515 + .../Editor/Commands/WaitForCommands.cs.meta | 11 + .../Editor/Commands/WaitRegistry.cs | 596 ++ .../Editor/Commands/WaitRegistry.cs.meta | 11 + .../com.unity.pipeline/Editor/Console.meta | 8 + .../Console/EditorConsoleCaptureBootstrap.cs | 76 + .../EditorConsoleCaptureBootstrap.cs.meta | 2 + .../Editor/Console/EditorConsoleEntries.cs | 224 + .../Console/EditorConsoleEntries.cs.meta | 11 + .../Console/EditorConsoleGroundTruth.cs | 254 + .../Console/EditorConsoleGroundTruth.cs.meta | 11 + .../Editor/EditorCodeReloadWatcher.cs | 694 ++ .../Editor/EditorCodeReloadWatcher.cs.meta | 11 + .../Editor/EditorDialogStateMirror.cs | 52 + .../Editor/EditorDialogStateMirror.cs.meta | 10 + .../Editor/EditorPipelineManager.cs | 105 + .../Editor/EditorPipelineManager.cs.meta | 11 + .../Editor/EditorPipelineManagerEditor.cs | 196 + .../EditorPipelineManagerEditor.cs.meta | 11 + .../Editor/EditorPipelineServer.cs | 372 + .../Editor/EditorPipelineServer.cs.meta | 11 + .../Editor/EditorPipelineStartup.cs | 345 + .../Editor/EditorPipelineStartup.cs.meta | 11 + .../Editor/EditorProgressMirror.cs | 67 + .../Editor/EditorProgressMirror.cs.meta | 10 + .../Editor/PipelineAnalytics.cs | 17 + .../Editor/PipelineAnalytics.cs.meta | 11 + .../Editor/PipelineTransactionLog.cs | 169 + .../Editor/PipelineTransactionLog.cs.meta | 2 + .../com.unity.pipeline/Editor/PushSigner.cs | 273 + .../Editor/PushSigner.cs.meta | 2 + .../Editor/PushSigningKey.cs | 78 + .../Editor/PushSigningKey.cs.meta | 2 + .../Editor/RuntimePipelineConfigEditor.cs | 116 + .../RuntimePipelineConfigEditor.cs.meta | 11 + .../Editor/RuntimePipelineSettingsProvider.cs | 89 + .../RuntimePipelineSettingsProvider.cs.meta | 11 + .../com.unity.pipeline/Editor/Testing.meta | 8 + .../Editor/Testing/PipelineTestRunner.cs | 836 ++ .../Editor/Testing/PipelineTestRunner.cs.meta | 11 + .../Editor/Testing/TestResultCollector.cs | 182 + .../Testing/TestResultCollector.cs.meta | 11 + .../Editor/TypeCacheCommandDiscovery.cs | 25 + .../Editor/TypeCacheCommandDiscovery.cs.meta | 11 + .../Editor/Unity.Pipeline.Editor.asmdef | 21 + .../Editor/Unity.Pipeline.Editor.asmdef.meta | 7 + .../Packages/com.unity.pipeline/LICENSE.md | 5 + .../com.unity.pipeline/LICENSE.md.meta | 7 + .../Packages/com.unity.pipeline/README.md | 91 + .../com.unity.pipeline/README.md.meta | 7 + .../Packages/com.unity.pipeline/Runtime.meta | 8 + .../com.unity.pipeline/Runtime/Analyzers.meta | 8 + .../Analyzers/IlInterpreterAnalyzer.dll | Bin 0 -> 18944 bytes .../Analyzers/IlInterpreterAnalyzer.dll.meta | 39 + .../Runtime/AssemblyInfo.cs | 10 + .../Runtime/AssemblyInfo.cs.meta | 11 + .../Runtime/Attributes.meta | 8 + .../Attributes/CodeReloadAttributes.cs | 71 + .../Attributes/CodeReloadAttributes.cs.meta | 11 + .../Unity.Pipeline.Attributes.asmdef | 14 + .../Unity.Pipeline.Attributes.asmdef.meta | 7 + .../Runtime/CodeReload.meta | 8 + .../CodeReload/AccessibilityValidator.cs | 211 + .../CodeReload/AccessibilityValidator.cs.meta | 11 + .../Runtime/CodeReload/CodeReloadActivity.cs | 67 + .../CodeReload/CodeReloadActivity.cs.meta | 11 + .../Runtime/CodeReload/CodeReloadBaseline.cs | 295 + .../CodeReload/CodeReloadBaseline.cs.meta | 2 + .../Runtime/CodeReload/CodeReloadRegistry.cs | 673 ++ .../CodeReload/CodeReloadRegistry.cs.meta | 11 + .../CodeReload/InPlaceReloadProcessor.cs | 703 ++ .../CodeReload/InPlaceReloadProcessor.cs.meta | 11 + .../CodeReload/PipelineCodeReloadConnect.cs | 195 + .../PipelineCodeReloadConnect.cs.meta | 11 + .../Runtime/CodeReload/PushEnvelope.cs | 336 + .../Runtime/CodeReload/PushEnvelope.cs.meta | 2 + .../CodeReload/SourceCodeTransformer.cs | 590 ++ .../CodeReload/SourceCodeTransformer.cs.meta | 11 + .../com.unity.pipeline/Runtime/Commands.meta | 8 + .../Commands/CaptureRuntimeElementCommand.cs | 144 + .../CaptureRuntimeElementCommand.cs.meta | 11 + .../Runtime/Commands/CodeEvalCommand.cs | 163 + .../Runtime/Commands/CodeEvalCommand.cs.meta | 11 + .../Runtime/Commands/CodeReloadCommands.cs | 455 + .../Commands/CodeReloadCommands.cs.meta | 11 + .../Runtime/Commands/ConsoleCommand.cs | 118 + .../Runtime/Commands/ConsoleCommand.cs.meta | 2 + .../Runtime/Commands/EvalTelemetryCommand.cs | 43 + .../Commands/EvalTelemetryCommand.cs.meta | 11 + .../Commands/RuntimeApplicationCommand.cs | 89 + .../RuntimeApplicationCommand.cs.meta | 11 + .../Runtime/Commands/RuntimeInputCommand.cs | 182 + .../Commands/RuntimeInputCommand.cs.meta | 11 + .../Runtime/Commands/RuntimeLogCommand.cs | 49 + .../Commands/RuntimeLogCommand.cs.meta | 11 + .../Runtime/Commands/RuntimeStatusCommand.cs | 217 + .../Commands/RuntimeStatusCommand.cs.meta | 11 + .../Commands/VisualElementCaptureSupport.cs | 444 + .../VisualElementCaptureSupport.cs.meta | 11 + .../com.unity.pipeline/Runtime/Common.meta | 8 + .../Runtime/Common/BasePipelineServer.cs | 2713 +++++ .../Runtime/Common/BasePipelineServer.cs.meta | 11 + .../Runtime/Common/CliArgAttribute.cs | 51 + .../Runtime/Common/CliArgAttribute.cs.meta | 11 + .../Runtime/Common/CliCommandAttribute.cs | 57 + .../Common/CliCommandAttribute.cs.meta | 11 + .../Runtime/Common/CliProgress.cs | 234 + .../Runtime/Common/CliProgress.cs.meta | 10 + .../Runtime/Common/CommandExecutionInfo.cs | 91 + .../Common/CommandExecutionInfo.cs.meta | 11 + .../Runtime/Common/CommandInfo.cs | 101 + .../Runtime/Common/CommandInfo.cs.meta | 11 + .../Runtime/Common/CommandLineBinder.cs | 537 + .../Runtime/Common/CommandLineBinder.cs.meta | 11 + .../Runtime/Common/CommandLineTokenizer.cs | 139 + .../Common/CommandLineTokenizer.cs.meta | 11 + .../Runtime/Common/CommandRegistry.cs | 400 + .../Runtime/Common/CommandRegistry.cs.meta | 11 + .../Runtime/Common/DialogStateTracker.cs | 102 + .../Runtime/Common/DialogStateTracker.cs.meta | 10 + .../Runtime/Common/Dispatcher.cs | 299 + .../Runtime/Common/Dispatcher.cs.meta | 11 + .../Runtime/Common/ExecResponseSerializer.cs | 141 + .../Common/ExecResponseSerializer.cs.meta | 11 + .../Runtime/Common/FilePermissions.cs | 110 + .../Runtime/Common/FilePermissions.cs.meta | 11 + .../Runtime/Common/ICommandDiscovery.cs | 20 + .../Runtime/Common/ICommandDiscovery.cs.meta | 11 + .../Runtime/Common/IStructuredCommandInput.cs | 28 + .../Common/IStructuredCommandInput.cs.meta | 11 + .../Runtime/Common/JsonSchemaGenerator.cs | 326 + .../Common/JsonSchemaGenerator.cs.meta | 11 + .../Runtime/Common/MaxLengthStream.cs | 97 + .../Runtime/Common/MaxLengthStream.cs.meta | 11 + .../Runtime/Common/ParameterInfo.cs | 62 + .../Runtime/Common/ParameterInfo.cs.meta | 11 + .../Runtime/Common/PipelineJobs.cs | 270 + .../Runtime/Common/PipelineJobs.cs.meta | 10 + .../Runtime/Common/PipelineUtils.cs | 231 + .../Runtime/Common/PipelineUtils.cs.meta | 11 + .../Runtime/Common/RotatingFileBackup.cs | 31 + .../Runtime/Common/RotatingFileBackup.cs.meta | 2 + .../Runtime/Compilation.meta | 8 + .../Runtime/Compilation/CodeReloadCompiler.cs | 578 ++ .../Compilation/CodeReloadCompiler.cs.meta | 11 + .../Runtime/Compilation/EvalCodeCompiler.cs | 335 + .../Compilation/EvalCodeCompiler.cs.meta | 11 + .../Compilation/IlInterpreterHostBindings.cs | 153 + .../IlInterpreterHostBindings.cs.meta | 11 + .../InterpolationToFormatRewriter.cs | 84 + .../InterpolationToFormatRewriter.cs.meta | 11 + .../InterpreterCodeReloadExecutor.cs | 314 + .../InterpreterCodeReloadExecutor.cs.meta | 11 + .../Compilation/RoslynCompilationService.cs | 534 + .../RoslynCompilationService.cs.meta | 11 + .../com.unity.pipeline/Runtime/Console.meta | 8 + .../Runtime/Console/ConsoleLogBuffer.cs | 427 + .../Runtime/Console/ConsoleLogBuffer.cs.meta | 2 + .../Runtime/Console/ConsoleLogCapture.cs | 89 + .../Runtime/Console/ConsoleLogCapture.cs.meta | 2 + .../Runtime/IlInterpreter.meta | 8 + .../Runtime/IlInterpreter/AssemblyInfo.cs | 17 + .../IlInterpreter/AssemblyInfo.cs.meta | 11 + .../Runtime/IlInterpreter/HostBinding.cs | 3220 ++++++ .../Runtime/IlInterpreter/HostBinding.cs.meta | 11 + .../Runtime/IlInterpreter/IFrameAllocator.cs | 18 + .../IlInterpreter/IFrameAllocator.cs.meta | 11 + .../Runtime/IlInterpreter/IScript.cs | 23 + .../Runtime/IlInterpreter/IScript.cs.meta | 11 + .../Runtime/IlInterpreter/IrDisassembler.cs | 106 + .../IlInterpreter/IrDisassembler.cs.meta | 11 + .../IlInterpreter/MarshalFrameAllocator.cs | 23 + .../MarshalFrameAllocator.cs.meta | 11 + .../Runtime/IlInterpreter/Op.cs | 387 + .../Runtime/IlInterpreter/Op.cs.meta | 11 + .../IlInterpreter/ScriptDelegateAdapter.cs | 105 + .../ScriptDelegateAdapter.cs.meta | 11 + .../Runtime/IlInterpreter/ScriptEnumerator.cs | 113 + .../IlInterpreter/ScriptEnumerator.cs.meta | 11 + .../Runtime/IlInterpreter/ScriptException.cs | 53 + .../IlInterpreter/ScriptException.cs.meta | 11 + .../IlInterpreter/ScriptInterpreter.cs | 9104 +++++++++++++++++ .../IlInterpreter/ScriptInterpreter.cs.meta | 11 + .../Runtime/IlInterpreter/ScriptObject.cs | 123 + .../IlInterpreter/ScriptObject.cs.meta | 11 + .../Unity.Pipeline.IlInterpreter.asmdef | 16 + .../Unity.Pipeline.IlInterpreter.asmdef.meta | 7 + .../Runtime/IlInterpreter/Value.cs | 19 + .../Runtime/IlInterpreter/Value.cs.meta | 11 + .../Runtime/IlInterpreter/Vm.cs | 14 + .../Runtime/IlInterpreter/Vm.cs.meta | 11 + .../Runtime/IlInterpreter/VmEngine.cs | 1979 ++++ .../Runtime/IlInterpreter/VmEngine.cs.meta | 11 + .../com.unity.pipeline/Runtime/Models.meta | 8 + .../Runtime/Models/ArgProblem.cs | 101 + .../Runtime/Models/ArgProblem.cs.meta | 11 + .../Runtime/Models/AuthoringResult.cs | 42 + .../Runtime/Models/AuthoringResult.cs.meta | 11 + .../Runtime/Models/BaseResponse.cs | 68 + .../Runtime/Models/BaseResponse.cs.meta | 11 + .../Runtime/Models/CommandExecutionRequest.cs | 199 + .../Models/CommandExecutionRequest.cs.meta | 11 + .../Models/CommandExecutionResponse.cs | 208 + .../Models/CommandExecutionResponse.cs.meta | 11 + .../Runtime/Models/ConsoleGroundTruth.cs | 63 + .../Runtime/Models/ConsoleGroundTruth.cs.meta | 11 + .../Runtime/Models/ConsoleLogEntry.cs | 63 + .../Runtime/Models/ConsoleLogEntry.cs.meta | 2 + .../Runtime/Models/ConsoleLogResponse.cs | 102 + .../Runtime/Models/ConsoleLogResponse.cs.meta | 2 + .../Runtime/Models/EvalResponse.cs | 126 + .../Runtime/Models/EvalResponse.cs.meta | 11 + .../Runtime/Models/InstanceDescriptor.cs | 273 + .../Runtime/Models/InstanceDescriptor.cs.meta | 11 + .../Runtime/Models/ObjectRef.cs | 60 + .../Runtime/Models/ObjectRef.cs.meta | 11 + .../Runtime/Models/ObjectRefConverter.cs | 199 + .../Runtime/Models/ObjectRefConverter.cs.meta | 11 + .../Models/RuntimeInstanceDescriptor.cs | 251 + .../Models/RuntimeInstanceDescriptor.cs.meta | 11 + .../Runtime/Models/StatusResponse.cs | 62 + .../Runtime/Models/StatusResponse.cs.meta | 11 + .../Runtime/Models/TestExecutionResponse.cs | 33 + .../Models/TestExecutionResponse.cs.meta | 11 + .../Runtime/Models/TestResult.cs | 22 + .../Runtime/Models/TestResult.cs.meta | 11 + .../Runtime/Models/TestSummary.cs | 32 + .../Runtime/Models/TestSummary.cs.meta | 11 + .../Runtime/PlayerSupport.meta | 8 + .../PlayerSupport/CodeReloadStatusOverlay.cs | 120 + .../CodeReloadStatusOverlay.cs.meta | 11 + .../PlayerSupport/FrameStatsSampler.cs | 225 + .../PlayerSupport/FrameStatsSampler.cs.meta | 11 + .../PlayerSupport/RuntimePipelineBootstrap.cs | 67 + .../RuntimePipelineBootstrap.cs.meta | 11 + .../PlayerSupport/RuntimePipelineBuildInfo.cs | 31 + .../RuntimePipelineBuildInfo.cs.meta | 11 + .../PlayerSupport/RuntimePipelineConfig.cs | 222 + .../RuntimePipelineConfig.cs.meta | 11 + .../PlayerSupport/RuntimePipelineDriver.cs | 664 ++ .../RuntimePipelineDriver.cs.meta | 11 + .../PlayerSupport/RuntimePipelineServer.cs | 98 + .../RuntimePipelineServer.cs.meta | 11 + .../com.unity.pipeline/Runtime/Plugins.meta | 8 + .../Runtime/Plugins/CodeAnalysis.meta | 8 + .../Runtime/Plugins/CodeAnalysis/CHECKSUMS | 17 + .../Plugins/CodeAnalysis/CHECKSUMS.meta | 7 + ...Pipeline.Microsoft.CodeAnalysis.CSharp.dll | Bin 0 -> 5758464 bytes ...ine.Microsoft.CodeAnalysis.CSharp.dll.meta | 60 + .../UnityPipeline.Microsoft.CodeAnalysis.dll | Bin 0 -> 2589696 bytes ...tyPipeline.Microsoft.CodeAnalysis.dll.meta | 60 + ...yPipeline.System.Collections.Immutable.dll | Bin 0 -> 243712 bytes ...line.System.Collections.Immutable.dll.meta | 60 + ...ityPipeline.System.Reflection.Metadata.dll | Bin 0 -> 517120 bytes ...peline.System.Reflection.Metadata.dll.meta | 60 + ...System.Runtime.CompilerServices.Unsafe.dll | Bin 0 -> 6656 bytes ...m.Runtime.CompilerServices.Unsafe.dll.meta | 60 + .../Runtime/SecurityTokenManager.cs | 150 + .../Runtime/SecurityTokenManager.cs.meta | 11 + .../com.unity.pipeline/Runtime/Telemetry.meta | 8 + .../Telemetry/EvalUsageFingerprinter.cs | 422 + .../Telemetry/EvalUsageFingerprinter.cs.meta | 11 + .../Runtime/Telemetry/EvalUsageReport.cs | 266 + .../Runtime/Telemetry/EvalUsageReport.cs.meta | 11 + .../Runtime/Telemetry/EvalUsageTelemetry.cs | 481 + .../Telemetry/EvalUsageTelemetry.cs.meta | 11 + .../Runtime/Unity.Pipeline.asmdef | 33 + .../Runtime/Unity.Pipeline.asmdef.meta | 7 + .../Samples~/CodeReload.meta | 8 + .../CodeReload/CodeReload_InPlace.meta | 8 + .../CodeReload_InPlace.unity | 447 + .../CodeReload_InPlace.unity.meta | 7 + .../InPlaceCodeReloadExample.cs | 83 + .../InPlaceCodeReloadExample.cs.meta | 2 + .../CodeReload_Minics/PongScene.unity | 437 + .../CodeReload_Minics/PongScene.unity.meta | 7 + .../CodeReload/CodeReload_Minics/README.md | 42 + .../CodeReload/CodeReload_Minics/pong.cs | 248 + .../CodeReload/CodeReload_Minics/pong.cs.meta | 2 + .../CodeReload/Unity.Pipeline.Samples.asmdef | 17 + .../Unity.Pipeline.Samples.asmdef.meta | 7 + .../Packages/com.unity.pipeline/Tests~.meta | 8 + .../com.unity.pipeline/Tests~/Editor.meta | 8 + .../Tests~/Editor/Animation.meta | 8 + .../Animation/AnimationClipCommandsTests.cs | 211 + .../AnimationClipCommandsTests.cs.meta | 2 + .../AnimatorControllerCommandsTests.cs | 261 + .../AnimatorControllerCommandsTests.cs.meta | 2 + .../Editor/Animation/TimelineCommandsTests.cs | 81 + .../Animation/TimelineCommandsTests.cs.meta | 2 + .../Tests~/Editor/ApiEndpointsTests.cs | 1229 +++ .../Tests~/Editor/ApiEndpointsTests.cs.meta | 11 + .../Tests~/Editor/Assets.meta | 8 + .../Editor/Assets/AssetCommandsTests.cs | 246 + .../Editor/Assets/AssetCommandsTests.cs.meta | 2 + .../Editor/Assets/AssetImportCommandsTests.cs | 103 + .../Assets/AssetImportCommandsTests.cs.meta | 2 + .../Assets/ImportSettingsCommandTests.cs | 432 + .../Assets/ImportSettingsCommandTests.cs.meta | 2 + .../Assets/MaterialAssetCommandsTests.cs | 182 + .../Assets/MaterialAssetCommandsTests.cs.meta | 11 + .../PhysicsMaterialAssetCommandsTests.cs | 158 + .../PhysicsMaterialAssetCommandsTests.cs.meta | 11 + .../Editor/Assets/TextFileCommandsTests.cs | 108 + .../Assets/TextFileCommandsTests.cs.meta | 2 + .../Tests~/Editor/Authoring.meta | 8 + .../Editor/Authoring/FolderCommandsTests.cs | 85 + .../Authoring/FolderCommandsTests.cs.meta | 11 + .../Authoring/ObjectRefConverterTests.cs | 223 + .../Authoring/ObjectRefConverterTests.cs.meta | 11 + .../Editor/Authoring/ObjectResolverTests.cs | 145 + .../Authoring/ObjectResolverTests.cs.meta | 11 + .../Editor/Authoring/ProjectPathsTests.cs | 84 + .../Authoring/ProjectPathsTests.cs.meta | 11 + .../Tests~/Editor/AutoTickCommandTests.cs | 114 + .../Editor/AutoTickCommandTests.cs.meta | 11 + .../Tests~/Editor/Baking.meta | 8 + .../Baking/LightingBakeCommandsTests.cs | 199 + .../Baking/LightingBakeCommandsTests.cs.meta | 11 + .../Editor/Baking/NavMeshBakeCommandsTests.cs | 125 + .../Baking/NavMeshBakeCommandsTests.cs.meta | 11 + .../Baking/OcclusionBakeCommandsTests.cs | 69 + .../Baking/OcclusionBakeCommandsTests.cs.meta | 11 + .../Tests~/Editor/Batch.meta | 8 + .../Tests~/Editor/Batch/BatchCommandTests.cs | 958 ++ .../Editor/Batch/BatchCommandTests.cs.meta | 11 + .../Tests~/Editor/BuildConfigCommandsTests.cs | 105 + .../Editor/BuildConfigCommandsTests.cs.meta | 11 + .../Tests~/Editor/Capture.meta | 8 + .../Editor/Capture/CaptureCommandsTests.cs | 428 + .../Capture/CaptureCommandsTests.cs.meta | 11 + .../CaptureVisualElementCommandsTests.cs | 243 + .../CaptureVisualElementCommandsTests.cs.meta | 11 + .../Tests~/Editor/CodeEvalCommandTests.cs | 341 + .../Editor/CodeEvalCommandTests.cs.meta | 11 + .../CodeReloadAssemblyDirectoryTests.cs | 88 + .../CodeReloadAssemblyDirectoryTests.cs.meta | 11 + .../Tests~/Editor/CodeReloadAttributeTests.cs | 109 + .../Editor/CodeReloadAttributeTests.cs.meta | 11 + .../Tests~/Editor/CodeReloadBaselineTests.cs | 316 + .../Editor/CodeReloadBaselineTests.cs.meta | 2 + .../Tests~/Editor/CodeReloadBasicTests.cs | 177 + .../Editor/CodeReloadBasicTests.cs.meta | 11 + .../Tests~/Editor/CodeReloadCommandTests.cs | 106 + .../Editor/CodeReloadCommandTests.cs.meta | 11 + .../Tests~/Editor/CodeReloadCompilerTests.cs | 127 + .../Editor/CodeReloadCompilerTests.cs.meta | 11 + .../Editor/CodeReloadConnectWireTests.cs | 55 + .../Editor/CodeReloadConnectWireTests.cs.meta | 11 + .../Tests~/Editor/CodeReloadCoroutineTests.cs | 328 + .../Editor/CodeReloadCoroutineTests.cs.meta | 11 + .../Tests~/Editor/CodeReloadInPlaceTests.cs | 1006 ++ .../Editor/CodeReloadInPlaceTests.cs.meta | 11 + .../Editor/CodeReloadLinkXmlGeneratorTests.cs | 279 + .../CodeReloadLinkXmlGeneratorTests.cs.meta | 11 + .../Tests~/Editor/CodeReloadRegistryTests.cs | 170 + .../Editor/CodeReloadRegistryTests.cs.meta | 11 + .../Tests~/Editor/CodeReloadStaticTests.cs | 259 + .../Editor/CodeReloadStaticTests.cs.meta | 11 + .../Editor/CodeReloadVerificationTests.cs | 136 + .../CodeReloadVerificationTests.cs.meta | 11 + .../Tests~/Editor/CommandLineBinderTests.cs | 732 ++ .../Editor/CommandLineBinderTests.cs.meta | 11 + .../Editor/CommandLineTokenizerTests.cs | 112 + .../Editor/CommandLineTokenizerTests.cs.meta | 11 + .../Tests~/Editor/CommandRegistrationTests.cs | 389 + .../Editor/CommandRegistrationTests.cs.meta | 11 + .../Tests~/Editor/Console.meta | 8 + .../Console/ConsoleCaptureResubscribeTests.cs | 87 + .../ConsoleCaptureResubscribeTests.cs.meta | 2 + .../Console/EditorConsoleGroundTruthTests.cs | 243 + .../EditorConsoleGroundTruthTests.cs.meta | 11 + .../Tests~/Editor/ConsoleCommandTests.cs | 193 + .../Tests~/Editor/ConsoleCommandTests.cs.meta | 2 + .../Tests~/Editor/ConsoleLogBufferTests.cs | 572 ++ .../Editor/ConsoleLogBufferTests.cs.meta | 2 + .../Tests~/Editor/DialogEndpointTests.cs | 79 + .../Tests~/Editor/DialogEndpointTests.cs.meta | 10 + .../Tests~/Editor/DialogStateTrackerTests.cs | 118 + .../Editor/DialogStateTrackerTests.cs.meta | 10 + .../Editor/DialogsDuringExecutionTests.cs | 95 + .../DialogsDuringExecutionTests.cs.meta | 10 + .../Editor/DynamicCommandRegistrationTests.cs | 336 + .../DynamicCommandRegistrationTests.cs.meta | 11 + .../com.unity.pipeline/Tests~/Editor/E2E.meta | 8 + .../Editor/E2E/AgentAuthoringE2ETests.cs | 70 + .../Editor/E2E/AgentAuthoringE2ETests.cs.meta | 11 + .../Editor/EditorAutomationModeTests.cs | 56 + .../Editor/EditorAutomationModeTests.cs.meta | 11 + .../EditorCodeReloadWatcherJournalTests.cs | 101 + ...ditorCodeReloadWatcherJournalTests.cs.meta | 11 + .../Editor/EditorCodeReloadWatcherTests.cs | 100 + .../EditorCodeReloadWatcherTests.cs.meta | 11 + .../Tests~/Editor/EditorStatusCommandTests.cs | 53 + .../Editor/EditorStatusCommandTests.cs.meta | 11 + .../Tests~/Editor/EditorTestUtilities.cs | 60 + .../Tests~/Editor/EditorTestUtilities.cs.meta | 11 + .../Tests~/Editor/EvalCodeCompilerTests.cs | 43 + .../Editor/EvalCodeCompilerTests.cs.meta | 11 + .../Tests~/Editor/EvalTelemetryTestGuard.cs | 53 + .../Editor/EvalTelemetryTestGuard.cs.meta | 11 + .../Tests~/Editor/FrameStatsSamplerTests.cs | 87 + .../Editor/FrameStatsSamplerTests.cs.meta | 11 + .../Tests~/Editor/GameObjects.meta | 8 + .../GameObjects/CoercionAndBatchTests.cs | 377 + .../GameObjects/CoercionAndBatchTests.cs.meta | 11 + .../GameObjects/ComponentCommandsTests.cs | 400 + .../ComponentCommandsTests.cs.meta | 2 + .../GameObjects/GameObjectCommandsTests.cs | 217 + .../GameObjectCommandsTests.cs.meta | 2 + .../Editor/IlInterpreterAutoBindTests.cs | 149 + .../Editor/IlInterpreterAutoBindTests.cs.meta | 11 + ...IlInterpreterCodeReloadInterpreterTests.cs | 1067 ++ ...erpreterCodeReloadInterpreterTests.cs.meta | 11 + .../Editor/IlInterpreterHostInteropTests.cs | 206 + .../IlInterpreterHostInteropTests.cs.meta | 11 + .../Editor/IlInterpreterHostSurfaceTests.cs | 136 + .../IlInterpreterHostSurfaceTests.cs.meta | 11 + .../Editor/IlInterpreterPerfBenchmarks.cs | 342 + .../IlInterpreterPerfBenchmarks.cs.meta | 11 + .../IlInterpreterWideValueEditorTests.cs | 68 + .../IlInterpreterWideValueEditorTests.cs.meta | 11 + .../Tests~/Editor/InstanceDiscoveryTests.cs | 425 + .../Editor/InstanceDiscoveryTests.cs.meta | 11 + .../Tests~/Editor/JobEndpointTests.cs | 369 + .../Tests~/Editor/JobEndpointTests.cs.meta | 10 + .../Tests~/Editor/LiveServerGuard.cs | 111 + .../Tests~/Editor/LiveServerGuard.cs.meta | 11 + .../Tests~/Editor/LoopbackBindingTests.cs | 47 + .../Editor/LoopbackBindingTests.cs.meta | 11 + .../Tests~/Editor/Materials.meta | 8 + .../Editor/Materials/MaterialCommandsTests.cs | 384 + .../Materials/MaterialCommandsTests.cs.meta | 2 + .../Editor/Materials/ShaderCommandsTests.cs | 177 + .../Materials/ShaderCommandsTests.cs.meta | 2 + .../Tests~/Editor/MaxLengthStreamTests.cs | 100 + .../Editor/MaxLengthStreamTests.cs.meta | 11 + .../Tests~/Editor/MenuCommandTests.cs | 146 + .../Tests~/Editor/MenuCommandTests.cs.meta | 2 + .../Tests~/Editor/Models.meta | 8 + .../Editor/Models/ObjectRefConverterTests.cs | 56 + .../Models/ObjectRefConverterTests.cs.meta | 11 + .../Tests~/Editor/Navigation.meta | 8 + .../Navigation/NavigationCommandsTests.cs | 147 + .../NavigationCommandsTests.cs.meta | 11 + .../Tests~/Editor/Observability.meta | 8 + .../ObservabilityCommandsTests.cs | 38 + .../ObservabilityCommandsTests.cs.meta | 11 + .../Editor/PackageManagerCommandTests.cs | 248 + .../Editor/PackageManagerCommandTests.cs.meta | 11 + .../Tests~/Editor/PipelineAnalyticsTests.cs | 459 + .../Editor/PipelineAnalyticsTests.cs.meta | 11 + .../PipelineRuntimeBuildProcessorTests.cs | 44 + ...PipelineRuntimeBuildProcessorTests.cs.meta | 11 + .../Tests~/Editor/PipelineTestServer.cs | 101 + .../Tests~/Editor/PipelineTestServer.cs.meta | 11 + .../Editor/PipelineTransactionLogTests.cs | 140 + .../PipelineTransactionLogTests.cs.meta | 2 + .../Editor/PipelineWatchdogTestGuard.cs | 44 + .../Editor/PipelineWatchdogTestGuard.cs.meta | 11 + .../Tests~/Editor/PlayModeCommandsTests.cs | 536 + .../Editor/PlayModeCommandsTests.cs.meta | 11 + .../Tests~/Editor/PlayModeReloadGuard.cs | 61 + .../Tests~/Editor/PlayModeReloadGuard.cs.meta | 11 + .../Tests~/Editor/Prefabs.meta | 8 + .../Editor/Prefabs/PrefabCommandsTests.cs | 267 + .../Prefabs/PrefabCommandsTests.cs.meta | 2 + .../Tests~/Editor/ProgressEndpointTests.cs | 165 + .../Editor/ProgressEndpointTests.cs.meta | 10 + .../Tests~/Editor/ProjectAudit.meta | 8 + .../ProjectAudit/ProjectAuditCommandsTests.cs | 138 + .../ProjectAuditCommandsTests.cs.meta | 11 + .../Editor/ProjectSettingsCommandTests.cs | 111 + .../ProjectSettingsCommandTests.cs.meta | 11 + .../ProjectSettingsGroupCommandsTests.cs | 108 + .../ProjectSettingsGroupCommandsTests.cs.meta | 11 + .../Editor/PushBindingValidationTests.cs | 56 + .../Editor/PushBindingValidationTests.cs.meta | 11 + .../Tests~/Editor/PushSigningTests.cs | 477 + .../Tests~/Editor/PushSigningTests.cs.meta | 2 + .../Tests~/Editor/RecompileCommandTests.cs | 74 + .../Editor/RecompileCommandTests.cs.meta | 11 + .../Tests~/Editor/RecompileStatusTests.cs | 146 + .../Editor/RecompileStatusTests.cs.meta | 11 + .../Editor/ReloadPathValidationTests.cs | 157 + .../Editor/ReloadPathValidationTests.cs.meta | 11 + .../Editor/ResponseEnvelopeSizeTests.cs | 306 + .../Editor/ResponseEnvelopeSizeTests.cs.meta | 11 + .../Tests~/Editor/RoslynChecksumTests.cs | 237 + .../Tests~/Editor/RoslynChecksumTests.cs.meta | 11 + .../Editor/RoslynCompilationServiceTests.cs | 412 + .../RoslynCompilationServiceTests.cs.meta | 11 + .../Editor/RuntimeApplicationCommandTests.cs | 103 + .../RuntimeApplicationCommandTests.cs.meta | 11 + .../Tests~/Editor/RuntimeInputCommandTests.cs | 88 + .../Editor/RuntimeInputCommandTests.cs.meta | 11 + .../Editor/RuntimeInstanceDescriptorTests.cs | 32 + .../RuntimeInstanceDescriptorTests.cs.meta | 2 + .../Tests~/Editor/RuntimeLogCommandTests.cs | 73 + .../Editor/RuntimeLogCommandTests.cs.meta | 11 + .../Editor/RuntimePipelineBootstrapTests.cs | 105 + .../RuntimePipelineBootstrapTests.cs.meta | 11 + .../Editor/RuntimePipelineBuildInfoTests.cs | 62 + .../RuntimePipelineBuildInfoTests.cs.meta | 11 + .../Editor/RuntimePipelineBuildTests.cs | 379 + .../Editor/RuntimePipelineBuildTests.cs.meta | 11 + .../RuntimePipelineConfigEditorTests.cs | 24 + .../RuntimePipelineConfigEditorTests.cs.meta | 11 + .../Editor/RuntimePipelineConfigTests.cs | 130 + .../Editor/RuntimePipelineConfigTests.cs.meta | 11 + .../Editor/RuntimePipelineDriverTests.cs | 243 + .../Editor/RuntimePipelineDriverTests.cs.meta | 11 + .../RuntimePipelineResourceTestGuard.cs | 35 + .../RuntimePipelineResourceTestGuard.cs.meta | 11 + .../Editor/RuntimePipelineServerTests.cs | 233 + .../Editor/RuntimePipelineServerTests.cs.meta | 11 + .../RuntimePipelineSettingsCommandsTests.cs | 226 + ...ntimePipelineSettingsCommandsTests.cs.meta | 11 + .../RuntimePipelineSettingsProviderTests.cs | 59 + ...ntimePipelineSettingsProviderTests.cs.meta | 11 + .../Editor/RuntimeStatusCommandTests.cs | 108 + .../Editor/RuntimeStatusCommandTests.cs.meta | 11 + .../Tests~/Editor/Scenes.meta | 8 + .../Editor/Scenes/SceneCommandsTests.cs | 463 + .../Editor/Scenes/SceneCommandsTests.cs.meta | 2 + .../Tests~/Editor/ScreenshotCommandTests.cs | 160 + .../Editor/ScreenshotCommandTests.cs.meta | 2 + .../Tests~/Editor/Scripts.meta | 8 + .../Editor/Scripts/RunScriptCommandTests.cs | 814 ++ .../Scripts/RunScriptCommandTests.cs.meta | 11 + .../Editor/Scripts/ScriptCommandsTests.cs | 681 ++ .../Scripts/ScriptCommandsTests.cs.meta | 2 + .../Tests~/Editor/SecurityTokenTests.cs | 131 + .../Tests~/Editor/SecurityTokenTests.cs.meta | 11 + .../Tests~/Editor/ServerAuthTests.cs | 103 + .../Tests~/Editor/ServerAuthTests.cs.meta | 11 + .../Tests~/Editor/ServerLifecycle.meta | 8 + .../Editor/ServerLifecycle/DialogGateTests.cs | 175 + .../ServerLifecycle/DialogGateTests.cs.meta | 10 + .../DialogStateMirrorResubscribeTests.cs | 86 + .../DialogStateMirrorResubscribeTests.cs.meta | 10 + .../Editor/ServerLifecycle/DualServerTests.cs | 194 + .../ServerLifecycle/DualServerTests.cs.meta | 11 + .../Editor/ServerLifecycle/EndToEndTests.cs | 124 + .../ServerLifecycle/EndToEndTests.cs.meta | 11 + .../ServerLifecycle/GlobalServerStateGuard.cs | 59 + .../GlobalServerStateGuard.cs.meta | 11 + .../GlobalServerStateGuardTests.cs | 71 + .../GlobalServerStateGuardTests.cs.meta | 11 + .../ServerLifecycle/PipelineServerTests.cs | 131 + .../PipelineServerTests.cs.meta | 11 + .../Editor/ServerLifecycle/SettleGateTests.cs | 255 + .../ServerLifecycle/SettleGateTests.cs.meta | 11 + .../Tests~/Editor/Telemetry.meta | 8 + .../Telemetry/EvalTelemetryCommandTests.cs | 139 + .../EvalTelemetryCommandTests.cs.meta | 11 + .../Telemetry/EvalUsageFingerprinterTests.cs | 282 + .../EvalUsageFingerprinterTests.cs.meta | 11 + .../Editor/Telemetry/EvalUsageReportTests.cs | 200 + .../Telemetry/EvalUsageReportTests.cs.meta | 11 + .../Telemetry/EvalUsageTelemetryTests.cs | 317 + .../Telemetry/EvalUsageTelemetryTests.cs.meta | 11 + .../Tests~/Editor/TestCommandsTests.cs | 147 + .../Tests~/Editor/TestCommandsTests.cs.meta | 11 + .../Tests~/Editor/TestEditorPipelineServer.cs | 55 + .../Editor/TestEditorPipelineServer.cs.meta | 11 + .../Tests~/Editor/TestOnlyCommands.cs | 23 + .../Tests~/Editor/TestOnlyCommands.cs.meta | 10 + .../Tests~/Editor/TestResultCollectorTests.cs | 134 + .../Editor/TestResultCollectorTests.cs.meta | 11 + .../Tests~/Editor/TransformTwinFixtures.cs | 23 + .../Editor/TransformTwinFixtures.cs.meta | 11 + .../Editor/Unity.Pipeline.Tests.Editor.asmdef | 28 + .../Unity.Pipeline.Tests.Editor.asmdef.meta | 7 + .../Tests~/Editor/WaitForCommandTests.cs | 1333 +++ .../Tests~/Editor/WaitForCommandTests.cs.meta | 11 + .../com.unity.pipeline/Tests~/Runtime.meta | 8 + .../Tests~/Runtime/AssemblyInfo.cs | 5 + .../Tests~/Runtime/AssemblyInfo.cs.meta | 11 + .../Tests~/Runtime/AttachByPathFixture.cs | 22 + .../Runtime/AttachByPathFixture.cs.meta | 11 + .../Runtime/CodeReloadInPlaceEditingTests.cs | 414 + .../CodeReloadInPlaceEditingTests.cs.meta | 11 + .../Runtime/IlInterpreterAotProbeBlobs.g.cs | 417 + .../IlInterpreterAotProbeBlobs.g.cs.meta | 2 + .../Runtime/IlInterpreterAotSmokeTests.cs | 83 + .../IlInterpreterAotSmokeTests.cs.meta | 11 + .../Runtime/IlInterpreterPlayModeTests.cs | 80 + .../IlInterpreterPlayModeTests.cs.meta | 11 + .../Tests~/Runtime/PipelineClient.cs | 412 + .../Tests~/Runtime/PipelineClient.cs.meta | 11 + .../RuntimeServerPlayModeSmokeTests.cs | 67 + .../RuntimeServerPlayModeSmokeTests.cs.meta | 11 + .../Unity.Pipeline.Tests.Runtime.asmdef | 23 + .../Unity.Pipeline.Tests.Runtime.asmdef.meta | 7 + .../com.unity.pipeline/Third Party Notices.md | 169 + .../Third Party Notices.md.meta | 7 + .../Packages/com.unity.pipeline/package.json | 1 + .../com.unity.pipeline/package.json.meta | 7 + AIClient/Packages/manifest.json | 55 + AIClient/Packages/packages-lock.json | 499 + AIClient/ProjectSettings/AudioManager.asset | 19 + .../ProjectSettings/ClusterInputManager.asset | 6 + .../ProjectSettings/DynamicsManager.asset | 34 + .../ProjectSettings/EditorBuildSettings.asset | 8 + AIClient/ProjectSettings/EditorSettings.asset | 30 + .../ProjectSettings/GraphicsSettings.asset | 67 + AIClient/ProjectSettings/InputManager.asset | 488 + AIClient/ProjectSettings/MemorySettings.asset | 35 + AIClient/ProjectSettings/NavMeshAreas.asset | 91 + .../PackageManagerSettings.asset | 44 + .../Settings.json | 5 + .../ProjectSettings/Physics2DSettings.asset | 56 + AIClient/ProjectSettings/PresetManager.asset | 7 + .../ProjectSettings/ProjectSettings.asset | 961 ++ AIClient/ProjectSettings/ProjectVersion.txt | 2 + .../ProjectSettings/QualitySettings.asset | 222 + .../ProjectSettings/ShaderGraphSettings.asset | 17 + AIClient/ProjectSettings/TagManager.asset | 43 + AIClient/ProjectSettings/TimeManager.asset | 9 + .../ProjectSettings/URPProjectSettings.asset | 15 + .../UnityConnectSettings.asset | 36 + AIClient/ProjectSettings/VFXManager.asset | 12 + .../VersionControlSettings.asset | 8 + AIClient/ProjectSettings/XRSettings.asset | 10 + Agents.md | 15 + Doc/ResDesc.md | 13 + Doc/ResDesc_Animation.md | 6 + Doc/ResDesc_Effect.md | 6 + Doc/ResDesc_Model.md | 6 + Doc/ResDesc_Picture.md | 11 + Doc/ResDesc_Sound.md | 6 + Doc/UI_Normal_Set.md | 140 + Doc/UI_Pic_Set.md | 124 + Doc/UI_Simple_Set.md | 105 + Doc/gpt-image_doc.md | 298 + Doc/minimax-h3_doc.md | 268 + Doc/ui_design.jpg | Bin 0 -> 192856 bytes ProjectDesign.md | 0 ResourceCreate.md | 108 + Tools/gpt_image_generate.py | 612 ++ Tools/hunyuan_3d/__init__.py | 14 + Tools/hunyuan_3d/auth.py | 240 + Tools/hunyuan_3d/client.py | 646 ++ Tools/hunyuan_3d/events.py | 78 + Tools/hunyuan_3d_generate.py | 299 + Tools/model_tools/README.md | 48 + Tools/model_tools/bl_bake.py | 216 + Tools/model_tools/bl_decimate.py | 481 + Tools/model_tools/model_bake.py | 50 + Tools/model_tools/model_decimate.py | 64 + Tools/model_tools/model_lowpoly_bake.py | 319 + Tools/model_tools/mt_run.py | 67 + Tools/model_tools/tests/test_model_formats.py | 26 + Tools/model_tools/uv_preview.py | 31 + Tools/output/_vip_probe.json | 1 + Tools/output/_vip_probe.png | Bin 0 -> 2136918 bytes Tools/output/male_explorer_cursor.png | Bin 0 -> 190515 bytes Tools/output/male_explorer_status.json | 52 + Tools/output/male_explorer_test.png | Bin 0 -> 1726126 bytes Tools/output/ui_normal_atlas_gpt.png | Bin 0 -> 2890847 bytes Tools/output/ui_normal_atlas_gpt_status.json | 53 + Tools/output/ui_normal_atlas_job.json | 1 + Tools/output/ui_normal_atlas_prompt.txt | 55 + Tools/output/ui_simple_atlas_gpt.png | Bin 0 -> 723740 bytes Tools/output/ui_simple_atlas_gpt_status.json | 52 + Tools/output/ui_simple_atlas_prompt.txt | 41 + Tools/requirements-hunyuan.txt | 10 + Tools/requirements.txt | 4 + UNITY-GUIDE.md | 50 + 931 files changed, 112366 insertions(+) create mode 100644 .claude/skills/unity-pipeline/SKILL.md create mode 100644 .cursor/rules/aigame-basics.mdc create mode 100644 .cursor/skills/unity-pipeline/SKILL.md create mode 100644 .gitignore create mode 100644 AIClient/.vsconfig create mode 100644 AIClient/Assets/Editor.meta create mode 100644 AIClient/Assets/Editor/SetupHybridClr.cs create mode 100644 AIClient/Assets/Editor/SetupHybridClr.cs.meta create mode 100644 AIClient/Assets/Editor/SetupUrp.cs create mode 100644 AIClient/Assets/Editor/SetupUrp.cs.meta create mode 100644 AIClient/Assets/Scenes.meta create mode 100644 AIClient/Assets/Scenes/SampleScene.unity create mode 100644 AIClient/Assets/Scenes/SampleScene.unity.meta create mode 100644 AIClient/Assets/Settings.meta create mode 100644 AIClient/Assets/Settings/URP.meta create mode 100644 AIClient/Assets/Settings/URP/ForwardRenderer 0VeryLowQuality.asset create mode 100644 AIClient/Assets/Settings/URP/ForwardRenderer 0VeryLowQuality.asset.meta create mode 100644 AIClient/Assets/Settings/URP/ForwardRenderer 1LowQuality.asset create mode 100644 AIClient/Assets/Settings/URP/ForwardRenderer 1LowQuality.asset.meta create mode 100644 AIClient/Assets/Settings/URP/ForwardRenderer 2MediumQuality.asset create mode 100644 AIClient/Assets/Settings/URP/ForwardRenderer 2MediumQuality.asset.meta create mode 100644 AIClient/Assets/Settings/URP/ForwardRenderer 3HighQuality.asset create mode 100644 AIClient/Assets/Settings/URP/ForwardRenderer 3HighQuality.asset.meta create mode 100644 AIClient/Assets/Settings/URP/ForwardRenderer 4VeryHighQuality.asset create mode 100644 AIClient/Assets/Settings/URP/ForwardRenderer 4VeryHighQuality.asset.meta create mode 100644 AIClient/Assets/Settings/URP/UniversalRP-0VeryLowQuality.asset create mode 100644 AIClient/Assets/Settings/URP/UniversalRP-0VeryLowQuality.asset.meta create mode 100644 AIClient/Assets/Settings/URP/UniversalRP-1LowQuality.asset create mode 100644 AIClient/Assets/Settings/URP/UniversalRP-1LowQuality.asset.meta create mode 100644 AIClient/Assets/Settings/URP/UniversalRP-2MediumQuality.asset create mode 100644 AIClient/Assets/Settings/URP/UniversalRP-2MediumQuality.asset.meta create mode 100644 AIClient/Assets/Settings/URP/UniversalRP-3HighQuality.asset create mode 100644 AIClient/Assets/Settings/URP/UniversalRP-3HighQuality.asset.meta create mode 100644 AIClient/Assets/Settings/URP/UniversalRP-4VeryHighQuality.asset create mode 100644 AIClient/Assets/Settings/URP/UniversalRP-4VeryHighQuality.asset.meta create mode 100644 AIClient/Assets/UniversalRenderPipelineGlobalSettings.asset create mode 100644 AIClient/Assets/UniversalRenderPipelineGlobalSettings.asset.meta create mode 100644 AIClient/Assets/_PipelineRefresh.stamp.txt create mode 100644 AIClient/Assets/_PipelineRefresh.stamp.txt.meta create mode 100644 AIClient/Packages/com.unity.pipeline/.attestation.p7m create mode 100644 AIClient/Packages/com.unity.pipeline/.claude/skills/unity-pipeline/SKILL.md create mode 100644 AIClient/Packages/com.unity.pipeline/.signature create mode 100644 AIClient/Packages/com.unity.pipeline/CHANGELOG.md create mode 100644 AIClient/Packages/com.unity.pipeline/CHANGELOG.md.meta create mode 100644 AIClient/Packages/com.unity.pipeline/CLAUDE.md create mode 100644 AIClient/Packages/com.unity.pipeline/CLAUDE.md.meta create mode 100644 AIClient/Packages/com.unity.pipeline/CODEOWNERS create mode 100644 AIClient/Packages/com.unity.pipeline/CODEOWNERS.meta create mode 100644 AIClient/Packages/com.unity.pipeline/CodeGen.meta create mode 100644 AIClient/Packages/com.unity.pipeline/CodeGen/CodeReloadInPlaceILPostProcessor.cs create mode 100644 AIClient/Packages/com.unity.pipeline/CodeGen/CodeReloadInPlaceILPostProcessor.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/CodeGen/Unity.Pipeline.CodeGen.asmdef create mode 100644 AIClient/Packages/com.unity.pipeline/CodeGen/Unity.Pipeline.CodeGen.asmdef.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/TableOfContents.md create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/analytics.md create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/authoring-commands.md create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/code-reload.md create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/commands/animation.md create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/commands/assets-and-files.md create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/commands/baking.md create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/commands/batch.md create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/commands/build-and-compilation.md create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/commands/capture.md create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/commands/editor-lifecycle-and-observability.md create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/commands/gameobjects-and-components.md create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/commands/materials.md create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/commands/navigation.md create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/commands/package-manager.md create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/commands/prefabs.md create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/commands/project-settings.md create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/commands/runtime.md create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/commands/scenes.md create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/commands/scripts.md create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/commands/wait.md create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/connectivity.md create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/creating-commands.md create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/filter.yml create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/images/codereload-watcher-panel.png create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/index.md create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/runtime-setup.md create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/safety-and-mutations.md create mode 100644 AIClient/Packages/com.unity.pipeline/Documentation~/testing.md create mode 100644 AIClient/Packages/com.unity.pipeline/Editor.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Authoring.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Authoring/AuthoringUndoScope.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Authoring/AuthoringUndoScope.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Authoring/ObjectResolver.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Authoring/ObjectResolver.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Authoring/ProjectPaths.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Authoring/ProjectPaths.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/BuildProcessors.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/BuildProcessors/CodeReloadLinkXmlGenerator.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/BuildProcessors/CodeReloadLinkXmlGenerator.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/BuildProcessors/PipelineRuntimeBuildProcessor.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/BuildProcessors/PipelineRuntimeBuildProcessor.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/CliEditorProgress.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/CliEditorProgress.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/AnimationClipCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/AnimationClipCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/AnimatorControllerCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/AnimatorControllerCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/TimelineCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/TimelineCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/TimelineGuard.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/TimelineGuard.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/AssetCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/AssetCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/AssetImportCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/AssetImportCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/FindAssetsResult.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/FindAssetsResult.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/FolderCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/FolderCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/TextFileCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/TextFileCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Authoring.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Authoring/AuthoringConfigCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Authoring/AuthoringConfigCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/AutoTickCommand.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/AutoTickCommand.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/BakeSceneGuard.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/BakeSceneGuard.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/LightingBakeCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/LightingBakeCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/NavMeshBakeCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/NavMeshBakeCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/OcclusionBakeCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/OcclusionBakeCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchCommand.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchCommand.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchInput.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchInput.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchReferenceResolver.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchReferenceResolver.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchResult.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchResult.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Build.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/BuildCommand.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/BuildCommand.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/BuildConfigCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/BuildConfigCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/BuildModels.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/BuildModels.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/SwitchBuildTargetCommand.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/SwitchBuildTargetCommand.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Capture.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Capture/CaptureCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Capture/CaptureCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/CaptureEditorElementCommand.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/CaptureEditorElementCommand.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/EditorStatusCommand.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/EditorStatusCommand.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/FocusEditorCommand.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/FocusEditorCommand.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/ComponentCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/ComponentCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/ComponentPropertiesResult.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/ComponentPropertiesResult.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/CreateGameObjectsResult.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/CreateGameObjectsResult.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/FindGameObjectsResult.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/FindGameObjectsResult.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/GameObjectCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/GameObjectCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/SerializedPropertyConverter.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/SerializedPropertyConverter.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/TypeResolver.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/TypeResolver.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/MaterialCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/MaterialCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/MaterialResults.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/MaterialResults.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/MaterialValueConverter.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/MaterialValueConverter.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/ShaderCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/ShaderCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/MenuItemCommand.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/MenuItemCommand.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Navigation.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Navigation/NavigationCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Navigation/NavigationCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Observability.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Observability/PerformanceCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Observability/PerformanceCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageIdentifier.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageIdentifier.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageManagerCommand.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageManagerCommand.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageManifest.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageManifest.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageModels.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageModels.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/PlayModeCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/PlayModeCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Prefabs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Prefabs/PrefabCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Prefabs/PrefabCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectAudit.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectAudit/ProjectAuditCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectAudit/ProjectAuditCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/AudioSettingsCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/AudioSettingsCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/GraphicsSettingsCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/GraphicsSettingsCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/InputSettingsCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/InputSettingsCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/PhysicsSettingsCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/PhysicsSettingsCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/PlayerSettingsCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/PlayerSettingsCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/ProjectSettingsAsset.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/ProjectSettingsAsset.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/ProjectSettingsCommand.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/ProjectSettingsCommand.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/ProjectSettingsResponse.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/ProjectSettingsResponse.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/QualitySettingsCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/QualitySettingsCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/RuntimePipelineSettingsCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/RuntimePipelineSettingsCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/TagsLayersCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/TagsLayersCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/TimeSettingsCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/TimeSettingsCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/PushReloadCommand.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/PushReloadCommand.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/RecompileCommand.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/RecompileCommand.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Scenes.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Scenes/SceneCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Scenes/SceneCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Scenes/SceneHierarchy.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Scenes/SceneHierarchy.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ScreenshotCommand.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/ScreenshotCommand.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/AttachScriptCommand.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/AttachScriptCommand.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/CreateScriptCommand.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/CreateScriptCommand.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/RunScriptCommand.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/RunScriptCommand.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/ScriptTypeResolver.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/ScriptTypeResolver.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/SerializedFieldCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/SerializedFieldCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/SerializedPropertyConverter.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/SerializedPropertyConverter.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/TestCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/TestCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/WaitConditionEvaluator.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/WaitConditionEvaluator.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/WaitForCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/WaitForCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/WaitRegistry.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Commands/WaitRegistry.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Console.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Console/EditorConsoleCaptureBootstrap.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Console/EditorConsoleCaptureBootstrap.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Console/EditorConsoleEntries.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Console/EditorConsoleEntries.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Console/EditorConsoleGroundTruth.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Console/EditorConsoleGroundTruth.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/EditorCodeReloadWatcher.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/EditorCodeReloadWatcher.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/EditorDialogStateMirror.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/EditorDialogStateMirror.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineManager.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineManager.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineManagerEditor.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineManagerEditor.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineServer.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineServer.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineStartup.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineStartup.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/EditorProgressMirror.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/EditorProgressMirror.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/PipelineAnalytics.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/PipelineAnalytics.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/PipelineTransactionLog.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/PipelineTransactionLog.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/PushSigner.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/PushSigner.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/PushSigningKey.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/PushSigningKey.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/RuntimePipelineConfigEditor.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/RuntimePipelineConfigEditor.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/RuntimePipelineSettingsProvider.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/RuntimePipelineSettingsProvider.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Testing.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Testing/PipelineTestRunner.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Testing/PipelineTestRunner.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Testing/TestResultCollector.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Testing/TestResultCollector.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/TypeCacheCommandDiscovery.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/TypeCacheCommandDiscovery.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Unity.Pipeline.Editor.asmdef create mode 100644 AIClient/Packages/com.unity.pipeline/Editor/Unity.Pipeline.Editor.asmdef.meta create mode 100644 AIClient/Packages/com.unity.pipeline/LICENSE.md create mode 100644 AIClient/Packages/com.unity.pipeline/LICENSE.md.meta create mode 100644 AIClient/Packages/com.unity.pipeline/README.md create mode 100644 AIClient/Packages/com.unity.pipeline/README.md.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Analyzers.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Analyzers/IlInterpreterAnalyzer.dll create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Analyzers/IlInterpreterAnalyzer.dll.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/AssemblyInfo.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/AssemblyInfo.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Attributes.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Attributes/CodeReloadAttributes.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Attributes/CodeReloadAttributes.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Attributes/Unity.Pipeline.Attributes.asmdef create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Attributes/Unity.Pipeline.Attributes.asmdef.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/CodeReload.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/AccessibilityValidator.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/AccessibilityValidator.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/CodeReloadActivity.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/CodeReloadActivity.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/CodeReloadBaseline.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/CodeReloadBaseline.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/CodeReloadRegistry.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/CodeReloadRegistry.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/InPlaceReloadProcessor.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/InPlaceReloadProcessor.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/PipelineCodeReloadConnect.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/PipelineCodeReloadConnect.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/PushEnvelope.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/PushEnvelope.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/SourceCodeTransformer.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/SourceCodeTransformer.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Commands.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Commands/CaptureRuntimeElementCommand.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Commands/CaptureRuntimeElementCommand.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Commands/CodeEvalCommand.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Commands/CodeEvalCommand.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Commands/CodeReloadCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Commands/CodeReloadCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Commands/ConsoleCommand.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Commands/ConsoleCommand.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Commands/EvalTelemetryCommand.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Commands/EvalTelemetryCommand.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeApplicationCommand.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeApplicationCommand.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeInputCommand.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeInputCommand.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeLogCommand.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeLogCommand.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeStatusCommand.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeStatusCommand.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Commands/VisualElementCaptureSupport.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Commands/VisualElementCaptureSupport.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/BasePipelineServer.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/BasePipelineServer.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/CliArgAttribute.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/CliArgAttribute.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/CliCommandAttribute.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/CliCommandAttribute.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/CliProgress.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/CliProgress.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandExecutionInfo.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandExecutionInfo.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandInfo.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandInfo.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandLineBinder.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandLineBinder.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandLineTokenizer.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandLineTokenizer.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandRegistry.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandRegistry.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/DialogStateTracker.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/DialogStateTracker.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/Dispatcher.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/Dispatcher.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/ExecResponseSerializer.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/ExecResponseSerializer.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/FilePermissions.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/FilePermissions.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/ICommandDiscovery.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/ICommandDiscovery.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/IStructuredCommandInput.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/IStructuredCommandInput.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/JsonSchemaGenerator.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/JsonSchemaGenerator.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/MaxLengthStream.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/MaxLengthStream.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/ParameterInfo.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/ParameterInfo.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/PipelineJobs.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/PipelineJobs.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/PipelineUtils.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/PipelineUtils.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/RotatingFileBackup.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Common/RotatingFileBackup.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Compilation.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Compilation/CodeReloadCompiler.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Compilation/CodeReloadCompiler.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Compilation/EvalCodeCompiler.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Compilation/EvalCodeCompiler.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Compilation/IlInterpreterHostBindings.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Compilation/IlInterpreterHostBindings.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Compilation/InterpolationToFormatRewriter.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Compilation/InterpolationToFormatRewriter.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Compilation/InterpreterCodeReloadExecutor.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Compilation/InterpreterCodeReloadExecutor.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Compilation/RoslynCompilationService.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Compilation/RoslynCompilationService.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Console.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Console/ConsoleLogBuffer.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Console/ConsoleLogBuffer.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Console/ConsoleLogCapture.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Console/ConsoleLogCapture.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/AssemblyInfo.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/AssemblyInfo.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/HostBinding.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/HostBinding.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/IFrameAllocator.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/IFrameAllocator.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/IScript.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/IScript.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/IrDisassembler.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/IrDisassembler.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/MarshalFrameAllocator.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/MarshalFrameAllocator.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Op.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Op.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptDelegateAdapter.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptDelegateAdapter.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptEnumerator.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptEnumerator.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptException.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptException.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptInterpreter.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptInterpreter.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptObject.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptObject.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Unity.Pipeline.IlInterpreter.asmdef create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Unity.Pipeline.IlInterpreter.asmdef.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Value.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Value.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Vm.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Vm.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/VmEngine.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/VmEngine.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/ArgProblem.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/ArgProblem.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/AuthoringResult.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/AuthoringResult.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/BaseResponse.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/BaseResponse.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/CommandExecutionRequest.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/CommandExecutionRequest.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/CommandExecutionResponse.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/CommandExecutionResponse.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/ConsoleGroundTruth.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/ConsoleGroundTruth.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/ConsoleLogEntry.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/ConsoleLogEntry.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/ConsoleLogResponse.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/ConsoleLogResponse.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/EvalResponse.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/EvalResponse.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/InstanceDescriptor.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/InstanceDescriptor.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/ObjectRef.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/ObjectRef.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/ObjectRefConverter.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/ObjectRefConverter.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/RuntimeInstanceDescriptor.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/RuntimeInstanceDescriptor.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/StatusResponse.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/StatusResponse.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/TestExecutionResponse.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/TestExecutionResponse.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/TestResult.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/TestResult.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/TestSummary.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Models/TestSummary.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/CodeReloadStatusOverlay.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/CodeReloadStatusOverlay.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/FrameStatsSampler.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/FrameStatsSampler.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineBootstrap.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineBootstrap.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineBuildInfo.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineBuildInfo.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineConfig.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineConfig.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineDriver.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineDriver.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineServer.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineServer.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Plugins.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Plugins/CodeAnalysis.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Plugins/CodeAnalysis/CHECKSUMS create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Plugins/CodeAnalysis/CHECKSUMS.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Plugins/CodeAnalysis/UnityPipeline.Microsoft.CodeAnalysis.CSharp.dll create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Plugins/CodeAnalysis/UnityPipeline.Microsoft.CodeAnalysis.CSharp.dll.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Plugins/CodeAnalysis/UnityPipeline.Microsoft.CodeAnalysis.dll create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Plugins/CodeAnalysis/UnityPipeline.Microsoft.CodeAnalysis.dll.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Plugins/CodeAnalysis/UnityPipeline.System.Collections.Immutable.dll create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Plugins/CodeAnalysis/UnityPipeline.System.Collections.Immutable.dll.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Plugins/CodeAnalysis/UnityPipeline.System.Reflection.Metadata.dll create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Plugins/CodeAnalysis/UnityPipeline.System.Reflection.Metadata.dll.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Plugins/CodeAnalysis/UnityPipeline.System.Runtime.CompilerServices.Unsafe.dll create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Plugins/CodeAnalysis/UnityPipeline.System.Runtime.CompilerServices.Unsafe.dll.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/SecurityTokenManager.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/SecurityTokenManager.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Telemetry.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Telemetry/EvalUsageFingerprinter.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Telemetry/EvalUsageFingerprinter.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Telemetry/EvalUsageReport.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Telemetry/EvalUsageReport.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Telemetry/EvalUsageTelemetry.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Telemetry/EvalUsageTelemetry.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Unity.Pipeline.asmdef create mode 100644 AIClient/Packages/com.unity.pipeline/Runtime/Unity.Pipeline.asmdef.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Samples~/CodeReload.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_InPlace.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_InPlace/CodeReload_InPlace.unity create mode 100644 AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_InPlace/CodeReload_InPlace.unity.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_InPlace/InPlaceCodeReloadExample.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_InPlace/InPlaceCodeReloadExample.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_Minics/PongScene.unity create mode 100644 AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_Minics/PongScene.unity.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_Minics/README.md create mode 100644 AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_Minics/pong.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_Minics/pong.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/Unity.Pipeline.Samples.asmdef create mode 100644 AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/Unity.Pipeline.Samples.asmdef.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation/AnimationClipCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation/AnimationClipCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation/AnimatorControllerCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation/AnimatorControllerCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation/TimelineCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation/TimelineCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ApiEndpointsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ApiEndpointsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/AssetCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/AssetCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/AssetImportCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/AssetImportCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/ImportSettingsCommandTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/ImportSettingsCommandTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/MaterialAssetCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/MaterialAssetCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/PhysicsMaterialAssetCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/PhysicsMaterialAssetCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/TextFileCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/TextFileCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/FolderCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/FolderCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/ObjectRefConverterTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/ObjectRefConverterTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/ObjectResolverTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/ObjectResolverTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/ProjectPathsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/ProjectPathsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/AutoTickCommandTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/AutoTickCommandTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking/LightingBakeCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking/LightingBakeCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking/NavMeshBakeCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking/NavMeshBakeCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking/OcclusionBakeCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking/OcclusionBakeCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Batch.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Batch/BatchCommandTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Batch/BatchCommandTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/BuildConfigCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/BuildConfigCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Capture.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Capture/CaptureCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Capture/CaptureCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CaptureVisualElementCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CaptureVisualElementCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeEvalCommandTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeEvalCommandTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeReloadAssemblyDirectoryTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeReloadAssemblyDirectoryTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeReloadAttributeTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeReloadAttributeTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeReloadBaselineTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeReloadBaselineTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeReloadBasicTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeReloadBasicTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeReloadCommandTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeReloadCommandTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeReloadCompilerTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeReloadCompilerTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeReloadConnectWireTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeReloadConnectWireTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeReloadCoroutineTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeReloadCoroutineTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeReloadInPlaceTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeReloadInPlaceTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeReloadLinkXmlGeneratorTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeReloadLinkXmlGeneratorTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeReloadRegistryTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeReloadRegistryTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeReloadStaticTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeReloadStaticTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeReloadVerificationTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CodeReloadVerificationTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CommandLineBinderTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CommandLineBinderTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CommandLineTokenizerTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CommandLineTokenizerTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CommandRegistrationTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/CommandRegistrationTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Console.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Console/ConsoleCaptureResubscribeTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Console/ConsoleCaptureResubscribeTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Console/EditorConsoleGroundTruthTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Console/EditorConsoleGroundTruthTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ConsoleCommandTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ConsoleCommandTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ConsoleLogBufferTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ConsoleLogBufferTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/DialogEndpointTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/DialogEndpointTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/DialogStateTrackerTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/DialogStateTrackerTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/DialogsDuringExecutionTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/DialogsDuringExecutionTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/DynamicCommandRegistrationTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/DynamicCommandRegistrationTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/E2E.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/E2E/AgentAuthoringE2ETests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/E2E/AgentAuthoringE2ETests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/EditorAutomationModeTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/EditorAutomationModeTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/EditorCodeReloadWatcherJournalTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/EditorCodeReloadWatcherJournalTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/EditorCodeReloadWatcherTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/EditorCodeReloadWatcherTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/EditorStatusCommandTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/EditorStatusCommandTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/EditorTestUtilities.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/EditorTestUtilities.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/EvalCodeCompilerTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/EvalCodeCompilerTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/EvalTelemetryTestGuard.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/EvalTelemetryTestGuard.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/FrameStatsSamplerTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/FrameStatsSamplerTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/GameObjects.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/GameObjects/CoercionAndBatchTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/GameObjects/CoercionAndBatchTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/GameObjects/ComponentCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/GameObjects/ComponentCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/GameObjects/GameObjectCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/GameObjects/GameObjectCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/IlInterpreterAutoBindTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/IlInterpreterAutoBindTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/IlInterpreterCodeReloadInterpreterTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/IlInterpreterCodeReloadInterpreterTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/IlInterpreterHostInteropTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/IlInterpreterHostInteropTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/IlInterpreterHostSurfaceTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/IlInterpreterHostSurfaceTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/IlInterpreterPerfBenchmarks.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/IlInterpreterPerfBenchmarks.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/IlInterpreterWideValueEditorTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/IlInterpreterWideValueEditorTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/InstanceDiscoveryTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/InstanceDiscoveryTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/JobEndpointTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/JobEndpointTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/LiveServerGuard.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/LiveServerGuard.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/LoopbackBindingTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/LoopbackBindingTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Materials.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Materials/MaterialCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Materials/MaterialCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Materials/ShaderCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Materials/ShaderCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/MaxLengthStreamTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/MaxLengthStreamTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/MenuCommandTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/MenuCommandTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Models.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Models/ObjectRefConverterTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Models/ObjectRefConverterTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Navigation.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Navigation/NavigationCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Navigation/NavigationCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Observability.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Observability/ObservabilityCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Observability/ObservabilityCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/PackageManagerCommandTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/PackageManagerCommandTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/PipelineAnalyticsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/PipelineAnalyticsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/PipelineRuntimeBuildProcessorTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/PipelineRuntimeBuildProcessorTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/PipelineTestServer.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/PipelineTestServer.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/PipelineTransactionLogTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/PipelineTransactionLogTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/PipelineWatchdogTestGuard.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/PipelineWatchdogTestGuard.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/PlayModeCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/PlayModeCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/PlayModeReloadGuard.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/PlayModeReloadGuard.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Prefabs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Prefabs/PrefabCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Prefabs/PrefabCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ProgressEndpointTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ProgressEndpointTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ProjectAudit.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ProjectAudit/ProjectAuditCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ProjectAudit/ProjectAuditCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ProjectSettingsCommandTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ProjectSettingsCommandTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ProjectSettingsGroupCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ProjectSettingsGroupCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/PushBindingValidationTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/PushBindingValidationTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/PushSigningTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/PushSigningTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RecompileCommandTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RecompileCommandTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RecompileStatusTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RecompileStatusTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ReloadPathValidationTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ReloadPathValidationTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ResponseEnvelopeSizeTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ResponseEnvelopeSizeTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RoslynChecksumTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RoslynChecksumTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RoslynCompilationServiceTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RoslynCompilationServiceTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimeApplicationCommandTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimeApplicationCommandTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimeInputCommandTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimeInputCommandTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimeInstanceDescriptorTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimeInstanceDescriptorTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimeLogCommandTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimeLogCommandTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimePipelineBootstrapTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimePipelineBootstrapTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimePipelineBuildInfoTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimePipelineBuildInfoTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimePipelineBuildTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimePipelineBuildTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimePipelineConfigEditorTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimePipelineConfigEditorTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimePipelineConfigTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimePipelineConfigTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimePipelineDriverTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimePipelineDriverTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimePipelineResourceTestGuard.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimePipelineResourceTestGuard.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimePipelineServerTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimePipelineServerTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimePipelineSettingsCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimePipelineSettingsCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimePipelineSettingsProviderTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimePipelineSettingsProviderTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimeStatusCommandTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/RuntimeStatusCommandTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Scenes.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Scenes/SceneCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Scenes/SceneCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ScreenshotCommandTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ScreenshotCommandTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Scripts.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Scripts/RunScriptCommandTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Scripts/RunScriptCommandTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Scripts/ScriptCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Scripts/ScriptCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/SecurityTokenTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/SecurityTokenTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ServerAuthTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ServerAuthTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ServerLifecycle.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ServerLifecycle/DialogGateTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ServerLifecycle/DialogGateTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ServerLifecycle/DialogStateMirrorResubscribeTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ServerLifecycle/DialogStateMirrorResubscribeTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ServerLifecycle/DualServerTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ServerLifecycle/DualServerTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ServerLifecycle/EndToEndTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ServerLifecycle/EndToEndTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ServerLifecycle/GlobalServerStateGuard.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ServerLifecycle/GlobalServerStateGuard.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ServerLifecycle/GlobalServerStateGuardTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ServerLifecycle/GlobalServerStateGuardTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ServerLifecycle/PipelineServerTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ServerLifecycle/PipelineServerTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ServerLifecycle/SettleGateTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/ServerLifecycle/SettleGateTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Telemetry.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Telemetry/EvalTelemetryCommandTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Telemetry/EvalTelemetryCommandTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Telemetry/EvalUsageFingerprinterTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Telemetry/EvalUsageFingerprinterTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Telemetry/EvalUsageReportTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Telemetry/EvalUsageReportTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Telemetry/EvalUsageTelemetryTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Telemetry/EvalUsageTelemetryTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/TestCommandsTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/TestCommandsTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/TestEditorPipelineServer.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/TestEditorPipelineServer.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/TestOnlyCommands.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/TestOnlyCommands.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/TestResultCollectorTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/TestResultCollectorTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/TransformTwinFixtures.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/TransformTwinFixtures.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Unity.Pipeline.Tests.Editor.asmdef create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/Unity.Pipeline.Tests.Editor.asmdef.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/WaitForCommandTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Editor/WaitForCommandTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Runtime.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Runtime/AssemblyInfo.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Runtime/AssemblyInfo.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Runtime/AttachByPathFixture.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Runtime/AttachByPathFixture.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Runtime/CodeReloadInPlaceEditingTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Runtime/CodeReloadInPlaceEditingTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Runtime/IlInterpreterAotProbeBlobs.g.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Runtime/IlInterpreterAotProbeBlobs.g.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Runtime/IlInterpreterAotSmokeTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Runtime/IlInterpreterAotSmokeTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Runtime/IlInterpreterPlayModeTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Runtime/IlInterpreterPlayModeTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Runtime/PipelineClient.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Runtime/PipelineClient.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Runtime/RuntimeServerPlayModeSmokeTests.cs create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Runtime/RuntimeServerPlayModeSmokeTests.cs.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Runtime/Unity.Pipeline.Tests.Runtime.asmdef create mode 100644 AIClient/Packages/com.unity.pipeline/Tests~/Runtime/Unity.Pipeline.Tests.Runtime.asmdef.meta create mode 100644 AIClient/Packages/com.unity.pipeline/Third Party Notices.md create mode 100644 AIClient/Packages/com.unity.pipeline/Third Party Notices.md.meta create mode 100644 AIClient/Packages/com.unity.pipeline/package.json create mode 100644 AIClient/Packages/com.unity.pipeline/package.json.meta create mode 100644 AIClient/Packages/manifest.json create mode 100644 AIClient/Packages/packages-lock.json create mode 100644 AIClient/ProjectSettings/AudioManager.asset create mode 100644 AIClient/ProjectSettings/ClusterInputManager.asset create mode 100644 AIClient/ProjectSettings/DynamicsManager.asset create mode 100644 AIClient/ProjectSettings/EditorBuildSettings.asset create mode 100644 AIClient/ProjectSettings/EditorSettings.asset create mode 100644 AIClient/ProjectSettings/GraphicsSettings.asset create mode 100644 AIClient/ProjectSettings/InputManager.asset create mode 100644 AIClient/ProjectSettings/MemorySettings.asset create mode 100644 AIClient/ProjectSettings/NavMeshAreas.asset create mode 100644 AIClient/ProjectSettings/PackageManagerSettings.asset create mode 100644 AIClient/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json create mode 100644 AIClient/ProjectSettings/Physics2DSettings.asset create mode 100644 AIClient/ProjectSettings/PresetManager.asset create mode 100644 AIClient/ProjectSettings/ProjectSettings.asset create mode 100644 AIClient/ProjectSettings/ProjectVersion.txt create mode 100644 AIClient/ProjectSettings/QualitySettings.asset create mode 100644 AIClient/ProjectSettings/ShaderGraphSettings.asset create mode 100644 AIClient/ProjectSettings/TagManager.asset create mode 100644 AIClient/ProjectSettings/TimeManager.asset create mode 100644 AIClient/ProjectSettings/URPProjectSettings.asset create mode 100644 AIClient/ProjectSettings/UnityConnectSettings.asset create mode 100644 AIClient/ProjectSettings/VFXManager.asset create mode 100644 AIClient/ProjectSettings/VersionControlSettings.asset create mode 100644 AIClient/ProjectSettings/XRSettings.asset create mode 100644 Agents.md create mode 100644 Doc/ResDesc.md create mode 100644 Doc/ResDesc_Animation.md create mode 100644 Doc/ResDesc_Effect.md create mode 100644 Doc/ResDesc_Model.md create mode 100644 Doc/ResDesc_Picture.md create mode 100644 Doc/ResDesc_Sound.md create mode 100644 Doc/UI_Normal_Set.md create mode 100644 Doc/UI_Pic_Set.md create mode 100644 Doc/UI_Simple_Set.md create mode 100644 Doc/gpt-image_doc.md create mode 100644 Doc/minimax-h3_doc.md create mode 100644 Doc/ui_design.jpg create mode 100644 ProjectDesign.md create mode 100644 ResourceCreate.md create mode 100644 Tools/gpt_image_generate.py create mode 100644 Tools/hunyuan_3d/__init__.py create mode 100644 Tools/hunyuan_3d/auth.py create mode 100644 Tools/hunyuan_3d/client.py create mode 100644 Tools/hunyuan_3d/events.py create mode 100644 Tools/hunyuan_3d_generate.py create mode 100644 Tools/model_tools/README.md create mode 100644 Tools/model_tools/bl_bake.py create mode 100644 Tools/model_tools/bl_decimate.py create mode 100644 Tools/model_tools/model_bake.py create mode 100644 Tools/model_tools/model_decimate.py create mode 100644 Tools/model_tools/model_lowpoly_bake.py create mode 100644 Tools/model_tools/mt_run.py create mode 100644 Tools/model_tools/tests/test_model_formats.py create mode 100644 Tools/model_tools/uv_preview.py create mode 100644 Tools/output/_vip_probe.json create mode 100644 Tools/output/_vip_probe.png create mode 100644 Tools/output/male_explorer_cursor.png create mode 100644 Tools/output/male_explorer_status.json create mode 100644 Tools/output/male_explorer_test.png create mode 100644 Tools/output/ui_normal_atlas_gpt.png create mode 100644 Tools/output/ui_normal_atlas_gpt_status.json create mode 100644 Tools/output/ui_normal_atlas_job.json create mode 100644 Tools/output/ui_normal_atlas_prompt.txt create mode 100644 Tools/output/ui_simple_atlas_gpt.png create mode 100644 Tools/output/ui_simple_atlas_gpt_status.json create mode 100644 Tools/output/ui_simple_atlas_prompt.txt create mode 100644 Tools/requirements-hunyuan.txt create mode 100644 Tools/requirements.txt create mode 100644 UNITY-GUIDE.md diff --git a/.claude/skills/unity-pipeline/SKILL.md b/.claude/skills/unity-pipeline/SKILL.md new file mode 100644 index 0000000..c4e4ab2 --- /dev/null +++ b/.claude/skills/unity-pipeline/SKILL.md @@ -0,0 +1,173 @@ +--- +name: unity-pipeline +description: Drive a running Unity Editor or development Player from the command line via the unity-pipeline package — install the package, keep the editor ticking while unfocused, run the edit→recompile→run_tests loop, evaluate C#, and code-reload files at runtime. Use when an agent needs to control a live Unity instance, automate Unity tests, recompile scripts headlessly, or apply runtime reloads. Assumes the `unity` CLI is on PATH. +--- + +# Unity Pipeline (agent control) + +Invoke commands with `unity command [args]`. Run `unity command` with no name to +list what an instance exposes. Two servers exist: **Editor** (`7800-7849`, auto-starts with +the editor) and **Runtime** (`7900-7949`, only in a dev Player build). See the package +`README.md` "Commands" reference for the full list and parameters. + +## 1. Install & verify + +```bash +unity pipeline install # install into current project (or --project-path) +unity pipeline list # confirm the editor instance + server are reachable +unity command editor_status # confirm the editor server answers +``` + +## 2. Autonomous edit loop (Editor) + +This is the core agent workflow: keep the editor alive, change code, recompile, test. + +```bash +# 1. Keep the editor ticking even when unfocused/minimized. REQUIRED before headless work — +# Unity otherwise throttles or stalls update/compile when it isn't the active app. +unity command set_autotick --enable true + +# 2. Edit C# source files on disk normally. + +# 3. Recompile (async: triggers a domain reload, then poll until done). +unity command recompile +unity command recompile_status # repeat until "completed" or "up_to_date" +# Tolerate connection errors while the domain reload is in flight — that is expected. +# If recompile_status reports failed=true, read its "errors" array and fix before testing. + +# 4. (Optional) List available tests without running them. +unity command list_tests --mode editor # mode: all | editor | playmode + +# 5. Run tests (filter to keep it fast). +unity command run_tests --mode editor --filter MyFixture.MyTest +``` + +`run_tests` modes: `all` | `editor` | `playmode`. `filter_type`: `testName` | `assembly` | +`category`. For long runs use `--async_tests true` and poll `unity command test_status` +(abort with `unity command cancel_tests`). + +> **Known caveat:** when any selected test *fails*, `run_tests` may surface an opaque +> result instead of the failure details. Re-run a narrower `--filter`, or inspect the +> editor's Test Runner / logs to get the real failure. + +**Reading exit codes.** They separate "rewrite the invocation" from "the Editor failed", which +is the distinction this loop depends on: + +| Exit | Meaning | What to do | +|------|---------|------------| +| `2` | Bad arguments — a misspelled flag, a wrong type, too many positionals. Nothing ran. | Fix the command line and retry. The error names the problem and often suggests the right flag. | +| `6` | The command ran and failed, or the Editor could not service it. | Read the error; retrying the same invocation will not help. | + +Do not retry an exit 2 unchanged, and do not rewrite a command line on an exit 6. + +## 3. Runtime code reload + +Change gameplay code in a **running** game with no domain reload. The game must be live: +enter Editor Play Mode (`unity command editor_play`) or run a dev Player. A +The runtime Pipeline driver (enabled via Project Settings > Pipeline > Runtime) auto-discovers tagged methods on `Awake` (no manual +registration). Mono only — Editor Play Mode and Mono desktop dev builds, not IL2CPP. The token +is auto-injected for local requests. + +### `reload_file` + +Edit the method body directly; no separate file, no boilerplate. + +1. Tag the method `[CodeReload]` on the MonoBehaviour. +2. Edit its body on disk. +3. Apply (re-run to iterate): + ```bash + unity command reload_file --filename Assets/Spinner.cs + ``` + Add `--pdb` to make it debuggable — emits a portable PDB mapped to your source so breakpoints in + the original file bind (attach the IDE + enable Editor Attaching; compiles unoptimized): + ```bash + unity command reload_file --filename Assets/Spinner.cs --pdb + ``` + +Constraints: `void` instance methods only; **public** members only; debugging requires `--pdb` +(the default emits no symbols). + +`unity command codereload_status` shows active overrides. `reload_file` options: `--timeout ` +(default 30000), `--assemblyDir ` (persist DLLs instead of in-memory); +`cleanup_codereload --assemblyDir ` clears old DLLs. + +## 4. Bulk construction: `run_script` (the builder pattern) + +For bulk work — creating many objects, wiring fields, generating content — put the code in a +**versioned project script** and run a named static entry point with `run_script`. No domain +reload, no code carried through the protocol; iterating costs an in-memory compile (< ~2s), not +a 15–20s recompile. + +```bash +# 1. Write the builder OUTSIDE Assets/ (so the write triggers no asset import / domain reload), +# e.g. AgentScripts/Build.cs: public static class Build { public static int All() { ... } } +# 2. Run it — relative paths resolve against the project root (the parent of Assets/): +unity command run_script --file AgentScripts/Build.cs --entry Build.All +# 3. Iterate: edit the file, re-run. Useful extras: +unity command run_script --file AgentScripts/Build.cs --dry_run true # compile-only check: diagnostics, nothing loaded or executed +unity command run_script --file AgentScripts/Build.cs --entry Build.All --args '[3, "Green"]' +``` + +Rules of thumb: + +- **Code goes in files on disk via `run_script`; `eval` is for genuinely ad-hoc one-liners.** + Never ship multi-line escaped C# strings through `eval` — write the file, run the entry. +- Compiles see the project's **active editor defines** (`UNITY_EDITOR`, version/platform symbols); + `--defines` appends extra symbols on top. +- Entry points may be `async Task`/`Task` — they are awaited asynchronously (the editor keeps + pumping, so awaits resuming on Unity's context work naturally) and `Task.Result` is returned. + The wait is bounded by `timeout_ms`; on expiry the task keeps running detached. +- Runtime exceptions come back with `file:line` mapped to your source (a source-mapped PDB is + always emitted for executing runs; they compile unoptimized). +- `--mode hotpatch` instead applies `[CodeReload]` in-place method replacements (delegates to + `reload_file`); `entry`/`args`/`dry_run` are rejected there and `references`/`defines` don't apply. + +## 5. Quick C# eval (Runtime) + +For genuinely ad-hoc one-liners only — anything longer belongs in a file run via `run_script`. + +```bash +unity command eval "return 2 + 2;" +# Or evaluate a .cs file on disk (contents run through the same path): +unity command eval_file Assets/Scratch.cs +``` + +## 5. Project audit (Editor) + +Static-analysis scan via Project Auditor, producing a CSV of issues to fix. Trigger, poll, read. + +```bash +unity command audit # optional: --categories Code,ProjectSetting --output my.csv +unity command audit_status # repeat until terminal status +``` + +`audit_status` is terminal on `completed` (with `csvPath` + `issueCount`), `failed`, `unavailable`, or +`interrupted` (a domain reload killed the scan — just re-run `audit`). Polling stays responsive while a +Code-category scan compiles assemblies and holds the main thread. One scan at a time: a second `audit` +returns `busy`. There is no cancel — stop polling to abandon a scan. + +CSV columns: `Category, Severity, Areas, Description, RelativePath, Line, DescriptorId, Recommendation` +(diagnostics only, so every row is something to fix; `Recommendation` says how). + +> **Requires Project Auditor plus its rules.** `unavailable` means the Editor has no Project Auditor, +> or it has no analysis rules — in a built-in-module Editor the rules live in the separate +> `com.unity.project-auditor-rules` package (`unity command package_add --identifier +> com.unity.project-auditor-rules --confirm true`). Read the `message` field; the command never reports +> an empty `completed` scan that would look like a clean project. + +## Gotchas + +- **`set_autotick` first.** Without it, recompile and tests can hang while the editor is + unfocused. The package's watchdog relies on the tick loop staying alive. +- **A stuck command may mean a modal dialog is open**, not a hang — a dialog blocks the main + thread until dismissed. If a command runs long, check `unity command editor_status` (answers + instantly even when blocked); `status: "blocked_by_dialog"` means stop retrying and tell the + human what's blocking (its `dialog.title`/`message`/`buttons`) — it can't be clicked over CLI. +- **Code reload needs the game running.** `reload_file` applies to a live + game — enter Editor Play Mode (`unity command editor_play`) first, or run a dev Player. +- **Player-only commands need a dev Player.** `log`, `set_timescale`, `runtime_status`, etc. hit + the Runtime server, which does not run in the Editor. +- **Async commands poll.** `recompile`→`recompile_status`, `run_tests --async_tests`→ + `test_status`. Never assume completion from the trigger call's response. +- **Target a specific instance** with `--instance host:port` or `--project-path ` + when more than one is running. diff --git a/.cursor/rules/aigame-basics.mdc b/.cursor/rules/aigame-basics.mdc new file mode 100644 index 0000000..da50c2f --- /dev/null +++ b/.cursor/rules/aigame-basics.mdc @@ -0,0 +1,16 @@ +--- +description: AIGame 项目基础规则(资源登记等必须遵守) +alwaysApply: true +--- + +# AIGame 项目说明 + +## 基础规则 + +1. **资源登记(必须)**:所有资源生成完成后,必须按类型追加到对应描述文件,并写明简要说明(用途、路径、生成方式等)。未登记视为流程未完成。 + - 索引:`Doc/ResDesc.md` + - model → `Doc/ResDesc_Model.md` + - animation → `Doc/ResDesc_Animation.md` + - picture → `Doc/ResDesc_Picture.md` + - sound → `Doc/ResDesc_Sound.md` + - effect → `Doc/ResDesc_Effect.md` diff --git a/.cursor/skills/unity-pipeline/SKILL.md b/.cursor/skills/unity-pipeline/SKILL.md new file mode 100644 index 0000000..c4e4ab2 --- /dev/null +++ b/.cursor/skills/unity-pipeline/SKILL.md @@ -0,0 +1,173 @@ +--- +name: unity-pipeline +description: Drive a running Unity Editor or development Player from the command line via the unity-pipeline package — install the package, keep the editor ticking while unfocused, run the edit→recompile→run_tests loop, evaluate C#, and code-reload files at runtime. Use when an agent needs to control a live Unity instance, automate Unity tests, recompile scripts headlessly, or apply runtime reloads. Assumes the `unity` CLI is on PATH. +--- + +# Unity Pipeline (agent control) + +Invoke commands with `unity command [args]`. Run `unity command` with no name to +list what an instance exposes. Two servers exist: **Editor** (`7800-7849`, auto-starts with +the editor) and **Runtime** (`7900-7949`, only in a dev Player build). See the package +`README.md` "Commands" reference for the full list and parameters. + +## 1. Install & verify + +```bash +unity pipeline install # install into current project (or --project-path) +unity pipeline list # confirm the editor instance + server are reachable +unity command editor_status # confirm the editor server answers +``` + +## 2. Autonomous edit loop (Editor) + +This is the core agent workflow: keep the editor alive, change code, recompile, test. + +```bash +# 1. Keep the editor ticking even when unfocused/minimized. REQUIRED before headless work — +# Unity otherwise throttles or stalls update/compile when it isn't the active app. +unity command set_autotick --enable true + +# 2. Edit C# source files on disk normally. + +# 3. Recompile (async: triggers a domain reload, then poll until done). +unity command recompile +unity command recompile_status # repeat until "completed" or "up_to_date" +# Tolerate connection errors while the domain reload is in flight — that is expected. +# If recompile_status reports failed=true, read its "errors" array and fix before testing. + +# 4. (Optional) List available tests without running them. +unity command list_tests --mode editor # mode: all | editor | playmode + +# 5. Run tests (filter to keep it fast). +unity command run_tests --mode editor --filter MyFixture.MyTest +``` + +`run_tests` modes: `all` | `editor` | `playmode`. `filter_type`: `testName` | `assembly` | +`category`. For long runs use `--async_tests true` and poll `unity command test_status` +(abort with `unity command cancel_tests`). + +> **Known caveat:** when any selected test *fails*, `run_tests` may surface an opaque +> result instead of the failure details. Re-run a narrower `--filter`, or inspect the +> editor's Test Runner / logs to get the real failure. + +**Reading exit codes.** They separate "rewrite the invocation" from "the Editor failed", which +is the distinction this loop depends on: + +| Exit | Meaning | What to do | +|------|---------|------------| +| `2` | Bad arguments — a misspelled flag, a wrong type, too many positionals. Nothing ran. | Fix the command line and retry. The error names the problem and often suggests the right flag. | +| `6` | The command ran and failed, or the Editor could not service it. | Read the error; retrying the same invocation will not help. | + +Do not retry an exit 2 unchanged, and do not rewrite a command line on an exit 6. + +## 3. Runtime code reload + +Change gameplay code in a **running** game with no domain reload. The game must be live: +enter Editor Play Mode (`unity command editor_play`) or run a dev Player. A +The runtime Pipeline driver (enabled via Project Settings > Pipeline > Runtime) auto-discovers tagged methods on `Awake` (no manual +registration). Mono only — Editor Play Mode and Mono desktop dev builds, not IL2CPP. The token +is auto-injected for local requests. + +### `reload_file` + +Edit the method body directly; no separate file, no boilerplate. + +1. Tag the method `[CodeReload]` on the MonoBehaviour. +2. Edit its body on disk. +3. Apply (re-run to iterate): + ```bash + unity command reload_file --filename Assets/Spinner.cs + ``` + Add `--pdb` to make it debuggable — emits a portable PDB mapped to your source so breakpoints in + the original file bind (attach the IDE + enable Editor Attaching; compiles unoptimized): + ```bash + unity command reload_file --filename Assets/Spinner.cs --pdb + ``` + +Constraints: `void` instance methods only; **public** members only; debugging requires `--pdb` +(the default emits no symbols). + +`unity command codereload_status` shows active overrides. `reload_file` options: `--timeout ` +(default 30000), `--assemblyDir ` (persist DLLs instead of in-memory); +`cleanup_codereload --assemblyDir ` clears old DLLs. + +## 4. Bulk construction: `run_script` (the builder pattern) + +For bulk work — creating many objects, wiring fields, generating content — put the code in a +**versioned project script** and run a named static entry point with `run_script`. No domain +reload, no code carried through the protocol; iterating costs an in-memory compile (< ~2s), not +a 15–20s recompile. + +```bash +# 1. Write the builder OUTSIDE Assets/ (so the write triggers no asset import / domain reload), +# e.g. AgentScripts/Build.cs: public static class Build { public static int All() { ... } } +# 2. Run it — relative paths resolve against the project root (the parent of Assets/): +unity command run_script --file AgentScripts/Build.cs --entry Build.All +# 3. Iterate: edit the file, re-run. Useful extras: +unity command run_script --file AgentScripts/Build.cs --dry_run true # compile-only check: diagnostics, nothing loaded or executed +unity command run_script --file AgentScripts/Build.cs --entry Build.All --args '[3, "Green"]' +``` + +Rules of thumb: + +- **Code goes in files on disk via `run_script`; `eval` is for genuinely ad-hoc one-liners.** + Never ship multi-line escaped C# strings through `eval` — write the file, run the entry. +- Compiles see the project's **active editor defines** (`UNITY_EDITOR`, version/platform symbols); + `--defines` appends extra symbols on top. +- Entry points may be `async Task`/`Task` — they are awaited asynchronously (the editor keeps + pumping, so awaits resuming on Unity's context work naturally) and `Task.Result` is returned. + The wait is bounded by `timeout_ms`; on expiry the task keeps running detached. +- Runtime exceptions come back with `file:line` mapped to your source (a source-mapped PDB is + always emitted for executing runs; they compile unoptimized). +- `--mode hotpatch` instead applies `[CodeReload]` in-place method replacements (delegates to + `reload_file`); `entry`/`args`/`dry_run` are rejected there and `references`/`defines` don't apply. + +## 5. Quick C# eval (Runtime) + +For genuinely ad-hoc one-liners only — anything longer belongs in a file run via `run_script`. + +```bash +unity command eval "return 2 + 2;" +# Or evaluate a .cs file on disk (contents run through the same path): +unity command eval_file Assets/Scratch.cs +``` + +## 5. Project audit (Editor) + +Static-analysis scan via Project Auditor, producing a CSV of issues to fix. Trigger, poll, read. + +```bash +unity command audit # optional: --categories Code,ProjectSetting --output my.csv +unity command audit_status # repeat until terminal status +``` + +`audit_status` is terminal on `completed` (with `csvPath` + `issueCount`), `failed`, `unavailable`, or +`interrupted` (a domain reload killed the scan — just re-run `audit`). Polling stays responsive while a +Code-category scan compiles assemblies and holds the main thread. One scan at a time: a second `audit` +returns `busy`. There is no cancel — stop polling to abandon a scan. + +CSV columns: `Category, Severity, Areas, Description, RelativePath, Line, DescriptorId, Recommendation` +(diagnostics only, so every row is something to fix; `Recommendation` says how). + +> **Requires Project Auditor plus its rules.** `unavailable` means the Editor has no Project Auditor, +> or it has no analysis rules — in a built-in-module Editor the rules live in the separate +> `com.unity.project-auditor-rules` package (`unity command package_add --identifier +> com.unity.project-auditor-rules --confirm true`). Read the `message` field; the command never reports +> an empty `completed` scan that would look like a clean project. + +## Gotchas + +- **`set_autotick` first.** Without it, recompile and tests can hang while the editor is + unfocused. The package's watchdog relies on the tick loop staying alive. +- **A stuck command may mean a modal dialog is open**, not a hang — a dialog blocks the main + thread until dismissed. If a command runs long, check `unity command editor_status` (answers + instantly even when blocked); `status: "blocked_by_dialog"` means stop retrying and tell the + human what's blocking (its `dialog.title`/`message`/`buttons`) — it can't be clicked over CLI. +- **Code reload needs the game running.** `reload_file` applies to a live + game — enter Editor Play Mode (`unity command editor_play`) first, or run a dev Player. +- **Player-only commands need a dev Player.** `log`, `set_timescale`, `runtime_status`, etc. hit + the Runtime server, which does not run in the Editor. +- **Async commands poll.** `recompile`→`recompile_status`, `run_tests --async_tests`→ + `test_status`. Never assume completion from the trigger call's response. +- **Target a specific instance** with `--instance host:port` or `--project-path ` + when more than one is running. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..cbc6039 --- /dev/null +++ b/.gitignore @@ -0,0 +1,53 @@ +# Python / tools +Tools/__pycache__/ +Tools/**/__pycache__/ +Tools/**/*.pyc + +# 混元3D 登录凭证与任务中间文件(勿提交) +Tools/data/hunyuan/storage_state.json +Tools/data/hunyuan/status.json +Tools/data/hunyuan/jobs/ + +# model_tools 中间产物(按需) +Tools/model_tools/out_bake/ +Tools/model_tools/**/_low_work/ + +# 本地输出(按需取消忽略) +# Tools/output/ + +# ===== Unity ===== +AIClient/[Ll]ibrary/ +AIClient/[Tt]emp/ +AIClient/[Oo]bj/ +AIClient/[Bb]uild/ +AIClient/[Bb]uilds/ +AIClient/[Ll]ogs/ +AIClient/[Uu]ser[Ss]ettings/ +AIClient/[Mm]emoryCaptures/ +AIClient/[Rr]ecordings/ + +# Unity generated IDE / project files +AIClient/*.csproj +AIClient/*.sln +AIClient/*.suo +AIClient/*.user +AIClient/*.userprefs +AIClient/*.pidb +AIClient/*.booproj +AIClient/*.svd +AIClient/*.pdb +AIClient/*.mdb +AIClient/*.opendb +AIClient/*.VC.db +AIClient/.vs/ +AIClient/.gradle/ + +# HybridCLR intermediate clone repos (LocalIl2Cpp 可按需提交) +AIClient/HybridCLRData/hybridclr_repo/ +AIClient/HybridCLRData/il2cpp_plus_repo/ + +# Crash / OS +*.stackdump +Thumbs.db +Desktop.ini +.DS_Store diff --git a/AIClient/.vsconfig b/AIClient/.vsconfig new file mode 100644 index 0000000..f019fd0 --- /dev/null +++ b/AIClient/.vsconfig @@ -0,0 +1,6 @@ +{ + "version": "1.0", + "components": [ + "Microsoft.VisualStudio.Workload.ManagedGame" + ] +} diff --git a/AIClient/Assets/Editor.meta b/AIClient/Assets/Editor.meta new file mode 100644 index 0000000..72c71b0 --- /dev/null +++ b/AIClient/Assets/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1f9e1fb3ff717414ab8d0cf27dbc6f3d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/Editor/SetupHybridClr.cs b/AIClient/Assets/Editor/SetupHybridClr.cs new file mode 100644 index 0000000..133f013 --- /dev/null +++ b/AIClient/Assets/Editor/SetupHybridClr.cs @@ -0,0 +1,22 @@ +#if UNITY_EDITOR +using HybridCLR.Editor.Installer; + +public static class SetupHybridClr +{ + public static string Install() + { + var c = new InstallerController(); + if (c.HasInstalledHybridCLR()) + return $"already_installed pkg={c.PackageVersion} local={c.InstalledLibil2cppVersion}"; + + c.InstallDefaultHybridCLR(); + return $"installed pkg={c.PackageVersion} has={c.HasInstalledHybridCLR()} local={c.InstalledLibil2cppVersion}"; + } + + public static string Status() + { + var c = new InstallerController(); + return $"has={c.HasInstalledHybridCLR()} pkg={c.PackageVersion} local={c.InstalledLibil2cppVersion}"; + } +} +#endif diff --git a/AIClient/Assets/Editor/SetupHybridClr.cs.meta b/AIClient/Assets/Editor/SetupHybridClr.cs.meta new file mode 100644 index 0000000..1e4a09a --- /dev/null +++ b/AIClient/Assets/Editor/SetupHybridClr.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b09764b3bf807f248b2a73e9dc8f04da +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/Editor/SetupUrp.cs b/AIClient/Assets/Editor/SetupUrp.cs new file mode 100644 index 0000000..7e3cae6 --- /dev/null +++ b/AIClient/Assets/Editor/SetupUrp.cs @@ -0,0 +1,72 @@ +#if UNITY_EDITOR +using System.Text; +using UnityEditor; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.Rendering.Universal; + +public static class SetupUrp +{ + // Map Quality level name -> URP asset under Assets/Settings/URP + static readonly (string qualityName, string assetPath)[] QualityPipelineMap = + { + ("Very Low", "Assets/Settings/URP/UniversalRP-0VeryLowQuality.asset"), + ("Low", "Assets/Settings/URP/UniversalRP-1LowQuality.asset"), + ("Medium", "Assets/Settings/URP/UniversalRP-2MediumQuality.asset"), + ("High", "Assets/Settings/URP/UniversalRP-3HighQuality.asset"), + ("Very High", "Assets/Settings/URP/UniversalRP-4VeryHighQuality.asset"), + ("Ultra", "Assets/Settings/URP/UniversalRP-4VeryHighQuality.asset"), + }; + + const string FallbackPipeline = "Assets/Settings/URP/UniversalRP-3HighQuality.asset"; + + /// + /// Assign a URP asset to every Quality level and set Graphics default pipeline. + /// Fixes: "platforms have assets in its associated Quality levels that belong to different render pipelines" + /// + public static string FixQualityPipelines() + { + var log = new StringBuilder(); + var names = QualitySettings.names; + UniversalRenderPipelineAsset fallback = AssetDatabase.LoadAssetAtPath(FallbackPipeline); + if (fallback == null) + return "ERROR: missing fallback URP asset at " + FallbackPipeline; + + for (int i = 0; i < names.Length; i++) + { + var path = ResolvePipelinePath(names[i]); + var asset = AssetDatabase.LoadAssetAtPath(path) ?? fallback; + QualitySettings.SetQualityLevel(i, applyExpensiveChanges: false); + QualitySettings.renderPipeline = asset; + log.AppendLine($"{i}:{names[i]} -> {AssetDatabase.GetAssetPath(asset)}"); + } + + // Prefer High-tier as project default (Graphics Settings) + GraphicsSettings.renderPipelineAsset = + AssetDatabase.LoadAssetAtPath(FallbackPipeline) ?? fallback; + + // Restore previous current quality if possible, else Ultra/last + int restore = System.Array.IndexOf(names, "Ultra"); + if (restore < 0) restore = names.Length - 1; + QualitySettings.SetQualityLevel(restore, applyExpensiveChanges: true); + + AssetDatabase.SaveAssets(); + EditorUtility.SetDirty(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/QualitySettings.asset")[0]); + log.AppendLine("Graphics default -> " + AssetDatabase.GetAssetPath(GraphicsSettings.renderPipelineAsset)); + log.AppendLine("Current quality -> " + QualitySettings.names[QualitySettings.GetQualityLevel()]); + return log.ToString(); + } + + static string ResolvePipelinePath(string qualityName) + { + foreach (var entry in QualityPipelineMap) + { + if (entry.qualityName == qualityName) + return entry.assetPath; + } + return FallbackPipeline; + } + + public static string Execute() => FixQualityPipelines(); +} +#endif diff --git a/AIClient/Assets/Editor/SetupUrp.cs.meta b/AIClient/Assets/Editor/SetupUrp.cs.meta new file mode 100644 index 0000000..d5efecf --- /dev/null +++ b/AIClient/Assets/Editor/SetupUrp.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9e35ed0006e33004a987f71bac5117bf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/Scenes.meta b/AIClient/Assets/Scenes.meta new file mode 100644 index 0000000..8f68d9f --- /dev/null +++ b/AIClient/Assets/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7a5f0c1a941fd9c4fa22ba5b2e81514e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/Scenes/SampleScene.unity b/AIClient/Assets/Scenes/SampleScene.unity new file mode 100644 index 0000000..2221b04 --- /dev/null +++ b/AIClient/Assets/Scenes/SampleScene.unity @@ -0,0 +1,267 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 705507994} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &705507993 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 705507995} + - component: {fileID: 705507994} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &705507994 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 705507993} + m_Enabled: 1 + serializedVersion: 8 + m_Type: 1 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_Lightmapping: 1 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &705507995 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 705507993} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &963194225 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 963194228} + - component: {fileID: 963194227} + - component: {fileID: 963194226} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &963194226 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 +--- !u!20 &963194227 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_GateFitMode: 2 + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &963194228 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/AIClient/Assets/Scenes/SampleScene.unity.meta b/AIClient/Assets/Scenes/SampleScene.unity.meta new file mode 100644 index 0000000..952bd1e --- /dev/null +++ b/AIClient/Assets/Scenes/SampleScene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9fc0d4010bbf28b4594072e72b8655ab +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/Settings.meta b/AIClient/Assets/Settings.meta new file mode 100644 index 0000000..edc2ef0 --- /dev/null +++ b/AIClient/Assets/Settings.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1345306f7b23afb4bb7701f34d02bae3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/Settings/URP.meta b/AIClient/Assets/Settings/URP.meta new file mode 100644 index 0000000..1d7c601 --- /dev/null +++ b/AIClient/Assets/Settings/URP.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1424677654ae2a5429cb4ba77e52c1cf +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/Settings/URP/ForwardRenderer 0VeryLowQuality.asset b/AIClient/Assets/Settings/URP/ForwardRenderer 0VeryLowQuality.asset new file mode 100644 index 0000000..191a8c1 --- /dev/null +++ b/AIClient/Assets/Settings/URP/ForwardRenderer 0VeryLowQuality.asset @@ -0,0 +1,386 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-2127331727782644450 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 88650573, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: CharacterRenderFeature + m_EditorClassIdentifier: + m_Active: 1 +--- !u!114 &-277282247946242087 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1749369493, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: EffectRenderFeature + m_EditorClassIdentifier: + m_Active: 1 + RenderTargetName: _ScreenColorTexture + SamplingShader: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3} + BlitShader: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3} + UberEffectPostShader: {fileID: 4800000, guid: 0f60273b12723a047a568dca50178e02, type: 3} + UberEffectPostMaterial: {fileID: 0} + RenderTargetSampling: 0 + UberEffectPostShaderName: Engine/Effect/UberEffectPost +--- !u!114 &-172830343826181105 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 09d572d36a83daa4bb576ae814b31f16, type: 3} + m_Name: TAA + m_EditorClassIdentifier: + m_Active: 1 + PreviewInSceneView: 0 + UseMotionVector: 0 + RenderingMode: 0 + WorkOnPrepass: 0 + IgonreTransparentObject: 1 + Use32Bit: 0 + Shader: {fileID: 4800000, guid: 8c0d9373e5d33404ba27de953fd7a309, type: 3} +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: de640fe3d0db1804a85f9fc8f5cadab6, type: 3} + m_Name: ForwardRenderer 0VeryLowQuality + m_EditorClassIdentifier: + debugShaders: + debugReplacementPS: {fileID: 4800000, guid: cf852408f2e174538bcd9b7fda1c5ae7, type: 3} + hdrDebugViewPS: {fileID: 4800000, guid: 573620ae32aec764abd4d728906d2587, type: 3} + m_RendererFeatures: [] + m_RendererFeatureMap: + m_UseNativeRenderPass: 0 + postProcessData: {fileID: 0} + xrSystemData: {fileID: 11400000, guid: 60e1133243b97e347b653163a8c01b64, type: 2} + shaders: + blitPS: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3} + copyDepthPS: {fileID: 4800000, guid: d6dae50ee9e1bfa4db75f19f99355220, type: 3} + screenSpaceShadowPS: {fileID: 4800000, guid: 0f854b35a0cf61a429bd5dcfea30eddd, type: 3} + samplingPS: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3} + stencilDeferredPS: {fileID: 4800000, guid: e9155b26e1bc55942a41e518703fe304, type: 3} + fallbackErrorPS: {fileID: 4800000, guid: e6e9a19c3678ded42a3bc431ebef7dbd, type: 3} + fallbackLoadingPS: {fileID: 4800000, guid: 7f888aff2ac86494babad1c2c5daeee2, type: 3} + materialErrorPS: {fileID: 4800000, guid: 5fd9a8feb75a4b5894c241777f519d4e, type: 3} + coreBlitPS: {fileID: 4800000, guid: 93446b5c5339d4f00b85c159e1159b7c, type: 3} + coreBlitColorAndDepthPS: {fileID: 4800000, guid: d104b2fc1ca6445babb8e90b0758136b, type: 3} + blitHDROverlay: {fileID: 4800000, guid: a89bee29cffa951418fc1e2da94d1959, type: 3} + cameraMotionVector: {fileID: 4800000, guid: c56b7e0d4c7cb484e959caeeedae9bbf, type: 3} + objectMotionVector: {fileID: 4800000, guid: 7b3ede40266cd49a395def176e1bc486, type: 3} + dataDrivenLensFlare: {fileID: 4800000, guid: 6cda457ac28612740adb23da5d39ea92, type: 3} + terrainDetailLitPS: {fileID: 4800000, guid: f6783ab646d374f94b199774402a5144, type: 3} + terrainDetailGrassPS: {fileID: 4800000, guid: e507fdfead5ca47e8b9a768b51c291a1, type: 3} + terrainDetailGrassBillboardPS: {fileID: 4800000, guid: 29868e73b638e48ca99a19ea58c48d90, type: 3} + m_AssetVersion: 2 + m_OpaqueLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_TransparentLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_DefaultStencilState: + overrideStencilState: 0 + stencilReference: 0 + stencilCompareFunction: 8 + passOperation: 2 + failOperation: 0 + zFailOperation: 0 + m_ShadowTransparentReceive: 0 + m_RenderingMode: 0 + m_DepthPrimingMode: 0 + m_CopyDepthMode: 0 + m_AccurateGbufferNormals: 0 + m_IntermediateTextureMode: 1 +--- !u!114 &721371497446299689 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1181071007, guid: 58d7e77cafa53d146af19f551ff0a3f7, type: 3} + m_Name: NiloToonCharacterRendererFeature + m_EditorClassIdentifier: + m_Active: 1 + mCharacterRenderSetting: + mOutlineSetting: + ShouldRenderOutline: 1 + UseBigSceneOutline: 0 + BigSceneOutlineAtten: 250 + outlineWidthMultiplier: 4 + outlineTintColor: {r: 1, g: 1, b: 1, a: 1} + outlineWidthAutoAdjustToCameraDistanceAndFOV: 1 + mSelfShadowSetting: + mEnableSelfShadow: 0 + mShadowUDAngle: 20 + mShadowLRAngle: 1.4 + mShadowMapSize: 2048 + mMaxShadowDistance: 100 + mShadowDepthBias: 0.78 + mUseNDotLFix: 1 + mPerfectCullingForShadowCasters: 0 + mDebugShadowCameraVisibleBox: 0 + mMiscParamsSetting: + mFinalColorMultiplier: {r: 1, g: 1, b: 1, a: 1} + mRenderDepthNormal: 1 + mFinalColorIntensity: 1 + mCharacterValueMultiplier: 1 + mCharacterSaturateMultiplier: 0.2 + mGlobalMainDirectionalLightMultiplier: 0.7 + mOverridedLightUpDownAngle: -30 + mOverridedLightLRAngle: 30 + mOverrideLightDirectionIntensity: 1 + mSpecularIntensity: 1 + mSpecularColor: {r: 1, g: 1, b: 1, a: 1} + mUseMainLightDirForSpecular: 1 + mIndirecLightMinColor: {r: 0.01, g: 0.01, b: 0.01, a: 1} + mIndirecLightMultiplier: 1 + mOverridedRimLightUpDownAngle: 180 + mOverridedRimLightLRAngle: -66 + mOverrideRimLightDirectionIntensity: 1 + mGlobalRimLightTintColor: {r: 1, g: 1, b: 1, a: 1} + mGlobalRimLightMultipiler: 4 + mRimLightStartFadeIn: 0 + mRimLightStartFadeOut: 100 + mRimLightAndShadowWidthMultiplier: 2 + mRimLightDepthDiffThresholdOffset: 0.5 + mAddLightMultipiler: {r: 1, g: 1, b: 1, a: 0.5} + mAddLightMaxContribution: {r: 1, g: 1, b: 1, a: 1} + mShadowColor: {r: 0, g: 0, b: 0, a: 0.5} + mShadowAngle: 311 + mShadowLength: 0.89 + mShadowHeight: 0.1 +--- !u!114 &858565357924166977 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1137749194, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: OutlineFeature + m_EditorClassIdentifier: + m_Active: 1 + settings: + profilerTag: Selection Outline + targetLayer: + serializedVersion: 2 + m_Bits: 2048 + outlineMaterial: {fileID: 2100000, guid: 19d53d4eaf4ccbf479c715921ed8d533, type: 2} + outlineColor: {r: 1, g: 1, b: 1, a: 1} + outlineWidth: 1.5 + renderPassEvent: 550 +--- !u!114 &1787417439418964875 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1467291068, guid: 58d7e77cafa53d146af19f551ff0a3f7, type: 3} + m_Name: EffectRenderFeature + m_EditorClassIdentifier: + m_Active: 1 + RenderTargetName: _ScreenColorTexture + SamplingShader: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3} + BlitShader: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3} + UberEffectPostShader: {fileID: 4800000, guid: e4dc0f5e3a376594b807a6e398748f7b, type: 3} + UberEffectPostMaterial: {fileID: 0} + RenderTargetSampling: 1 + UberEffectPostShaderName: GYGame/Effect/UberEffectPost +--- !u!114 &3022920579844600396 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1741494071, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: GlobalScanFeature + m_EditorClassIdentifier: + m_Active: 1 + settings: + scanMaterial: {fileID: 2100000, guid: d67115296155f3c41ab11dbf400eaadf, type: 2} + renderPassEvent: 500 +--- !u!114 &4726037285063046694 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1608182031, guid: 58d7e77cafa53d146af19f551ff0a3f7, type: 3} + m_Name: SceneRenderFeature + m_EditorClassIdentifier: + m_Active: 1 + Settings: + SceneParameters: + CopyColor: 1 + ShadowColor: {r: 0.38492838, g: 0.3236027, b: 0.6792453, a: 1} + BakedShadowStrength: 0.807 + GlobalBrightness: 1 + SceneDebug: 0 + NormalDebug: 0 + VertexColorDebug: 0 + DebugCustomValue: + FogParameters: + OpenFog: 1 + LineFogColor: {r: 0.9811321, g: 0.8294182, b: 0.5784977, a: 1} + LineFogStartDistance: 77.46 + LineFogEndDistance: 144.2 + LineFogStrength: 0.846 + HeightFogColor: {r: 0.12116811, g: 0.56545126, b: 0.65199995, a: 1} + HeightFogStartHeight: -2.77 + HeightFogFalloff: 1.974 + HeightFogDensity: 0.0116 + HeightFogStartDistance: 55.1 + HeightFogMinOpacity: 1 + FogAmbient: 1 +--- !u!114 &4957971812801212640 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1749369493, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: EffectRenderFeature + m_EditorClassIdentifier: + m_Active: 1 + RenderTargetName: _ScreenColorTexture + SamplingShader: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3} + BlitShader: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3} + UberEffectPostShader: {fileID: 4800000, guid: 0f60273b12723a047a568dca50178e02, type: 3} + UberEffectPostMaterial: {fileID: 0} + RenderTargetSampling: 0 + UberEffectPostShaderName: Engine/Effect/UberEffectPost +--- !u!114 &5078528552640289789 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a5c14bbf9359ff549afb7ea0f09037df, type: 3} + m_Name: NiloToonCharacterRendererFeature + m_EditorClassIdentifier: + m_Active: 1 + mCharacterRenderSetting: + mOutlineSetting: + ShouldRenderOutline: 1 + UseBigSceneOutline: 0 + BigSceneOutlineAtten: 250 + outlineWidthMultiplier: 1 + outlineTintColor: {r: 1, g: 1, b: 1, a: 1} + outlineWidthAutoAdjustToCameraDistanceAndFOV: 1 + mSelfShadowSetting: + mEnableSelfShadow: 1 + mShadowUDAngle: 30 + mShadowLRAngle: 0 + mShadowMapSize: 512 + mMaxShadowDistance: 50 + mShadowDepthBias: 1 + mUseNDotLFix: 1 + mPerfectCullingForShadowCasters: 0 + mDebugShadowCameraVisibleBox: 0 + mMiscParamsSetting: + mFinalColorMultiplier: {r: 1, g: 1, b: 1, a: 1} + mRenderDepthNormal: 0 + mFinalColorIntensity: 1 + mCharacterValueMultiplier: 1 + mCharacterSaturateMultiplier: 1 + mGlobalMainDirectionalLightMultiplier: 1 + mOverridedLightUpDownAngle: 0 + mOverridedLightLRAngle: 0 + mOverrideLightDirectionIntensity: 0 + mSpecularIntensity: 1 + mSpecularColor: {r: 1, g: 1, b: 1, a: 1} + mUseMainLightDirForSpecular: 1 + mIndirecLightMinColor: {r: 0.01, g: 0.01, b: 0.01, a: 1} + mIndirecLightMultiplier: 1 + mOverridedRimLightUpDownAngle: 0 + mOverridedRimLightLRAngle: 0 + mOverrideRimLightDirectionIntensity: 0 + mGlobalRimLightTintColor: {r: 1, g: 1, b: 1, a: 1} + mGlobalRimLightMultipiler: 1 + mRimLightStartFadeIn: 1 + mRimLightStartFadeOut: 50 + mRimLightAndShadowWidthMultiplier: 1 + mRimLightDepthDiffThresholdOffset: 0.5 + mAddLightMultipiler: {r: 1, g: 1, b: 1, a: 0.5} + mAddLightMaxContribution: {r: 1, g: 1, b: 1, a: 1} + mShadowColor: {r: 0, g: 0, b: 0, a: 0.5} + mShadowAngle: 70 + mShadowLength: 1 + mShadowHeight: 0.1 +--- !u!114 &5744085369761597830 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -929177382, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: SceneRenderFeature + m_EditorClassIdentifier: + m_Active: 1 + SSRComputeShader: {fileID: 7200000, guid: cf8964bc444045b4c830d86205bf1838, type: 3} + Settings: + SceneParameters: + CopyColor: 0 + ShadowColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + BakedShadowStrength: 1 + GlobalBrightness: 1 + SceneDebug: 0 + NormalDebug: 0 + VertexColorDebug: 0 + DebugCustomValue: + FogParameters: + OpenFog: 1 + LineFogColor: {r: 0.5, g: 0, b: 0, a: 1} + LineFogStartDistance: 10 + LineFogEndDistance: 100 + LineFogStrength: 0 + HeightFogColor: {r: 0.5, g: 0, b: 0, a: 1} + HeightFogStartHeight: 0 + HeightFogFalloff: 0 + HeightFogDensity: 0 + HeightFogStartDistance: 0 + HeightFogMinOpacity: 0 + FogAmbient: 0 diff --git a/AIClient/Assets/Settings/URP/ForwardRenderer 0VeryLowQuality.asset.meta b/AIClient/Assets/Settings/URP/ForwardRenderer 0VeryLowQuality.asset.meta new file mode 100644 index 0000000..e35619e --- /dev/null +++ b/AIClient/Assets/Settings/URP/ForwardRenderer 0VeryLowQuality.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 39a007eb403d850479271fda4ed87835 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/Settings/URP/ForwardRenderer 1LowQuality.asset b/AIClient/Assets/Settings/URP/ForwardRenderer 1LowQuality.asset new file mode 100644 index 0000000..7b6dcaa --- /dev/null +++ b/AIClient/Assets/Settings/URP/ForwardRenderer 1LowQuality.asset @@ -0,0 +1,386 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-8140000362427506868 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1749369493, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: EffectRenderFeature + m_EditorClassIdentifier: + m_Active: 1 + RenderTargetName: _ScreenColorTexture + SamplingShader: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3} + BlitShader: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3} + UberEffectPostShader: {fileID: 4800000, guid: 0f60273b12723a047a568dca50178e02, type: 3} + UberEffectPostMaterial: {fileID: 0} + RenderTargetSampling: 0 + UberEffectPostShaderName: Engine/Effect/UberEffectPost +--- !u!114 &-7290361237560686537 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1181071007, guid: 58d7e77cafa53d146af19f551ff0a3f7, type: 3} + m_Name: NiloToonCharacterRendererFeature + m_EditorClassIdentifier: + m_Active: 1 + mCharacterRenderSetting: + mOutlineSetting: + ShouldRenderOutline: 1 + UseBigSceneOutline: 0 + BigSceneOutlineAtten: 250 + outlineWidthMultiplier: 1 + outlineTintColor: {r: 1, g: 1, b: 1, a: 1} + outlineWidthAutoAdjustToCameraDistanceAndFOV: 1 + mSelfShadowSetting: + mEnableSelfShadow: 1 + mShadowUDAngle: 20 + mShadowLRAngle: 0 + mShadowMapSize: 2048 + mMaxShadowDistance: 100 + mShadowDepthBias: 1 + mUseNDotLFix: 1 + mPerfectCullingForShadowCasters: 1 + mDebugShadowCameraVisibleBox: 0 + mMiscParamsSetting: + mFinalColorMultiplier: {r: 1, g: 1, b: 1, a: 1} + mRenderDepthNormal: 1 + mFinalColorIntensity: 1 + mCharacterValueMultiplier: 1 + mCharacterSaturateMultiplier: 1 + mGlobalMainDirectionalLightMultiplier: 0.72 + mOverridedLightUpDownAngle: -30 + mOverridedLightLRAngle: -20 + mOverrideLightDirectionIntensity: 1 + mSpecularIntensity: 1.2 + mSpecularColor: {r: 1, g: 1, b: 1, a: 1} + mUseMainLightDirForSpecular: 1 + mIndirecLightMinColor: {r: 0.01, g: 0.01, b: 0.01, a: 1} + mIndirecLightMultiplier: 1 + mOverridedRimLightUpDownAngle: 4 + mOverridedRimLightLRAngle: 47 + mOverrideRimLightDirectionIntensity: 1 + mGlobalRimLightTintColor: {r: 1, g: 0.6084906, b: 0.68266994, a: 1} + mGlobalRimLightMultipiler: 8.3 + mRimLightStartFadeIn: 1 + mRimLightStartFadeOut: 50 + mRimLightAndShadowWidthMultiplier: 1 + mRimLightDepthDiffThresholdOffset: 0.5 + mAddLightMultipiler: {r: 1, g: 1, b: 1, a: 0.5} + mAddLightMaxContribution: {r: 1, g: 1, b: 1, a: 1} + mShadowColor: {r: 0, g: 0, b: 0, a: 0.5} + mShadowAngle: 70 + mShadowLength: 1 + mShadowHeight: 0.1 +--- !u!114 &-5507381615842164399 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 88650573, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: CharacterRenderFeature + m_EditorClassIdentifier: + m_Active: 1 +--- !u!114 &-1672808413483951387 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1749369493, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: EffectRenderFeature + m_EditorClassIdentifier: + m_Active: 1 + RenderTargetName: _ScreenColorTexture + SamplingShader: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3} + BlitShader: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3} + UberEffectPostShader: {fileID: 4800000, guid: 0f60273b12723a047a568dca50178e02, type: 3} + UberEffectPostMaterial: {fileID: 0} + RenderTargetSampling: 0 + UberEffectPostShaderName: Engine/Effect/UberEffectPost +--- !u!114 &-1190632597373315364 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -929177382, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: SceneRenderFeature + m_EditorClassIdentifier: + m_Active: 1 + SSRComputeShader: {fileID: 7200000, guid: cf8964bc444045b4c830d86205bf1838, type: 3} + Settings: + SceneParameters: + CopyColor: 0 + ShadowColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + BakedShadowStrength: 1 + GlobalBrightness: 1 + SceneDebug: 0 + NormalDebug: 0 + VertexColorDebug: 0 + DebugCustomValue: + FogParameters: + OpenFog: 1 + LineFogColor: {r: 0.5, g: 0, b: 0, a: 1} + LineFogStartDistance: 10 + LineFogEndDistance: 100 + LineFogStrength: 0 + HeightFogColor: {r: 0.5, g: 0, b: 0, a: 1} + HeightFogStartHeight: 0 + HeightFogFalloff: 0 + HeightFogDensity: 0 + HeightFogStartDistance: 0 + HeightFogMinOpacity: 0 + FogAmbient: 0 +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: de640fe3d0db1804a85f9fc8f5cadab6, type: 3} + m_Name: ForwardRenderer 1LowQuality + m_EditorClassIdentifier: + debugShaders: + debugReplacementPS: {fileID: 4800000, guid: cf852408f2e174538bcd9b7fda1c5ae7, type: 3} + hdrDebugViewPS: {fileID: 4800000, guid: 573620ae32aec764abd4d728906d2587, type: 3} + m_RendererFeatures: [] + m_RendererFeatureMap: + m_UseNativeRenderPass: 0 + postProcessData: {fileID: 0} + xrSystemData: {fileID: 11400000, guid: 60e1133243b97e347b653163a8c01b64, type: 2} + shaders: + blitPS: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3} + copyDepthPS: {fileID: 4800000, guid: d6dae50ee9e1bfa4db75f19f99355220, type: 3} + screenSpaceShadowPS: {fileID: 4800000, guid: 0f854b35a0cf61a429bd5dcfea30eddd, type: 3} + samplingPS: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3} + stencilDeferredPS: {fileID: 4800000, guid: e9155b26e1bc55942a41e518703fe304, type: 3} + fallbackErrorPS: {fileID: 4800000, guid: e6e9a19c3678ded42a3bc431ebef7dbd, type: 3} + fallbackLoadingPS: {fileID: 4800000, guid: 7f888aff2ac86494babad1c2c5daeee2, type: 3} + materialErrorPS: {fileID: 4800000, guid: 5fd9a8feb75a4b5894c241777f519d4e, type: 3} + coreBlitPS: {fileID: 4800000, guid: 93446b5c5339d4f00b85c159e1159b7c, type: 3} + coreBlitColorAndDepthPS: {fileID: 4800000, guid: d104b2fc1ca6445babb8e90b0758136b, type: 3} + blitHDROverlay: {fileID: 4800000, guid: a89bee29cffa951418fc1e2da94d1959, type: 3} + cameraMotionVector: {fileID: 4800000, guid: c56b7e0d4c7cb484e959caeeedae9bbf, type: 3} + objectMotionVector: {fileID: 4800000, guid: 7b3ede40266cd49a395def176e1bc486, type: 3} + dataDrivenLensFlare: {fileID: 4800000, guid: 6cda457ac28612740adb23da5d39ea92, type: 3} + terrainDetailLitPS: {fileID: 4800000, guid: f6783ab646d374f94b199774402a5144, type: 3} + terrainDetailGrassPS: {fileID: 4800000, guid: e507fdfead5ca47e8b9a768b51c291a1, type: 3} + terrainDetailGrassBillboardPS: {fileID: 4800000, guid: 29868e73b638e48ca99a19ea58c48d90, type: 3} + m_AssetVersion: 2 + m_OpaqueLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_TransparentLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_DefaultStencilState: + overrideStencilState: 0 + stencilReference: 0 + stencilCompareFunction: 8 + passOperation: 2 + failOperation: 0 + zFailOperation: 0 + m_ShadowTransparentReceive: 0 + m_RenderingMode: 0 + m_DepthPrimingMode: 0 + m_CopyDepthMode: 0 + m_AccurateGbufferNormals: 0 + m_IntermediateTextureMode: 1 +--- !u!114 &1558999346734371754 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1741494071, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: GlobalScanFeature + m_EditorClassIdentifier: + m_Active: 1 + settings: + scanMaterial: {fileID: 2100000, guid: d67115296155f3c41ab11dbf400eaadf, type: 2} + renderPassEvent: 500 +--- !u!114 &1682763883357394284 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1137749194, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: OutlineFeature + m_EditorClassIdentifier: + m_Active: 1 + settings: + profilerTag: Selection Outline + targetLayer: + serializedVersion: 2 + m_Bits: 2048 + outlineMaterial: {fileID: 2100000, guid: 19d53d4eaf4ccbf479c715921ed8d533, type: 2} + outlineColor: {r: 1, g: 1, b: 1, a: 1} + outlineWidth: 1.5 + renderPassEvent: 550 +--- !u!114 &3537890718694377718 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a5c14bbf9359ff549afb7ea0f09037df, type: 3} + m_Name: NiloToonCharacterRendererFeature + m_EditorClassIdentifier: + m_Active: 1 + mCharacterRenderSetting: + mOutlineSetting: + ShouldRenderOutline: 1 + UseBigSceneOutline: 0 + BigSceneOutlineAtten: 250 + outlineWidthMultiplier: 1 + outlineTintColor: {r: 1, g: 1, b: 1, a: 1} + outlineWidthAutoAdjustToCameraDistanceAndFOV: 1 + mSelfShadowSetting: + mEnableSelfShadow: 1 + mShadowUDAngle: 30 + mShadowLRAngle: 0 + mShadowMapSize: 512 + mMaxShadowDistance: 50 + mShadowDepthBias: 1 + mUseNDotLFix: 1 + mPerfectCullingForShadowCasters: 0 + mDebugShadowCameraVisibleBox: 0 + mMiscParamsSetting: + mFinalColorMultiplier: {r: 1, g: 1, b: 1, a: 1} + mRenderDepthNormal: 0 + mFinalColorIntensity: 1 + mCharacterValueMultiplier: 1 + mCharacterSaturateMultiplier: 1 + mGlobalMainDirectionalLightMultiplier: 1 + mOverridedLightUpDownAngle: 0 + mOverridedLightLRAngle: 0 + mOverrideLightDirectionIntensity: 0 + mSpecularIntensity: 1 + mSpecularColor: {r: 1, g: 1, b: 1, a: 1} + mUseMainLightDirForSpecular: 1 + mIndirecLightMinColor: {r: 0.01, g: 0.01, b: 0.01, a: 1} + mIndirecLightMultiplier: 1 + mOverridedRimLightUpDownAngle: 0 + mOverridedRimLightLRAngle: 0 + mOverrideRimLightDirectionIntensity: 0 + mGlobalRimLightTintColor: {r: 1, g: 1, b: 1, a: 1} + mGlobalRimLightMultipiler: 1 + mRimLightStartFadeIn: 1 + mRimLightStartFadeOut: 50 + mRimLightAndShadowWidthMultiplier: 1 + mRimLightDepthDiffThresholdOffset: 0.5 + mAddLightMultipiler: {r: 1, g: 1, b: 1, a: 0.5} + mAddLightMaxContribution: {r: 1, g: 1, b: 1, a: 1} + mShadowColor: {r: 0, g: 0, b: 0, a: 0.5} + mShadowAngle: 70 + mShadowLength: 1 + mShadowHeight: 0.1 +--- !u!114 &3542269519574187309 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1467291068, guid: 58d7e77cafa53d146af19f551ff0a3f7, type: 3} + m_Name: EffectRenderFeature + m_EditorClassIdentifier: + m_Active: 1 + RenderTargetName: _ScreenColorTexture + SamplingShader: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3} + BlitShader: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3} + UberEffectPostShader: {fileID: 4800000, guid: e4dc0f5e3a376594b807a6e398748f7b, type: 3} + UberEffectPostMaterial: {fileID: 0} + RenderTargetSampling: 1 + UberEffectPostShaderName: GYGame/Effect/UberEffectPost +--- !u!114 &7530585995642756810 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 09d572d36a83daa4bb576ae814b31f16, type: 3} + m_Name: TAA + m_EditorClassIdentifier: + m_Active: 1 + PreviewInSceneView: 0 + UseMotionVector: 0 + RenderingMode: 0 + WorkOnPrepass: 0 + IgonreTransparentObject: 1 + Use32Bit: 0 + Shader: {fileID: 4800000, guid: 8c0d9373e5d33404ba27de953fd7a309, type: 3} +--- !u!114 &7600997400158244659 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1608182031, guid: 58d7e77cafa53d146af19f551ff0a3f7, type: 3} + m_Name: SceneRenderFeature + m_EditorClassIdentifier: + m_Active: 1 + Settings: + SceneParameters: + CopyColor: 0 + ShadowColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + BakedShadowStrength: 1 + GlobalBrightness: 1 + SceneDebug: 0 + NormalDebug: 0 + VertexColorDebug: 0 + DebugCustomValue: + FogParameters: + OpenFog: 1 + LineFogColor: {r: 0.5, g: 0, b: 0, a: 1} + LineFogStartDistance: 10 + LineFogEndDistance: 100 + LineFogStrength: 0 + HeightFogColor: {r: 0.5, g: 0, b: 0, a: 1} + HeightFogStartHeight: 0 + HeightFogFalloff: 0 + HeightFogDensity: 0 + HeightFogStartDistance: 0 + HeightFogMinOpacity: 0 + FogAmbient: 0 diff --git a/AIClient/Assets/Settings/URP/ForwardRenderer 1LowQuality.asset.meta b/AIClient/Assets/Settings/URP/ForwardRenderer 1LowQuality.asset.meta new file mode 100644 index 0000000..7a2d5eb --- /dev/null +++ b/AIClient/Assets/Settings/URP/ForwardRenderer 1LowQuality.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ab43e90c602bfdb4e97e042f15d35169 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/Settings/URP/ForwardRenderer 2MediumQuality.asset b/AIClient/Assets/Settings/URP/ForwardRenderer 2MediumQuality.asset new file mode 100644 index 0000000..2288a51 --- /dev/null +++ b/AIClient/Assets/Settings/URP/ForwardRenderer 2MediumQuality.asset @@ -0,0 +1,386 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-7718913652599309650 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -929177382, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: SceneRenderFeature + m_EditorClassIdentifier: + m_Active: 1 + SSRComputeShader: {fileID: 7200000, guid: cf8964bc444045b4c830d86205bf1838, type: 3} + Settings: + SceneParameters: + CopyColor: 0 + ShadowColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + BakedShadowStrength: 1 + GlobalBrightness: 1 + SceneDebug: 0 + NormalDebug: 0 + VertexColorDebug: 0 + DebugCustomValue: + FogParameters: + OpenFog: 1 + LineFogColor: {r: 0.5, g: 0, b: 0, a: 1} + LineFogStartDistance: 10 + LineFogEndDistance: 100 + LineFogStrength: 0 + HeightFogColor: {r: 0.5, g: 0, b: 0, a: 1} + HeightFogStartHeight: 0 + HeightFogFalloff: 0 + HeightFogDensity: 0 + HeightFogStartDistance: 0 + HeightFogMinOpacity: 0 + FogAmbient: 0 +--- !u!114 &-6991330952846024812 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1181071007, guid: 58d7e77cafa53d146af19f551ff0a3f7, type: 3} + m_Name: NiloToonCharacterRendererFeature + m_EditorClassIdentifier: + m_Active: 1 + mCharacterRenderSetting: + mOutlineSetting: + ShouldRenderOutline: 1 + UseBigSceneOutline: 0 + BigSceneOutlineAtten: 250 + outlineWidthMultiplier: 4 + outlineTintColor: {r: 1, g: 1, b: 1, a: 1} + outlineWidthAutoAdjustToCameraDistanceAndFOV: 1 + mSelfShadowSetting: + mEnableSelfShadow: 0 + mShadowUDAngle: 20 + mShadowLRAngle: 1.4 + mShadowMapSize: 2048 + mMaxShadowDistance: 100 + mShadowDepthBias: 0.78 + mUseNDotLFix: 1 + mPerfectCullingForShadowCasters: 0 + mDebugShadowCameraVisibleBox: 0 + mMiscParamsSetting: + mFinalColorMultiplier: {r: 1, g: 1, b: 1, a: 1} + mRenderDepthNormal: 1 + mFinalColorIntensity: 1 + mCharacterValueMultiplier: 1 + mCharacterSaturateMultiplier: 0.2 + mGlobalMainDirectionalLightMultiplier: 0.7 + mOverridedLightUpDownAngle: -30 + mOverridedLightLRAngle: 30 + mOverrideLightDirectionIntensity: 1 + mSpecularIntensity: 1 + mSpecularColor: {r: 1, g: 1, b: 1, a: 1} + mUseMainLightDirForSpecular: 1 + mIndirecLightMinColor: {r: 0.01, g: 0.01, b: 0.01, a: 1} + mIndirecLightMultiplier: 1 + mOverridedRimLightUpDownAngle: 180 + mOverridedRimLightLRAngle: -66 + mOverrideRimLightDirectionIntensity: 1 + mGlobalRimLightTintColor: {r: 1, g: 1, b: 1, a: 1} + mGlobalRimLightMultipiler: 4 + mRimLightStartFadeIn: 0 + mRimLightStartFadeOut: 100 + mRimLightAndShadowWidthMultiplier: 2 + mRimLightDepthDiffThresholdOffset: 0.5 + mAddLightMultipiler: {r: 1, g: 1, b: 1, a: 0.5} + mAddLightMaxContribution: {r: 1, g: 1, b: 1, a: 1} + mShadowColor: {r: 0, g: 0, b: 0, a: 0.5} + mShadowAngle: 311 + mShadowLength: 0.89 + mShadowHeight: 0.1 +--- !u!114 &-5455261652415300069 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1467291068, guid: 58d7e77cafa53d146af19f551ff0a3f7, type: 3} + m_Name: EffectRenderFeature + m_EditorClassIdentifier: + m_Active: 1 + RenderTargetName: _ScreenColorTexture + SamplingShader: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3} + BlitShader: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3} + UberEffectPostShader: {fileID: 4800000, guid: e4dc0f5e3a376594b807a6e398748f7b, type: 3} + UberEffectPostMaterial: {fileID: 0} + RenderTargetSampling: 1 + UberEffectPostShaderName: GYGame/Effect/UberEffectPost +--- !u!114 &-2003660147899227534 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1741494071, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: GlobalScanFeature + m_EditorClassIdentifier: + m_Active: 1 + settings: + scanMaterial: {fileID: 2100000, guid: d67115296155f3c41ab11dbf400eaadf, type: 2} + renderPassEvent: 500 +--- !u!114 &-847716761063671179 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 88650573, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: CharacterRenderFeature + m_EditorClassIdentifier: + m_Active: 1 +--- !u!114 &-490646824858370943 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1749369493, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: EffectRenderFeature + m_EditorClassIdentifier: + m_Active: 1 + RenderTargetName: _ScreenColorTexture + SamplingShader: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3} + BlitShader: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3} + UberEffectPostShader: {fileID: 4800000, guid: 0f60273b12723a047a568dca50178e02, type: 3} + UberEffectPostMaterial: {fileID: 0} + RenderTargetSampling: 0 + UberEffectPostShaderName: Engine/Effect/UberEffectPost +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: de640fe3d0db1804a85f9fc8f5cadab6, type: 3} + m_Name: ForwardRenderer 2MediumQuality + m_EditorClassIdentifier: + debugShaders: + debugReplacementPS: {fileID: 4800000, guid: cf852408f2e174538bcd9b7fda1c5ae7, type: 3} + hdrDebugViewPS: {fileID: 4800000, guid: 573620ae32aec764abd4d728906d2587, type: 3} + m_RendererFeatures: [] + m_RendererFeatureMap: + m_UseNativeRenderPass: 0 + postProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2} + xrSystemData: {fileID: 11400000, guid: 60e1133243b97e347b653163a8c01b64, type: 2} + shaders: + blitPS: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3} + copyDepthPS: {fileID: 4800000, guid: d6dae50ee9e1bfa4db75f19f99355220, type: 3} + screenSpaceShadowPS: {fileID: 4800000, guid: 0f854b35a0cf61a429bd5dcfea30eddd, type: 3} + samplingPS: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3} + stencilDeferredPS: {fileID: 4800000, guid: e9155b26e1bc55942a41e518703fe304, type: 3} + fallbackErrorPS: {fileID: 4800000, guid: e6e9a19c3678ded42a3bc431ebef7dbd, type: 3} + fallbackLoadingPS: {fileID: 4800000, guid: 7f888aff2ac86494babad1c2c5daeee2, type: 3} + materialErrorPS: {fileID: 4800000, guid: 5fd9a8feb75a4b5894c241777f519d4e, type: 3} + coreBlitPS: {fileID: 4800000, guid: 93446b5c5339d4f00b85c159e1159b7c, type: 3} + coreBlitColorAndDepthPS: {fileID: 4800000, guid: d104b2fc1ca6445babb8e90b0758136b, type: 3} + blitHDROverlay: {fileID: 4800000, guid: a89bee29cffa951418fc1e2da94d1959, type: 3} + cameraMotionVector: {fileID: 4800000, guid: c56b7e0d4c7cb484e959caeeedae9bbf, type: 3} + objectMotionVector: {fileID: 4800000, guid: 7b3ede40266cd49a395def176e1bc486, type: 3} + dataDrivenLensFlare: {fileID: 4800000, guid: 6cda457ac28612740adb23da5d39ea92, type: 3} + terrainDetailLitPS: {fileID: 4800000, guid: f6783ab646d374f94b199774402a5144, type: 3} + terrainDetailGrassPS: {fileID: 4800000, guid: e507fdfead5ca47e8b9a768b51c291a1, type: 3} + terrainDetailGrassBillboardPS: {fileID: 4800000, guid: 29868e73b638e48ca99a19ea58c48d90, type: 3} + m_AssetVersion: 2 + m_OpaqueLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_TransparentLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_DefaultStencilState: + overrideStencilState: 0 + stencilReference: 0 + stencilCompareFunction: 8 + passOperation: 2 + failOperation: 0 + zFailOperation: 0 + m_ShadowTransparentReceive: 1 + m_RenderingMode: 0 + m_DepthPrimingMode: 0 + m_CopyDepthMode: 0 + m_AccurateGbufferNormals: 0 + m_IntermediateTextureMode: 1 +--- !u!114 &5699326553694581020 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1137749194, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: OutlineFeature + m_EditorClassIdentifier: + m_Active: 1 + settings: + profilerTag: Selection Outline + targetLayer: + serializedVersion: 2 + m_Bits: 2048 + outlineMaterial: {fileID: 2100000, guid: 19d53d4eaf4ccbf479c715921ed8d533, type: 2} + outlineColor: {r: 1, g: 1, b: 1, a: 1} + outlineWidth: 1.5 + renderPassEvent: 550 +--- !u!114 &6943902112415961173 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1749369493, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: EffectRenderFeature + m_EditorClassIdentifier: + m_Active: 1 + RenderTargetName: _ScreenColorTexture + SamplingShader: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3} + BlitShader: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3} + UberEffectPostShader: {fileID: 4800000, guid: 0f60273b12723a047a568dca50178e02, type: 3} + UberEffectPostMaterial: {fileID: 0} + RenderTargetSampling: 0 + UberEffectPostShaderName: Engine/Effect/UberEffectPost +--- !u!114 &7161363195401994471 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a5c14bbf9359ff549afb7ea0f09037df, type: 3} + m_Name: NiloToonCharacterRendererFeature + m_EditorClassIdentifier: + m_Active: 1 + mCharacterRenderSetting: + mOutlineSetting: + ShouldRenderOutline: 1 + UseBigSceneOutline: 0 + BigSceneOutlineAtten: 250 + outlineWidthMultiplier: 1 + outlineTintColor: {r: 1, g: 1, b: 1, a: 1} + outlineWidthAutoAdjustToCameraDistanceAndFOV: 1 + mSelfShadowSetting: + mEnableSelfShadow: 1 + mShadowUDAngle: 30 + mShadowLRAngle: 0 + mShadowMapSize: 512 + mMaxShadowDistance: 50 + mShadowDepthBias: 1 + mUseNDotLFix: 1 + mPerfectCullingForShadowCasters: 0 + mDebugShadowCameraVisibleBox: 0 + mMiscParamsSetting: + mFinalColorMultiplier: {r: 1, g: 1, b: 1, a: 1} + mRenderDepthNormal: 0 + mFinalColorIntensity: 1 + mCharacterValueMultiplier: 1 + mCharacterSaturateMultiplier: 1 + mGlobalMainDirectionalLightMultiplier: 1 + mOverridedLightUpDownAngle: 0 + mOverridedLightLRAngle: 0 + mOverrideLightDirectionIntensity: 0 + mSpecularIntensity: 1 + mSpecularColor: {r: 1, g: 1, b: 1, a: 1} + mUseMainLightDirForSpecular: 1 + mIndirecLightMinColor: {r: 0.01, g: 0.01, b: 0.01, a: 1} + mIndirecLightMultiplier: 1 + mOverridedRimLightUpDownAngle: 0 + mOverridedRimLightLRAngle: 0 + mOverrideRimLightDirectionIntensity: 0 + mGlobalRimLightTintColor: {r: 1, g: 1, b: 1, a: 1} + mGlobalRimLightMultipiler: 1 + mRimLightStartFadeIn: 1 + mRimLightStartFadeOut: 50 + mRimLightAndShadowWidthMultiplier: 1 + mRimLightDepthDiffThresholdOffset: 0.5 + mAddLightMultipiler: {r: 1, g: 1, b: 1, a: 0.5} + mAddLightMaxContribution: {r: 1, g: 1, b: 1, a: 1} + mShadowColor: {r: 0, g: 0, b: 0, a: 0.5} + mShadowAngle: 70 + mShadowLength: 1 + mShadowHeight: 0.1 +--- !u!114 &8305250864628069769 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1608182031, guid: 58d7e77cafa53d146af19f551ff0a3f7, type: 3} + m_Name: SceneRenderFeature + m_EditorClassIdentifier: + m_Active: 1 + Settings: + SceneParameters: + CopyColor: 1 + ShadowColor: {r: 0.38492838, g: 0.3236027, b: 0.6792453, a: 1} + BakedShadowStrength: 0.807 + GlobalBrightness: 1 + SceneDebug: 0 + NormalDebug: 0 + VertexColorDebug: 0 + DebugCustomValue: + FogParameters: + OpenFog: 1 + LineFogColor: {r: 0.9811321, g: 0.8294182, b: 0.5784977, a: 1} + LineFogStartDistance: 77.46 + LineFogEndDistance: 144.2 + LineFogStrength: 0.846 + HeightFogColor: {r: 0.12116811, g: 0.56545126, b: 0.65199995, a: 1} + HeightFogStartHeight: -2.77 + HeightFogFalloff: 1.974 + HeightFogDensity: 0.0116 + HeightFogStartDistance: 55.1 + HeightFogMinOpacity: 1 + FogAmbient: 1 +--- !u!114 &8504462900099931217 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 09d572d36a83daa4bb576ae814b31f16, type: 3} + m_Name: TAA + m_EditorClassIdentifier: + m_Active: 1 + PreviewInSceneView: 0 + UseMotionVector: 0 + RenderingMode: 0 + WorkOnPrepass: 0 + IgonreTransparentObject: 1 + Use32Bit: 0 + Shader: {fileID: 4800000, guid: 8c0d9373e5d33404ba27de953fd7a309, type: 3} diff --git a/AIClient/Assets/Settings/URP/ForwardRenderer 2MediumQuality.asset.meta b/AIClient/Assets/Settings/URP/ForwardRenderer 2MediumQuality.asset.meta new file mode 100644 index 0000000..983345e --- /dev/null +++ b/AIClient/Assets/Settings/URP/ForwardRenderer 2MediumQuality.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f454285041681a44999cc258865df961 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/Settings/URP/ForwardRenderer 3HighQuality.asset b/AIClient/Assets/Settings/URP/ForwardRenderer 3HighQuality.asset new file mode 100644 index 0000000..a468a9e --- /dev/null +++ b/AIClient/Assets/Settings/URP/ForwardRenderer 3HighQuality.asset @@ -0,0 +1,386 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-7801194434031207102 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1181071007, guid: 58d7e77cafa53d146af19f551ff0a3f7, type: 3} + m_Name: NiloToonCharacterRendererFeature + m_EditorClassIdentifier: + m_Active: 1 + mCharacterRenderSetting: + mOutlineSetting: + ShouldRenderOutline: 1 + UseBigSceneOutline: 0 + BigSceneOutlineAtten: 250 + outlineWidthMultiplier: 1 + outlineTintColor: {r: 1, g: 1, b: 1, a: 1} + outlineWidthAutoAdjustToCameraDistanceAndFOV: 1 + mSelfShadowSetting: + mEnableSelfShadow: 1 + mShadowUDAngle: 0 + mShadowLRAngle: 0 + mShadowMapSize: 512 + mMaxShadowDistance: 50 + mShadowDepthBias: 1 + mUseNDotLFix: 1 + mPerfectCullingForShadowCasters: 1 + mDebugShadowCameraVisibleBox: 0 + mMiscParamsSetting: + mFinalColorMultiplier: {r: 1, g: 1, b: 1, a: 1} + mRenderDepthNormal: 1 + mFinalColorIntensity: 1 + mCharacterValueMultiplier: 1 + mCharacterSaturateMultiplier: 1 + mGlobalMainDirectionalLightMultiplier: 1 + mOverridedLightUpDownAngle: 0 + mOverridedLightLRAngle: 0 + mOverrideLightDirectionIntensity: 0 + mSpecularIntensity: 1 + mSpecularColor: {r: 1, g: 1, b: 1, a: 1} + mUseMainLightDirForSpecular: 1 + mIndirecLightMinColor: {r: 0.01, g: 0.01, b: 0.01, a: 1} + mIndirecLightMultiplier: 1 + mOverridedRimLightUpDownAngle: -93 + mOverridedRimLightLRAngle: -66 + mOverrideRimLightDirectionIntensity: 1 + mGlobalRimLightTintColor: {r: 1, g: 1, b: 1, a: 1} + mGlobalRimLightMultipiler: 1 + mRimLightStartFadeIn: 1 + mRimLightStartFadeOut: 50 + mRimLightAndShadowWidthMultiplier: 1 + mRimLightDepthDiffThresholdOffset: 0.5 + mAddLightMultipiler: {r: 1, g: 1, b: 1, a: 0.5} + mAddLightMaxContribution: {r: 1, g: 1, b: 1, a: 1} + mShadowColor: {r: 0, g: 0, b: 0, a: 0.5} + mShadowAngle: 70 + mShadowLength: 1 + mShadowHeight: 0.1 +--- !u!114 &-6694115839964173624 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1137749194, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: OutlineFeature + m_EditorClassIdentifier: + m_Active: 1 + settings: + profilerTag: Selection Outline + targetLayer: + serializedVersion: 2 + m_Bits: 2048 + outlineMaterial: {fileID: 2100000, guid: 19d53d4eaf4ccbf479c715921ed8d533, type: 2} + outlineColor: {r: 1, g: 1, b: 1, a: 1} + outlineWidth: 1.5 + renderPassEvent: 550 +--- !u!114 &-4899579376300271201 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1741494071, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: GlobalScanFeature + m_EditorClassIdentifier: + m_Active: 1 + settings: + scanMaterial: {fileID: 2100000, guid: d67115296155f3c41ab11dbf400eaadf, type: 2} + renderPassEvent: 500 +--- !u!114 &-3248482767401251789 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1749369493, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: EffectRenderFeature + m_EditorClassIdentifier: + m_Active: 1 + RenderTargetName: _ScreenColorTexture + SamplingShader: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3} + BlitShader: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3} + UberEffectPostShader: {fileID: 4800000, guid: 0f60273b12723a047a568dca50178e02, type: 3} + UberEffectPostMaterial: {fileID: 0} + RenderTargetSampling: 0 + UberEffectPostShaderName: Engine/Effect/UberEffectPost +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: de640fe3d0db1804a85f9fc8f5cadab6, type: 3} + m_Name: ForwardRenderer 3HighQuality + m_EditorClassIdentifier: + debugShaders: + debugReplacementPS: {fileID: 4800000, guid: cf852408f2e174538bcd9b7fda1c5ae7, type: 3} + hdrDebugViewPS: {fileID: 4800000, guid: 573620ae32aec764abd4d728906d2587, type: 3} + m_RendererFeatures: [] + m_RendererFeatureMap: + m_UseNativeRenderPass: 0 + postProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2} + xrSystemData: {fileID: 11400000, guid: 60e1133243b97e347b653163a8c01b64, type: 2} + shaders: + blitPS: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3} + copyDepthPS: {fileID: 4800000, guid: d6dae50ee9e1bfa4db75f19f99355220, type: 3} + screenSpaceShadowPS: {fileID: 4800000, guid: 0f854b35a0cf61a429bd5dcfea30eddd, type: 3} + samplingPS: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3} + stencilDeferredPS: {fileID: 4800000, guid: e9155b26e1bc55942a41e518703fe304, type: 3} + fallbackErrorPS: {fileID: 4800000, guid: e6e9a19c3678ded42a3bc431ebef7dbd, type: 3} + fallbackLoadingPS: {fileID: 4800000, guid: 7f888aff2ac86494babad1c2c5daeee2, type: 3} + materialErrorPS: {fileID: 4800000, guid: 5fd9a8feb75a4b5894c241777f519d4e, type: 3} + coreBlitPS: {fileID: 4800000, guid: 93446b5c5339d4f00b85c159e1159b7c, type: 3} + coreBlitColorAndDepthPS: {fileID: 4800000, guid: d104b2fc1ca6445babb8e90b0758136b, type: 3} + blitHDROverlay: {fileID: 4800000, guid: a89bee29cffa951418fc1e2da94d1959, type: 3} + cameraMotionVector: {fileID: 4800000, guid: c56b7e0d4c7cb484e959caeeedae9bbf, type: 3} + objectMotionVector: {fileID: 4800000, guid: 7b3ede40266cd49a395def176e1bc486, type: 3} + dataDrivenLensFlare: {fileID: 4800000, guid: 6cda457ac28612740adb23da5d39ea92, type: 3} + terrainDetailLitPS: {fileID: 4800000, guid: f6783ab646d374f94b199774402a5144, type: 3} + terrainDetailGrassPS: {fileID: 4800000, guid: e507fdfead5ca47e8b9a768b51c291a1, type: 3} + terrainDetailGrassBillboardPS: {fileID: 4800000, guid: 29868e73b638e48ca99a19ea58c48d90, type: 3} + m_AssetVersion: 2 + m_OpaqueLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_TransparentLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_DefaultStencilState: + overrideStencilState: 0 + stencilReference: 0 + stencilCompareFunction: 8 + passOperation: 2 + failOperation: 0 + zFailOperation: 0 + m_ShadowTransparentReceive: 1 + m_RenderingMode: 0 + m_DepthPrimingMode: 0 + m_CopyDepthMode: 0 + m_AccurateGbufferNormals: 0 + m_IntermediateTextureMode: 1 +--- !u!114 &2306520689226812427 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1749369493, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: EffectRenderFeature + m_EditorClassIdentifier: + m_Active: 1 + RenderTargetName: _ScreenColorTexture + SamplingShader: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3} + BlitShader: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3} + UberEffectPostShader: {fileID: 4800000, guid: 0f60273b12723a047a568dca50178e02, type: 3} + UberEffectPostMaterial: {fileID: 0} + RenderTargetSampling: 0 + UberEffectPostShaderName: Engine/Effect/UberEffectPost +--- !u!114 &3389092417788614536 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 88650573, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: CharacterRenderFeature + m_EditorClassIdentifier: + m_Active: 1 +--- !u!114 &4194082081604926240 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1467291068, guid: 58d7e77cafa53d146af19f551ff0a3f7, type: 3} + m_Name: EffectRenderFeature + m_EditorClassIdentifier: + m_Active: 1 + RenderTargetName: _ScreenColorTexture + SamplingShader: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3} + BlitShader: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3} + UberEffectPostShader: {fileID: 4800000, guid: e4dc0f5e3a376594b807a6e398748f7b, type: 3} + UberEffectPostMaterial: {fileID: 0} + RenderTargetSampling: 0 + UberEffectPostShaderName: GYGame/Effect/UberEffectPost +--- !u!114 &4324850898653140070 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a5c14bbf9359ff549afb7ea0f09037df, type: 3} + m_Name: NiloToonCharacterRendererFeature + m_EditorClassIdentifier: + m_Active: 1 + mCharacterRenderSetting: + mOutlineSetting: + ShouldRenderOutline: 1 + UseBigSceneOutline: 0 + BigSceneOutlineAtten: 250 + outlineWidthMultiplier: 1 + outlineTintColor: {r: 1, g: 1, b: 1, a: 1} + outlineWidthAutoAdjustToCameraDistanceAndFOV: 1 + mSelfShadowSetting: + mEnableSelfShadow: 1 + mShadowUDAngle: 30 + mShadowLRAngle: 0 + mShadowMapSize: 512 + mMaxShadowDistance: 50 + mShadowDepthBias: 1 + mUseNDotLFix: 1 + mPerfectCullingForShadowCasters: 0 + mDebugShadowCameraVisibleBox: 0 + mMiscParamsSetting: + mFinalColorMultiplier: {r: 1, g: 1, b: 1, a: 1} + mRenderDepthNormal: 0 + mFinalColorIntensity: 1 + mCharacterValueMultiplier: 1 + mCharacterSaturateMultiplier: 1 + mGlobalMainDirectionalLightMultiplier: 1 + mOverridedLightUpDownAngle: 0 + mOverridedLightLRAngle: 0 + mOverrideLightDirectionIntensity: 0 + mSpecularIntensity: 1 + mSpecularColor: {r: 1, g: 1, b: 1, a: 1} + mUseMainLightDirForSpecular: 1 + mIndirecLightMinColor: {r: 0.01, g: 0.01, b: 0.01, a: 1} + mIndirecLightMultiplier: 1 + mOverridedRimLightUpDownAngle: 0 + mOverridedRimLightLRAngle: 0 + mOverrideRimLightDirectionIntensity: 0 + mGlobalRimLightTintColor: {r: 1, g: 1, b: 1, a: 1} + mGlobalRimLightMultipiler: 1 + mRimLightStartFadeIn: 1 + mRimLightStartFadeOut: 50 + mRimLightAndShadowWidthMultiplier: 1 + mRimLightDepthDiffThresholdOffset: 0.5 + mAddLightMultipiler: {r: 1, g: 1, b: 1, a: 0.5} + mAddLightMaxContribution: {r: 1, g: 1, b: 1, a: 1} + mShadowColor: {r: 0, g: 0, b: 0, a: 0.5} + mShadowAngle: 70 + mShadowLength: 1 + mShadowHeight: 0.1 +--- !u!114 &4815503470696360763 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 09d572d36a83daa4bb576ae814b31f16, type: 3} + m_Name: TAA + m_EditorClassIdentifier: + m_Active: 1 + PreviewInSceneView: 0 + UseMotionVector: 0 + RenderingMode: 0 + WorkOnPrepass: 0 + IgonreTransparentObject: 1 + Use32Bit: 0 + Shader: {fileID: 4800000, guid: 8c0d9373e5d33404ba27de953fd7a309, type: 3} +--- !u!114 &7287650270393091027 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1608182031, guid: 58d7e77cafa53d146af19f551ff0a3f7, type: 3} + m_Name: SceneRenderFeature + m_EditorClassIdentifier: + m_Active: 1 + Settings: + SceneParameters: + CopyColor: 0 + ShadowColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + BakedShadowStrength: 1 + GlobalBrightness: 1 + SceneDebug: 0 + NormalDebug: 0 + VertexColorDebug: 0 + DebugCustomValue: + FogParameters: + OpenFog: 1 + LineFogColor: {r: 0.5, g: 0, b: 0, a: 1} + LineFogStartDistance: 10 + LineFogEndDistance: 100 + LineFogStrength: 0 + HeightFogColor: {r: 0.5, g: 0, b: 0, a: 1} + HeightFogStartHeight: 0 + HeightFogFalloff: 0 + HeightFogDensity: 0 + HeightFogStartDistance: 0 + HeightFogMinOpacity: 0 + FogAmbient: 0 +--- !u!114 &8702178449611039958 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -929177382, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: SceneRenderFeature + m_EditorClassIdentifier: + m_Active: 1 + SSRComputeShader: {fileID: 7200000, guid: cf8964bc444045b4c830d86205bf1838, type: 3} + Settings: + SceneParameters: + CopyColor: 0 + ShadowColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + BakedShadowStrength: 1 + GlobalBrightness: 1 + SceneDebug: 0 + NormalDebug: 0 + VertexColorDebug: 0 + DebugCustomValue: + FogParameters: + OpenFog: 1 + LineFogColor: {r: 0.5, g: 0, b: 0, a: 1} + LineFogStartDistance: 10 + LineFogEndDistance: 100 + LineFogStrength: 0 + HeightFogColor: {r: 0.5, g: 0, b: 0, a: 1} + HeightFogStartHeight: 0 + HeightFogFalloff: 0 + HeightFogDensity: 0 + HeightFogStartDistance: 0 + HeightFogMinOpacity: 0 + FogAmbient: 0 diff --git a/AIClient/Assets/Settings/URP/ForwardRenderer 3HighQuality.asset.meta b/AIClient/Assets/Settings/URP/ForwardRenderer 3HighQuality.asset.meta new file mode 100644 index 0000000..4517c7e --- /dev/null +++ b/AIClient/Assets/Settings/URP/ForwardRenderer 3HighQuality.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ad8f6453bdbe88e409d8fd14942f700d +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/Settings/URP/ForwardRenderer 4VeryHighQuality.asset b/AIClient/Assets/Settings/URP/ForwardRenderer 4VeryHighQuality.asset new file mode 100644 index 0000000..ba3c96c --- /dev/null +++ b/AIClient/Assets/Settings/URP/ForwardRenderer 4VeryHighQuality.asset @@ -0,0 +1,575 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &-6867683717461137263 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1137749194, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: OutlineFeature + m_EditorClassIdentifier: + m_Active: 1 + settings: + profilerTag: Selection Outline + targetLayer: + serializedVersion: 2 + m_Bits: 2048 + outlineMaterial: {fileID: 2100000, guid: 19d53d4eaf4ccbf479c715921ed8d533, type: 2} + outlineColor: {r: 1, g: 1, b: 1, a: 1} + outlineWidth: 1.5 + renderPassEvent: 550 +--- !u!114 &-5451962332241528892 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 09d572d36a83daa4bb576ae814b31f16, type: 3} + m_Name: TAA + m_EditorClassIdentifier: + m_Active: 1 + PreviewInSceneView: 0 + UseMotionVector: 0 + RenderingMode: 0 + WorkOnPrepass: 0 + IgonreTransparentObject: 1 + Use32Bit: 0 + Shader: {fileID: 4800000, guid: 8c0d9373e5d33404ba27de953fd7a309, type: 3} +--- !u!114 &-5192553248712847449 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a5c14bbf9359ff549afb7ea0f09037df, type: 3} + m_Name: NiloToonCharacterRendererFeature + m_EditorClassIdentifier: + m_Active: 1 + mCharacterRenderSetting: + mOutlineSetting: + ShouldRenderOutline: 1 + UseBigSceneOutline: 0 + BigSceneOutlineAtten: 250 + outlineWidthMultiplier: 1 + outlineTintColor: {r: 1, g: 1, b: 1, a: 1} + outlineWidthAutoAdjustToCameraDistanceAndFOV: 1 + mSelfShadowSetting: + mEnableSelfShadow: 1 + mShadowUDAngle: 30 + mShadowLRAngle: 0 + mShadowMapSize: 512 + mMaxShadowDistance: 50 + mShadowDepthBias: 1 + mUseNDotLFix: 1 + mPerfectCullingForShadowCasters: 0 + mDebugShadowCameraVisibleBox: 0 + mMiscParamsSetting: + mFinalColorMultiplier: {r: 1, g: 1, b: 1, a: 1} + mRenderDepthNormal: 0 + mFinalColorIntensity: 1 + mCharacterValueMultiplier: 1 + mCharacterSaturateMultiplier: 1 + mGlobalMainDirectionalLightMultiplier: 1 + mOverridedLightUpDownAngle: 0 + mOverridedLightLRAngle: 0 + mOverrideLightDirectionIntensity: 0 + mSpecularIntensity: 1 + mSpecularColor: {r: 1, g: 1, b: 1, a: 1} + mUseMainLightDirForSpecular: 1 + mIndirecLightMinColor: {r: 0.01, g: 0.01, b: 0.01, a: 1} + mIndirecLightMultiplier: 1 + mOverridedRimLightUpDownAngle: 0 + mOverridedRimLightLRAngle: 0 + mOverrideRimLightDirectionIntensity: 0 + mGlobalRimLightTintColor: {r: 1, g: 1, b: 1, a: 1} + mGlobalRimLightMultipiler: 1 + mRimLightStartFadeIn: 1 + mRimLightStartFadeOut: 50 + mRimLightAndShadowWidthMultiplier: 1 + mRimLightDepthDiffThresholdOffset: 0.5 + mAddLightMultipiler: {r: 1, g: 1, b: 1, a: 0.5} + mAddLightMaxContribution: {r: 1, g: 1, b: 1, a: 1} + mShadowColor: {r: 0, g: 0, b: 0, a: 0.5} + mShadowAngle: 70 + mShadowLength: 1 + mShadowHeight: 0.1 +--- !u!114 &-4124891324505445878 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1733187461, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: FogOfWarRendererFeature + m_EditorClassIdentifier: + m_Active: 1 + settings: + material: {fileID: 2100000, guid: 7fbd1a5d99ab35f40b6c59ea18b4d4f6, type: 2} + renderPassEvent: 500 +--- !u!114 &-2417408525049291374 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1918578592, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: UIGrabPassFeature + m_EditorClassIdentifier: + m_Active: 1 + settings: + renderScale: 1 + uiCameraName: CameraUi + blurredMaterial: {fileID: 0} +--- !u!114 &-2278940370034410917 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 770177407, guid: 38d7f5c1b6979824ab378dfa57dcc73e, type: 3} + m_Name: GlobalScanFeature + m_EditorClassIdentifier: + m_Active: 1 + settings: {scanMaterial: {fileID: 2100000, guid: d67115296155f3c41ab11dbf400eaadf, type: 2}, renderPassEvent: 500} +--- !u!114 &-1168925892722199119 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1749369493, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: EffectRenderFeature + m_EditorClassIdentifier: + m_Active: 1 + RenderTargetName: _ScreenColorTexture + SamplingShader: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3} + BlitShader: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3} + UberEffectPostShader: {fileID: 4800000, guid: 0f60273b12723a047a568dca50178e02, type: 3} + UberEffectPostMaterial: {fileID: 0} + RenderTargetSampling: 0 + UberEffectPostShaderName: Engine/Effect/UberEffectPost +--- !u!114 &-448008844506635923 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1729826526, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: AfterTransparentColorAndCloakFeature + m_EditorClassIdentifier: + m_Active: 1 + m_Settings: + afterTransparentColorTextureName: _AfterTransparentColorTex + downsample: 0.5 + skipSceneView: 1 +--- !u!114 &-386890362932611403 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1918578592, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: UIGrabPassFeature + m_EditorClassIdentifier: + m_Active: 1 + settings: + renderScale: 1 + uiCameraName: CameraUi + blurredMaterial: {fileID: 0} +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: de640fe3d0db1804a85f9fc8f5cadab6, type: 3} + m_Name: ForwardRenderer 4VeryHighQuality + m_EditorClassIdentifier: + debugShaders: + debugReplacementPS: {fileID: 4800000, guid: cf852408f2e174538bcd9b7fda1c5ae7, type: 3} + hdrDebugViewPS: {fileID: 4800000, guid: 573620ae32aec764abd4d728906d2587, type: 3} + m_RendererFeatures: [] + m_RendererFeatureMap: + m_UseNativeRenderPass: 0 + postProcessData: {fileID: 11400000, guid: 41439944d30ece34e96484bdb6645b55, type: 2} + xrSystemData: {fileID: 11400000, guid: 60e1133243b97e347b653163a8c01b64, type: 2} + shaders: + blitPS: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3} + copyDepthPS: {fileID: 4800000, guid: d6dae50ee9e1bfa4db75f19f99355220, type: 3} + screenSpaceShadowPS: {fileID: 4800000, guid: 0f854b35a0cf61a429bd5dcfea30eddd, type: 3} + samplingPS: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3} + stencilDeferredPS: {fileID: 4800000, guid: e9155b26e1bc55942a41e518703fe304, type: 3} + fallbackErrorPS: {fileID: 4800000, guid: e6e9a19c3678ded42a3bc431ebef7dbd, type: 3} + fallbackLoadingPS: {fileID: 4800000, guid: 7f888aff2ac86494babad1c2c5daeee2, type: 3} + materialErrorPS: {fileID: 4800000, guid: 5fd9a8feb75a4b5894c241777f519d4e, type: 3} + coreBlitPS: {fileID: 4800000, guid: 93446b5c5339d4f00b85c159e1159b7c, type: 3} + coreBlitColorAndDepthPS: {fileID: 4800000, guid: d104b2fc1ca6445babb8e90b0758136b, type: 3} + blitHDROverlay: {fileID: 4800000, guid: a89bee29cffa951418fc1e2da94d1959, type: 3} + cameraMotionVector: {fileID: 4800000, guid: c56b7e0d4c7cb484e959caeeedae9bbf, type: 3} + objectMotionVector: {fileID: 4800000, guid: 7b3ede40266cd49a395def176e1bc486, type: 3} + dataDrivenLensFlare: {fileID: 4800000, guid: 6cda457ac28612740adb23da5d39ea92, type: 3} + terrainDetailLitPS: {fileID: 4800000, guid: f6783ab646d374f94b199774402a5144, type: 3} + terrainDetailGrassPS: {fileID: 4800000, guid: e507fdfead5ca47e8b9a768b51c291a1, type: 3} + terrainDetailGrassBillboardPS: {fileID: 4800000, guid: 29868e73b638e48ca99a19ea58c48d90, type: 3} + m_AssetVersion: 2 + m_OpaqueLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_TransparentLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_DefaultStencilState: + overrideStencilState: 0 + stencilReference: 0 + stencilCompareFunction: 8 + passOperation: 2 + failOperation: 0 + zFailOperation: 0 + m_ShadowTransparentReceive: 1 + m_RenderingMode: 0 + m_DepthPrimingMode: 0 + m_CopyDepthMode: 0 + m_AccurateGbufferNormals: 0 + m_IntermediateTextureMode: 1 +--- !u!114 &82592129937281022 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 88650573, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: CharacterRenderFeature + m_EditorClassIdentifier: + m_Active: 1 +--- !u!114 &204869185421428586 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1749369493, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: EffectRenderFeature + m_EditorClassIdentifier: + m_Active: 1 + RenderTargetName: _ScreenColorTexture + SamplingShader: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3} + BlitShader: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3} + UberEffectPostShader: {fileID: 4800000, guid: 0f60273b12723a047a568dca50178e02, type: 3} + UberEffectPostMaterial: {fileID: 0} + RenderTargetSampling: 0 + UberEffectPostShaderName: Engine/Effect/UberEffectPost +--- !u!114 &725774101322325403 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1749369493, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: EffectRenderFeature + m_EditorClassIdentifier: + m_Active: 1 + RenderTargetName: _ScreenColorTexture + SamplingShader: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3} + BlitShader: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3} + UberEffectPostShader: {fileID: 4800000, guid: 0f60273b12723a047a568dca50178e02, type: 3} + UberEffectPostMaterial: {fileID: 0} + RenderTargetSampling: 0 + UberEffectPostShaderName: Engine/Effect/UberEffectPost +--- !u!114 &1268361228661498312 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1741494071, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: GlobalScanFeature + m_EditorClassIdentifier: + m_Active: 1 + settings: + scanMaterial: {fileID: 2100000, guid: d67115296155f3c41ab11dbf400eaadf, type: 2} + renderPassEvent: 500 +--- !u!114 &1282094438684808781 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: de6450284375eea4aa7e52135fd4e340, type: 3} + m_Name: GlobalScanFeature + m_EditorClassIdentifier: + m_Active: 1 + settings: {scanMaterial: {fileID: 2100000, guid: d67115296155f3c41ab11dbf400eaadf, type: 2}, renderPassEvent: 500} +--- !u!114 &1305107786418458812 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1181071007, guid: 58d7e77cafa53d146af19f551ff0a3f7, type: 3} + m_Name: NiloToonCharacterRendererFeature + m_EditorClassIdentifier: + m_Active: 1 + mCharacterRenderSetting: + mOutlineSetting: + ShouldRenderOutline: 1 + UseBigSceneOutline: 0 + BigSceneOutlineAtten: 250 + outlineWidthMultiplier: 4 + outlineTintColor: {r: 1, g: 1, b: 1, a: 1} + outlineWidthAutoAdjustToCameraDistanceAndFOV: 1 + mSelfShadowSetting: + mEnableSelfShadow: 0 + mShadowUDAngle: 20 + mShadowLRAngle: 1.4 + mShadowMapSize: 2048 + mMaxShadowDistance: 100 + mShadowDepthBias: 0.78 + mUseNDotLFix: 1 + mPerfectCullingForShadowCasters: 0 + mDebugShadowCameraVisibleBox: 0 + mMiscParamsSetting: + mFinalColorMultiplier: {r: 1, g: 1, b: 1, a: 1} + mRenderDepthNormal: 1 + mFinalColorIntensity: 1 + mCharacterValueMultiplier: 1 + mCharacterSaturateMultiplier: 0.2 + mGlobalMainDirectionalLightMultiplier: 0.75 + mOverridedLightUpDownAngle: -30 + mOverridedLightLRAngle: 30 + mOverrideLightDirectionIntensity: 1 + mSpecularIntensity: 1 + mSpecularColor: {r: 1, g: 1, b: 1, a: 1} + mUseMainLightDirForSpecular: 1 + mIndirecLightMinColor: {r: 0.01, g: 0.01, b: 0.01, a: 1} + mIndirecLightMultiplier: 1 + mOverridedRimLightUpDownAngle: 180 + mOverridedRimLightLRAngle: -66 + mOverrideRimLightDirectionIntensity: 1 + mGlobalRimLightTintColor: {r: 1, g: 1, b: 1, a: 1} + mGlobalRimLightMultipiler: 4 + mRimLightStartFadeIn: 0 + mRimLightStartFadeOut: 100 + mRimLightAndShadowWidthMultiplier: 2 + mRimLightDepthDiffThresholdOffset: 0.5 + mAddLightMultipiler: {r: 1, g: 1, b: 1, a: 0.5} + mAddLightMaxContribution: {r: 1, g: 1, b: 1, a: 1} + mShadowColor: {r: 0, g: 0, b: 0, a: 0.5} + mShadowAngle: 311 + mShadowLength: 0.89 + mShadowHeight: 0.1 +--- !u!114 &1346129852619499677 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1467291068, guid: 58d7e77cafa53d146af19f551ff0a3f7, type: 3} + m_Name: EffectRenderFeature + m_EditorClassIdentifier: + m_Active: 1 + RenderTargetName: _ScreenColorTexture + SamplingShader: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3} + BlitShader: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3} + UberEffectPostShader: {fileID: 4800000, guid: e4dc0f5e3a376594b807a6e398748f7b, type: 3} + UberEffectPostMaterial: {fileID: 0} + RenderTargetSampling: 0 + UberEffectPostShaderName: GYGame/Effect/UberEffectPost +--- !u!114 &2194802274330149393 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1918578592, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: UIGrabPassFeature + m_EditorClassIdentifier: + m_Active: 1 + settings: + renderScale: 1 + uiCameraName: CameraUi + blurredMaterial: {fileID: 0} +--- !u!114 &3140139178374968523 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 88650573, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: CharacterRenderFeature + m_EditorClassIdentifier: + m_Active: 1 +--- !u!114 &3838470855858450216 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a319187780713924f9f1ad5521975bbe, type: 3} + m_Name: AfterTransparentColorAndCloakFeature + m_EditorClassIdentifier: + m_Active: 1 + m_Settings: + afterTransparentColorTextureName: _AfterTransparentColorTex + downsample: 0.5 + skipSceneView: 1 +--- !u!114 &5386121282085986449 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1749369493, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: EffectRenderFeature + m_EditorClassIdentifier: + m_Active: 1 + RenderTargetName: _ScreenColorTexture + SamplingShader: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3} + BlitShader: {fileID: 4800000, guid: c17132b1f77d20942aa75f8429c0f8bc, type: 3} + UberEffectPostShader: {fileID: 4800000, guid: 0f60273b12723a047a568dca50178e02, type: 3} + UberEffectPostMaterial: {fileID: 0} + RenderTargetSampling: 0 + UberEffectPostShaderName: Engine/Effect/UberEffectPost +--- !u!114 &6856233958429584178 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1608182031, guid: 58d7e77cafa53d146af19f551ff0a3f7, type: 3} + m_Name: SceneRenderFeature + m_EditorClassIdentifier: + m_Active: 1 + Settings: + SceneParameters: + CopyColor: 1 + ShadowColor: {r: 0.2719384, g: 0.35710105, b: 0.5943396, a: 1} + BakedShadowStrength: 0.822 + GlobalBrightness: 1 + SceneDebug: 0 + NormalDebug: 0 + VertexColorDebug: 0 + DebugCustomValue: + FogParameters: + OpenFog: 1 + LineFogColor: {r: 0.2776789, g: 0.7451238, b: 0.9056604, a: 1} + LineFogStartDistance: 75.6 + LineFogEndDistance: 163.8 + LineFogStrength: 0 + HeightFogColor: {r: 0.19215687, g: 0.5803922, b: 0.6117647, a: 1} + HeightFogStartHeight: -0.62 + HeightFogFalloff: 1.974 + HeightFogDensity: 0.0072 + HeightFogStartDistance: 75.25 + HeightFogMinOpacity: 1 + FogAmbient: 1 +--- !u!114 &6876166720411419037 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 1918578592, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: UIGrabPassFeature + m_EditorClassIdentifier: + m_Active: 1 + settings: + renderScale: 1 + uiCameraName: CameraUi + blurredMaterial: {fileID: 0} +--- !u!114 &7225584861622257479 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 88650573, guid: d69daf564475a6b48a9faa2993a03538, type: 3} + m_Name: CharacterRenderFeature + m_EditorClassIdentifier: + m_Active: 1 +--- !u!114 &9176359278972220443 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 0ef3e8d453aa10e459b89fc52b664d0e, type: 3} + m_Name: GlobalScanFeature + m_EditorClassIdentifier: + m_Active: 1 + settings: {scanMaterial: {fileID: 2100000, guid: d67115296155f3c41ab11dbf400eaadf, type: 2}, renderPassEvent: 500} diff --git a/AIClient/Assets/Settings/URP/ForwardRenderer 4VeryHighQuality.asset.meta b/AIClient/Assets/Settings/URP/ForwardRenderer 4VeryHighQuality.asset.meta new file mode 100644 index 0000000..1c8b1ea --- /dev/null +++ b/AIClient/Assets/Settings/URP/ForwardRenderer 4VeryHighQuality.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8ba4e2173e1767649a1a39195e744d4f +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/Settings/URP/UniversalRP-0VeryLowQuality.asset b/AIClient/Assets/Settings/URP/UniversalRP-0VeryLowQuality.asset new file mode 100644 index 0000000..63e41de --- /dev/null +++ b/AIClient/Assets/Settings/URP/UniversalRP-0VeryLowQuality.asset @@ -0,0 +1,114 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bf2edee5c58d82540a51f03df9d42094, type: 3} + m_Name: UniversalRP-0VeryLowQuality + m_EditorClassIdentifier: + k_AssetVersion: 11 + k_AssetPreviousVersion: 11 + m_RendererType: 1 + m_RendererData: {fileID: 0} + m_RendererDataList: + - {fileID: 11400000, guid: 39a007eb403d850479271fda4ed87835, type: 2} + m_DefaultRendererIndex: 0 + m_RequireDepthTexture: 0 + m_RequireOpaqueTexture: 0 + m_OpaqueDownsampling: 1 + m_SupportsTerrainHoles: 0 + m_SupportsHDR: 0 + m_HDRColorBufferPrecision: 0 + m_MSAA: 1 + m_RenderScale: 0.85 + m_UpscalingFilter: 0 + m_FsrOverrideSharpness: 0 + m_FsrSharpness: 0.92 + m_EnableLODCrossFade: 1 + m_LODCrossFadeDitheringType: 1 + m_ShEvalMode: 0 + m_MainLightRenderingMode: 1 + m_MainLightShadowsSupported: 0 + m_MainLightShadowmapResolution: 1024 + m_AdditionalLightsRenderingMode: 2 + m_AdditionalLightsPerObjectLimit: 4 + m_AdditionalLightShadowsSupported: 1 + m_AdditionalLightsShadowmapResolution: 1024 + m_AdditionalLightsShadowResolutionTierLow: 256 + m_AdditionalLightsShadowResolutionTierMedium: 512 + m_AdditionalLightsShadowResolutionTierHigh: 1024 + m_ReflectionProbeBlending: 0 + m_ReflectionProbeBoxProjection: 0 + m_ShadowDistance: 10 + m_ShadowCascadeCount: 1 + m_Cascade2Split: 0.16666667 + m_Cascade3Split: {x: 0.25800002, y: 0.5776} + m_Cascade4Split: {x: 0.067, y: 0.2, z: 0.46700004} + m_CascadeBorder: 0 + m_ShadowDepthBias: 1 + m_ShadowNormalBias: 1 + m_AnyShadowsSupported: 1 + m_SoftShadowsSupported: 0 + m_ConservativeEnclosingSphere: 0 + m_NumIterationsEnclosingSphere: 64 + m_SoftShadowQuality: 2 + m_AdditionalLightsCookieResolution: 256 + m_AdditionalLightsCookieFormat: 3 + m_UseSRPBatcher: 1 + m_SupportsDynamicBatching: 0 + m_MixedLightingSupported: 1 + m_SupportsLightCookies: 1 + m_SupportsLightLayers: 0 + m_DebugLevel: 0 + m_StoreActionsOptimization: 0 + m_EnableRenderGraph: 0 + m_UseAdaptivePerformance: 1 + m_ColorGradingMode: 0 + m_ColorGradingLutSize: 32 + m_UseFastSRGBLinearConversion: 0 + m_SupportDataDrivenLensFlare: 1 + m_ShadowType: 1 + m_LocalShadowsSupported: 0 + m_LocalShadowsAtlasResolution: 256 + m_MaxPixelLights: 0 + m_ShadowAtlasResolution: 256 + m_VolumeFrameworkUpdateMode: 0 + m_Textures: + blueNoise64LTex: {fileID: 2800000, guid: e3d24661c1e055f45a7560c033dbb837, type: 3} + bayerMatrixTex: {fileID: 2800000, guid: f9ee4ed84c1d10c49aabb9b210b0fc44, type: 3} + m_PrefilteringModeMainLightShadows: 0 + m_PrefilteringModeAdditionalLight: 1 + m_PrefilteringModeAdditionalLightShadows: 0 + m_PrefilterXRKeywords: 1 + m_PrefilteringModeForwardPlus: 0 + m_PrefilteringModeDeferredRendering: 0 + m_PrefilteringModeScreenSpaceOcclusion: 0 + m_PrefilterDebugKeywords: 1 + m_PrefilterWriteRenderingLayers: 1 + m_PrefilterHDROutput: 1 + m_PrefilterSSAODepthNormals: 1 + m_PrefilterSSAOSourceDepthLow: 1 + m_PrefilterSSAOSourceDepthMedium: 1 + m_PrefilterSSAOSourceDepthHigh: 1 + m_PrefilterSSAOInterleaved: 1 + m_PrefilterSSAOBlueNoise: 1 + m_PrefilterSSAOSampleCountLow: 1 + m_PrefilterSSAOSampleCountMedium: 1 + m_PrefilterSSAOSampleCountHigh: 1 + m_PrefilterDBufferMRT1: 1 + m_PrefilterDBufferMRT2: 1 + m_PrefilterDBufferMRT3: 1 + m_PrefilterSoftShadowsQualityLow: 1 + m_PrefilterSoftShadowsQualityMedium: 1 + m_PrefilterSoftShadowsQualityHigh: 1 + m_PrefilterSoftShadows: 0 + m_PrefilterScreenCoord: 1 + m_PrefilterNativeRenderPass: 1 + m_ShaderVariantLogLevel: 0 + m_ShadowCascades: 1 diff --git a/AIClient/Assets/Settings/URP/UniversalRP-0VeryLowQuality.asset.meta b/AIClient/Assets/Settings/URP/UniversalRP-0VeryLowQuality.asset.meta new file mode 100644 index 0000000..a058c0b --- /dev/null +++ b/AIClient/Assets/Settings/URP/UniversalRP-0VeryLowQuality.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3d8cd8eb10307ce4b9685eccaedfb19d +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/Settings/URP/UniversalRP-1LowQuality.asset b/AIClient/Assets/Settings/URP/UniversalRP-1LowQuality.asset new file mode 100644 index 0000000..44e6467 --- /dev/null +++ b/AIClient/Assets/Settings/URP/UniversalRP-1LowQuality.asset @@ -0,0 +1,114 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bf2edee5c58d82540a51f03df9d42094, type: 3} + m_Name: UniversalRP-1LowQuality + m_EditorClassIdentifier: + k_AssetVersion: 11 + k_AssetPreviousVersion: 11 + m_RendererType: 1 + m_RendererData: {fileID: 0} + m_RendererDataList: + - {fileID: 11400000, guid: ab43e90c602bfdb4e97e042f15d35169, type: 2} + m_DefaultRendererIndex: 0 + m_RequireDepthTexture: 0 + m_RequireOpaqueTexture: 0 + m_OpaqueDownsampling: 1 + m_SupportsTerrainHoles: 0 + m_SupportsHDR: 1 + m_HDRColorBufferPrecision: 0 + m_MSAA: 1 + m_RenderScale: 1 + m_UpscalingFilter: 0 + m_FsrOverrideSharpness: 0 + m_FsrSharpness: 0.92 + m_EnableLODCrossFade: 1 + m_LODCrossFadeDitheringType: 1 + m_ShEvalMode: 0 + m_MainLightRenderingMode: 1 + m_MainLightShadowsSupported: 0 + m_MainLightShadowmapResolution: 1024 + m_AdditionalLightsRenderingMode: 1 + m_AdditionalLightsPerObjectLimit: 2 + m_AdditionalLightShadowsSupported: 1 + m_AdditionalLightsShadowmapResolution: 1024 + m_AdditionalLightsShadowResolutionTierLow: 256 + m_AdditionalLightsShadowResolutionTierMedium: 512 + m_AdditionalLightsShadowResolutionTierHigh: 1024 + m_ReflectionProbeBlending: 0 + m_ReflectionProbeBoxProjection: 0 + m_ShadowDistance: 10 + m_ShadowCascadeCount: 1 + m_Cascade2Split: 0.16666667 + m_Cascade3Split: {x: 0.25800002, y: 0.5776} + m_Cascade4Split: {x: 0.067, y: 0.2, z: 0.46700004} + m_CascadeBorder: 0 + m_ShadowDepthBias: 1 + m_ShadowNormalBias: 1 + m_AnyShadowsSupported: 1 + m_SoftShadowsSupported: 1 + m_ConservativeEnclosingSphere: 0 + m_NumIterationsEnclosingSphere: 64 + m_SoftShadowQuality: 2 + m_AdditionalLightsCookieResolution: 512 + m_AdditionalLightsCookieFormat: 3 + m_UseSRPBatcher: 1 + m_SupportsDynamicBatching: 0 + m_MixedLightingSupported: 1 + m_SupportsLightCookies: 1 + m_SupportsLightLayers: 0 + m_DebugLevel: 0 + m_StoreActionsOptimization: 0 + m_EnableRenderGraph: 0 + m_UseAdaptivePerformance: 1 + m_ColorGradingMode: 1 + m_ColorGradingLutSize: 32 + m_UseFastSRGBLinearConversion: 0 + m_SupportDataDrivenLensFlare: 1 + m_ShadowType: 1 + m_LocalShadowsSupported: 0 + m_LocalShadowsAtlasResolution: 256 + m_MaxPixelLights: 0 + m_ShadowAtlasResolution: 256 + m_VolumeFrameworkUpdateMode: 0 + m_Textures: + blueNoise64LTex: {fileID: 2800000, guid: e3d24661c1e055f45a7560c033dbb837, type: 3} + bayerMatrixTex: {fileID: 2800000, guid: f9ee4ed84c1d10c49aabb9b210b0fc44, type: 3} + m_PrefilteringModeMainLightShadows: 0 + m_PrefilteringModeAdditionalLight: 3 + m_PrefilteringModeAdditionalLightShadows: 2 + m_PrefilterXRKeywords: 1 + m_PrefilteringModeForwardPlus: 0 + m_PrefilteringModeDeferredRendering: 0 + m_PrefilteringModeScreenSpaceOcclusion: 0 + m_PrefilterDebugKeywords: 1 + m_PrefilterWriteRenderingLayers: 1 + m_PrefilterHDROutput: 1 + m_PrefilterSSAODepthNormals: 1 + m_PrefilterSSAOSourceDepthLow: 1 + m_PrefilterSSAOSourceDepthMedium: 1 + m_PrefilterSSAOSourceDepthHigh: 1 + m_PrefilterSSAOInterleaved: 1 + m_PrefilterSSAOBlueNoise: 1 + m_PrefilterSSAOSampleCountLow: 1 + m_PrefilterSSAOSampleCountMedium: 1 + m_PrefilterSSAOSampleCountHigh: 1 + m_PrefilterDBufferMRT1: 1 + m_PrefilterDBufferMRT2: 1 + m_PrefilterDBufferMRT3: 1 + m_PrefilterSoftShadowsQualityLow: 1 + m_PrefilterSoftShadowsQualityMedium: 1 + m_PrefilterSoftShadowsQualityHigh: 1 + m_PrefilterSoftShadows: 0 + m_PrefilterScreenCoord: 1 + m_PrefilterNativeRenderPass: 1 + m_ShaderVariantLogLevel: 0 + m_ShadowCascades: 1 diff --git a/AIClient/Assets/Settings/URP/UniversalRP-1LowQuality.asset.meta b/AIClient/Assets/Settings/URP/UniversalRP-1LowQuality.asset.meta new file mode 100644 index 0000000..8d33b7e --- /dev/null +++ b/AIClient/Assets/Settings/URP/UniversalRP-1LowQuality.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 81260592605bd4049b035d0093204b55 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/Settings/URP/UniversalRP-2MediumQuality.asset b/AIClient/Assets/Settings/URP/UniversalRP-2MediumQuality.asset new file mode 100644 index 0000000..fb45080 --- /dev/null +++ b/AIClient/Assets/Settings/URP/UniversalRP-2MediumQuality.asset @@ -0,0 +1,114 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bf2edee5c58d82540a51f03df9d42094, type: 3} + m_Name: UniversalRP-2MediumQuality + m_EditorClassIdentifier: + k_AssetVersion: 11 + k_AssetPreviousVersion: 11 + m_RendererType: 1 + m_RendererData: {fileID: 0} + m_RendererDataList: + - {fileID: 11400000, guid: f454285041681a44999cc258865df961, type: 2} + m_DefaultRendererIndex: 0 + m_RequireDepthTexture: 0 + m_RequireOpaqueTexture: 0 + m_OpaqueDownsampling: 1 + m_SupportsTerrainHoles: 0 + m_SupportsHDR: 1 + m_HDRColorBufferPrecision: 0 + m_MSAA: 1 + m_RenderScale: 1 + m_UpscalingFilter: 0 + m_FsrOverrideSharpness: 0 + m_FsrSharpness: 0.92 + m_EnableLODCrossFade: 1 + m_LODCrossFadeDitheringType: 1 + m_ShEvalMode: 0 + m_MainLightRenderingMode: 1 + m_MainLightShadowsSupported: 0 + m_MainLightShadowmapResolution: 512 + m_AdditionalLightsRenderingMode: 1 + m_AdditionalLightsPerObjectLimit: 4 + m_AdditionalLightShadowsSupported: 0 + m_AdditionalLightsShadowmapResolution: 512 + m_AdditionalLightsShadowResolutionTierLow: 256 + m_AdditionalLightsShadowResolutionTierMedium: 512 + m_AdditionalLightsShadowResolutionTierHigh: 1024 + m_ReflectionProbeBlending: 0 + m_ReflectionProbeBoxProjection: 0 + m_ShadowDistance: 15 + m_ShadowCascadeCount: 1 + m_Cascade2Split: 0.16666667 + m_Cascade3Split: {x: 0.25800002, y: 0.5776} + m_Cascade4Split: {x: 0.067, y: 0.2, z: 0.46700004} + m_CascadeBorder: 0 + m_ShadowDepthBias: 1 + m_ShadowNormalBias: 1 + m_AnyShadowsSupported: 1 + m_SoftShadowsSupported: 0 + m_ConservativeEnclosingSphere: 0 + m_NumIterationsEnclosingSphere: 64 + m_SoftShadowQuality: 2 + m_AdditionalLightsCookieResolution: 512 + m_AdditionalLightsCookieFormat: 3 + m_UseSRPBatcher: 1 + m_SupportsDynamicBatching: 0 + m_MixedLightingSupported: 1 + m_SupportsLightCookies: 1 + m_SupportsLightLayers: 0 + m_DebugLevel: 0 + m_StoreActionsOptimization: 0 + m_EnableRenderGraph: 0 + m_UseAdaptivePerformance: 1 + m_ColorGradingMode: 1 + m_ColorGradingLutSize: 32 + m_UseFastSRGBLinearConversion: 0 + m_SupportDataDrivenLensFlare: 1 + m_ShadowType: 1 + m_LocalShadowsSupported: 0 + m_LocalShadowsAtlasResolution: 256 + m_MaxPixelLights: 0 + m_ShadowAtlasResolution: 256 + m_VolumeFrameworkUpdateMode: 0 + m_Textures: + blueNoise64LTex: {fileID: 2800000, guid: e3d24661c1e055f45a7560c033dbb837, type: 3} + bayerMatrixTex: {fileID: 2800000, guid: f9ee4ed84c1d10c49aabb9b210b0fc44, type: 3} + m_PrefilteringModeMainLightShadows: 0 + m_PrefilteringModeAdditionalLight: 3 + m_PrefilteringModeAdditionalLightShadows: 0 + m_PrefilterXRKeywords: 1 + m_PrefilteringModeForwardPlus: 0 + m_PrefilteringModeDeferredRendering: 0 + m_PrefilteringModeScreenSpaceOcclusion: 0 + m_PrefilterDebugKeywords: 1 + m_PrefilterWriteRenderingLayers: 1 + m_PrefilterHDROutput: 1 + m_PrefilterSSAODepthNormals: 1 + m_PrefilterSSAOSourceDepthLow: 1 + m_PrefilterSSAOSourceDepthMedium: 1 + m_PrefilterSSAOSourceDepthHigh: 1 + m_PrefilterSSAOInterleaved: 1 + m_PrefilterSSAOBlueNoise: 1 + m_PrefilterSSAOSampleCountLow: 1 + m_PrefilterSSAOSampleCountMedium: 1 + m_PrefilterSSAOSampleCountHigh: 1 + m_PrefilterDBufferMRT1: 1 + m_PrefilterDBufferMRT2: 1 + m_PrefilterDBufferMRT3: 1 + m_PrefilterSoftShadowsQualityLow: 1 + m_PrefilterSoftShadowsQualityMedium: 1 + m_PrefilterSoftShadowsQualityHigh: 1 + m_PrefilterSoftShadows: 0 + m_PrefilterScreenCoord: 1 + m_PrefilterNativeRenderPass: 1 + m_ShaderVariantLogLevel: 0 + m_ShadowCascades: 1 diff --git a/AIClient/Assets/Settings/URP/UniversalRP-2MediumQuality.asset.meta b/AIClient/Assets/Settings/URP/UniversalRP-2MediumQuality.asset.meta new file mode 100644 index 0000000..4e6a027 --- /dev/null +++ b/AIClient/Assets/Settings/URP/UniversalRP-2MediumQuality.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7c88b4d5ed0b098458268b323ad17abb +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/Settings/URP/UniversalRP-3HighQuality.asset b/AIClient/Assets/Settings/URP/UniversalRP-3HighQuality.asset new file mode 100644 index 0000000..5886c4c --- /dev/null +++ b/AIClient/Assets/Settings/URP/UniversalRP-3HighQuality.asset @@ -0,0 +1,114 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bf2edee5c58d82540a51f03df9d42094, type: 3} + m_Name: UniversalRP-3HighQuality + m_EditorClassIdentifier: + k_AssetVersion: 11 + k_AssetPreviousVersion: 11 + m_RendererType: 1 + m_RendererData: {fileID: 0} + m_RendererDataList: + - {fileID: 11400000, guid: ad8f6453bdbe88e409d8fd14942f700d, type: 2} + m_DefaultRendererIndex: 0 + m_RequireDepthTexture: 1 + m_RequireOpaqueTexture: 1 + m_OpaqueDownsampling: 0 + m_SupportsTerrainHoles: 0 + m_SupportsHDR: 1 + m_HDRColorBufferPrecision: 0 + m_MSAA: 1 + m_RenderScale: 1 + m_UpscalingFilter: 0 + m_FsrOverrideSharpness: 0 + m_FsrSharpness: 0.92 + m_EnableLODCrossFade: 1 + m_LODCrossFadeDitheringType: 1 + m_ShEvalMode: 0 + m_MainLightRenderingMode: 1 + m_MainLightShadowsSupported: 1 + m_MainLightShadowmapResolution: 1024 + m_AdditionalLightsRenderingMode: 1 + m_AdditionalLightsPerObjectLimit: 4 + m_AdditionalLightShadowsSupported: 0 + m_AdditionalLightsShadowmapResolution: 1024 + m_AdditionalLightsShadowResolutionTierLow: 256 + m_AdditionalLightsShadowResolutionTierMedium: 512 + m_AdditionalLightsShadowResolutionTierHigh: 1024 + m_ReflectionProbeBlending: 0 + m_ReflectionProbeBoxProjection: 0 + m_ShadowDistance: 15 + m_ShadowCascadeCount: 2 + m_Cascade2Split: 0.26666668 + m_Cascade3Split: {x: 0.25800002, y: 0.5776} + m_Cascade4Split: {x: 0.067, y: 0.2, z: 0.46700004} + m_CascadeBorder: 0 + m_ShadowDepthBias: 1 + m_ShadowNormalBias: 1 + m_AnyShadowsSupported: 1 + m_SoftShadowsSupported: 0 + m_ConservativeEnclosingSphere: 0 + m_NumIterationsEnclosingSphere: 64 + m_SoftShadowQuality: 2 + m_AdditionalLightsCookieResolution: 1024 + m_AdditionalLightsCookieFormat: 3 + m_UseSRPBatcher: 1 + m_SupportsDynamicBatching: 0 + m_MixedLightingSupported: 1 + m_SupportsLightCookies: 1 + m_SupportsLightLayers: 0 + m_DebugLevel: 0 + m_StoreActionsOptimization: 0 + m_EnableRenderGraph: 0 + m_UseAdaptivePerformance: 1 + m_ColorGradingMode: 1 + m_ColorGradingLutSize: 32 + m_UseFastSRGBLinearConversion: 0 + m_SupportDataDrivenLensFlare: 1 + m_ShadowType: 1 + m_LocalShadowsSupported: 0 + m_LocalShadowsAtlasResolution: 256 + m_MaxPixelLights: 0 + m_ShadowAtlasResolution: 256 + m_VolumeFrameworkUpdateMode: 0 + m_Textures: + blueNoise64LTex: {fileID: 2800000, guid: e3d24661c1e055f45a7560c033dbb837, type: 3} + bayerMatrixTex: {fileID: 2800000, guid: f9ee4ed84c1d10c49aabb9b210b0fc44, type: 3} + m_PrefilteringModeMainLightShadows: 3 + m_PrefilteringModeAdditionalLight: 3 + m_PrefilteringModeAdditionalLightShadows: 0 + m_PrefilterXRKeywords: 1 + m_PrefilteringModeForwardPlus: 0 + m_PrefilteringModeDeferredRendering: 0 + m_PrefilteringModeScreenSpaceOcclusion: 0 + m_PrefilterDebugKeywords: 1 + m_PrefilterWriteRenderingLayers: 1 + m_PrefilterHDROutput: 1 + m_PrefilterSSAODepthNormals: 1 + m_PrefilterSSAOSourceDepthLow: 1 + m_PrefilterSSAOSourceDepthMedium: 1 + m_PrefilterSSAOSourceDepthHigh: 1 + m_PrefilterSSAOInterleaved: 1 + m_PrefilterSSAOBlueNoise: 1 + m_PrefilterSSAOSampleCountLow: 1 + m_PrefilterSSAOSampleCountMedium: 1 + m_PrefilterSSAOSampleCountHigh: 1 + m_PrefilterDBufferMRT1: 1 + m_PrefilterDBufferMRT2: 1 + m_PrefilterDBufferMRT3: 1 + m_PrefilterSoftShadowsQualityLow: 1 + m_PrefilterSoftShadowsQualityMedium: 1 + m_PrefilterSoftShadowsQualityHigh: 1 + m_PrefilterSoftShadows: 0 + m_PrefilterScreenCoord: 1 + m_PrefilterNativeRenderPass: 1 + m_ShaderVariantLogLevel: 0 + m_ShadowCascades: 1 diff --git a/AIClient/Assets/Settings/URP/UniversalRP-3HighQuality.asset.meta b/AIClient/Assets/Settings/URP/UniversalRP-3HighQuality.asset.meta new file mode 100644 index 0000000..f186cc0 --- /dev/null +++ b/AIClient/Assets/Settings/URP/UniversalRP-3HighQuality.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 76ed49667b45f35418709c0859652e70 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/Settings/URP/UniversalRP-4VeryHighQuality.asset b/AIClient/Assets/Settings/URP/UniversalRP-4VeryHighQuality.asset new file mode 100644 index 0000000..772f4f5 --- /dev/null +++ b/AIClient/Assets/Settings/URP/UniversalRP-4VeryHighQuality.asset @@ -0,0 +1,114 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: bf2edee5c58d82540a51f03df9d42094, type: 3} + m_Name: UniversalRP-4VeryHighQuality + m_EditorClassIdentifier: + k_AssetVersion: 11 + k_AssetPreviousVersion: 11 + m_RendererType: 1 + m_RendererData: {fileID: 0} + m_RendererDataList: + - {fileID: 11400000, guid: 8ba4e2173e1767649a1a39195e744d4f, type: 2} + m_DefaultRendererIndex: 0 + m_RequireDepthTexture: 1 + m_RequireOpaqueTexture: 1 + m_OpaqueDownsampling: 0 + m_SupportsTerrainHoles: 0 + m_SupportsHDR: 1 + m_HDRColorBufferPrecision: 0 + m_MSAA: 1 + m_RenderScale: 1 + m_UpscalingFilter: 0 + m_FsrOverrideSharpness: 0 + m_FsrSharpness: 0.92 + m_EnableLODCrossFade: 1 + m_LODCrossFadeDitheringType: 1 + m_ShEvalMode: 0 + m_MainLightRenderingMode: 1 + m_MainLightShadowsSupported: 1 + m_MainLightShadowmapResolution: 2048 + m_AdditionalLightsRenderingMode: 1 + m_AdditionalLightsPerObjectLimit: 4 + m_AdditionalLightShadowsSupported: 1 + m_AdditionalLightsShadowmapResolution: 1024 + m_AdditionalLightsShadowResolutionTierLow: 256 + m_AdditionalLightsShadowResolutionTierMedium: 512 + m_AdditionalLightsShadowResolutionTierHigh: 1024 + m_ReflectionProbeBlending: 0 + m_ReflectionProbeBoxProjection: 0 + m_ShadowDistance: 30 + m_ShadowCascadeCount: 2 + m_Cascade2Split: 0.2 + m_Cascade3Split: {x: 0.10000001, y: 0.3} + m_Cascade4Split: {x: 0, y: 0.001, z: 0.24375} + m_CascadeBorder: 0 + m_ShadowDepthBias: 1 + m_ShadowNormalBias: 0 + m_AnyShadowsSupported: 1 + m_SoftShadowsSupported: 1 + m_ConservativeEnclosingSphere: 0 + m_NumIterationsEnclosingSphere: 64 + m_SoftShadowQuality: 2 + m_AdditionalLightsCookieResolution: 1024 + m_AdditionalLightsCookieFormat: 3 + m_UseSRPBatcher: 1 + m_SupportsDynamicBatching: 0 + m_MixedLightingSupported: 1 + m_SupportsLightCookies: 1 + m_SupportsLightLayers: 0 + m_DebugLevel: 0 + m_StoreActionsOptimization: 0 + m_EnableRenderGraph: 0 + m_UseAdaptivePerformance: 1 + m_ColorGradingMode: 1 + m_ColorGradingLutSize: 32 + m_UseFastSRGBLinearConversion: 0 + m_SupportDataDrivenLensFlare: 1 + m_ShadowType: 1 + m_LocalShadowsSupported: 0 + m_LocalShadowsAtlasResolution: 256 + m_MaxPixelLights: 0 + m_ShadowAtlasResolution: 256 + m_VolumeFrameworkUpdateMode: 0 + m_Textures: + blueNoise64LTex: {fileID: 2800000, guid: e3d24661c1e055f45a7560c033dbb837, type: 3} + bayerMatrixTex: {fileID: 2800000, guid: f9ee4ed84c1d10c49aabb9b210b0fc44, type: 3} + m_PrefilteringModeMainLightShadows: 3 + m_PrefilteringModeAdditionalLight: 3 + m_PrefilteringModeAdditionalLightShadows: 2 + m_PrefilterXRKeywords: 1 + m_PrefilteringModeForwardPlus: 0 + m_PrefilteringModeDeferredRendering: 0 + m_PrefilteringModeScreenSpaceOcclusion: 0 + m_PrefilterDebugKeywords: 1 + m_PrefilterWriteRenderingLayers: 1 + m_PrefilterHDROutput: 1 + m_PrefilterSSAODepthNormals: 1 + m_PrefilterSSAOSourceDepthLow: 1 + m_PrefilterSSAOSourceDepthMedium: 1 + m_PrefilterSSAOSourceDepthHigh: 1 + m_PrefilterSSAOInterleaved: 1 + m_PrefilterSSAOBlueNoise: 1 + m_PrefilterSSAOSampleCountLow: 1 + m_PrefilterSSAOSampleCountMedium: 1 + m_PrefilterSSAOSampleCountHigh: 1 + m_PrefilterDBufferMRT1: 1 + m_PrefilterDBufferMRT2: 1 + m_PrefilterDBufferMRT3: 1 + m_PrefilterSoftShadowsQualityLow: 1 + m_PrefilterSoftShadowsQualityMedium: 1 + m_PrefilterSoftShadowsQualityHigh: 1 + m_PrefilterSoftShadows: 0 + m_PrefilterScreenCoord: 1 + m_PrefilterNativeRenderPass: 1 + m_ShaderVariantLogLevel: 0 + m_ShadowCascades: 1 diff --git a/AIClient/Assets/Settings/URP/UniversalRP-4VeryHighQuality.asset.meta b/AIClient/Assets/Settings/URP/UniversalRP-4VeryHighQuality.asset.meta new file mode 100644 index 0000000..f3748a9 --- /dev/null +++ b/AIClient/Assets/Settings/URP/UniversalRP-4VeryHighQuality.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f3546fc18618b9a488f828377c92aa47 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/UniversalRenderPipelineGlobalSettings.asset b/AIClient/Assets/UniversalRenderPipelineGlobalSettings.asset new file mode 100644 index 0000000..783520f --- /dev/null +++ b/AIClient/Assets/UniversalRenderPipelineGlobalSettings.asset @@ -0,0 +1,34 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2ec995e51a6e251468d2a3fd8a686257, type: 3} + m_Name: UniversalRenderPipelineGlobalSettings + m_EditorClassIdentifier: + k_AssetVersion: 3 + m_RenderingLayerNames: + - Default + m_ValidRenderingLayers: 1 + lightLayerName0: + lightLayerName1: + lightLayerName2: + lightLayerName3: + lightLayerName4: + lightLayerName5: + lightLayerName6: + lightLayerName7: + m_StripDebugVariants: 1 + m_StripUnusedPostProcessingVariants: 0 + m_StripUnusedVariants: 1 + m_StripUnusedLODCrossFadeVariants: 1 + m_StripScreenCoordOverrideVariants: 1 + supportRuntimeDebugDisplay: 0 + m_ShaderVariantLogLevel: 0 + m_ExportShaderVariants: 1 diff --git a/AIClient/Assets/UniversalRenderPipelineGlobalSettings.asset.meta b/AIClient/Assets/UniversalRenderPipelineGlobalSettings.asset.meta new file mode 100644 index 0000000..fcb16d1 --- /dev/null +++ b/AIClient/Assets/UniversalRenderPipelineGlobalSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d71d555e4685d9542882aaf4f6b61df8 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Assets/_PipelineRefresh.stamp.txt b/AIClient/Assets/_PipelineRefresh.stamp.txt new file mode 100644 index 0000000..3d7fb24 --- /dev/null +++ b/AIClient/Assets/_PipelineRefresh.stamp.txt @@ -0,0 +1 @@ +refresh 2026-09-21T11:42:00.4196961+08:00 diff --git a/AIClient/Assets/_PipelineRefresh.stamp.txt.meta b/AIClient/Assets/_PipelineRefresh.stamp.txt.meta new file mode 100644 index 0000000..d641399 --- /dev/null +++ b/AIClient/Assets/_PipelineRefresh.stamp.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 617dcf84faf5e0f40920c08af2539308 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/.attestation.p7m b/AIClient/Packages/com.unity.pipeline/.attestation.p7m new file mode 100644 index 0000000000000000000000000000000000000000..cd27434424c67addfdd34f37850560257a5f562e GIT binary patch literal 10926 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 L53{Aqfbo9;qN}|z literal 0 HcmV?d00001 diff --git a/AIClient/Packages/com.unity.pipeline/.claude/skills/unity-pipeline/SKILL.md b/AIClient/Packages/com.unity.pipeline/.claude/skills/unity-pipeline/SKILL.md new file mode 100644 index 0000000..c4e4ab2 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/.claude/skills/unity-pipeline/SKILL.md @@ -0,0 +1,173 @@ +--- +name: unity-pipeline +description: Drive a running Unity Editor or development Player from the command line via the unity-pipeline package — install the package, keep the editor ticking while unfocused, run the edit→recompile→run_tests loop, evaluate C#, and code-reload files at runtime. Use when an agent needs to control a live Unity instance, automate Unity tests, recompile scripts headlessly, or apply runtime reloads. Assumes the `unity` CLI is on PATH. +--- + +# Unity Pipeline (agent control) + +Invoke commands with `unity command [args]`. Run `unity command` with no name to +list what an instance exposes. Two servers exist: **Editor** (`7800-7849`, auto-starts with +the editor) and **Runtime** (`7900-7949`, only in a dev Player build). See the package +`README.md` "Commands" reference for the full list and parameters. + +## 1. Install & verify + +```bash +unity pipeline install # install into current project (or --project-path) +unity pipeline list # confirm the editor instance + server are reachable +unity command editor_status # confirm the editor server answers +``` + +## 2. Autonomous edit loop (Editor) + +This is the core agent workflow: keep the editor alive, change code, recompile, test. + +```bash +# 1. Keep the editor ticking even when unfocused/minimized. REQUIRED before headless work — +# Unity otherwise throttles or stalls update/compile when it isn't the active app. +unity command set_autotick --enable true + +# 2. Edit C# source files on disk normally. + +# 3. Recompile (async: triggers a domain reload, then poll until done). +unity command recompile +unity command recompile_status # repeat until "completed" or "up_to_date" +# Tolerate connection errors while the domain reload is in flight — that is expected. +# If recompile_status reports failed=true, read its "errors" array and fix before testing. + +# 4. (Optional) List available tests without running them. +unity command list_tests --mode editor # mode: all | editor | playmode + +# 5. Run tests (filter to keep it fast). +unity command run_tests --mode editor --filter MyFixture.MyTest +``` + +`run_tests` modes: `all` | `editor` | `playmode`. `filter_type`: `testName` | `assembly` | +`category`. For long runs use `--async_tests true` and poll `unity command test_status` +(abort with `unity command cancel_tests`). + +> **Known caveat:** when any selected test *fails*, `run_tests` may surface an opaque +> result instead of the failure details. Re-run a narrower `--filter`, or inspect the +> editor's Test Runner / logs to get the real failure. + +**Reading exit codes.** They separate "rewrite the invocation" from "the Editor failed", which +is the distinction this loop depends on: + +| Exit | Meaning | What to do | +|------|---------|------------| +| `2` | Bad arguments — a misspelled flag, a wrong type, too many positionals. Nothing ran. | Fix the command line and retry. The error names the problem and often suggests the right flag. | +| `6` | The command ran and failed, or the Editor could not service it. | Read the error; retrying the same invocation will not help. | + +Do not retry an exit 2 unchanged, and do not rewrite a command line on an exit 6. + +## 3. Runtime code reload + +Change gameplay code in a **running** game with no domain reload. The game must be live: +enter Editor Play Mode (`unity command editor_play`) or run a dev Player. A +The runtime Pipeline driver (enabled via Project Settings > Pipeline > Runtime) auto-discovers tagged methods on `Awake` (no manual +registration). Mono only — Editor Play Mode and Mono desktop dev builds, not IL2CPP. The token +is auto-injected for local requests. + +### `reload_file` + +Edit the method body directly; no separate file, no boilerplate. + +1. Tag the method `[CodeReload]` on the MonoBehaviour. +2. Edit its body on disk. +3. Apply (re-run to iterate): + ```bash + unity command reload_file --filename Assets/Spinner.cs + ``` + Add `--pdb` to make it debuggable — emits a portable PDB mapped to your source so breakpoints in + the original file bind (attach the IDE + enable Editor Attaching; compiles unoptimized): + ```bash + unity command reload_file --filename Assets/Spinner.cs --pdb + ``` + +Constraints: `void` instance methods only; **public** members only; debugging requires `--pdb` +(the default emits no symbols). + +`unity command codereload_status` shows active overrides. `reload_file` options: `--timeout ` +(default 30000), `--assemblyDir ` (persist DLLs instead of in-memory); +`cleanup_codereload --assemblyDir ` clears old DLLs. + +## 4. Bulk construction: `run_script` (the builder pattern) + +For bulk work — creating many objects, wiring fields, generating content — put the code in a +**versioned project script** and run a named static entry point with `run_script`. No domain +reload, no code carried through the protocol; iterating costs an in-memory compile (< ~2s), not +a 15–20s recompile. + +```bash +# 1. Write the builder OUTSIDE Assets/ (so the write triggers no asset import / domain reload), +# e.g. AgentScripts/Build.cs: public static class Build { public static int All() { ... } } +# 2. Run it — relative paths resolve against the project root (the parent of Assets/): +unity command run_script --file AgentScripts/Build.cs --entry Build.All +# 3. Iterate: edit the file, re-run. Useful extras: +unity command run_script --file AgentScripts/Build.cs --dry_run true # compile-only check: diagnostics, nothing loaded or executed +unity command run_script --file AgentScripts/Build.cs --entry Build.All --args '[3, "Green"]' +``` + +Rules of thumb: + +- **Code goes in files on disk via `run_script`; `eval` is for genuinely ad-hoc one-liners.** + Never ship multi-line escaped C# strings through `eval` — write the file, run the entry. +- Compiles see the project's **active editor defines** (`UNITY_EDITOR`, version/platform symbols); + `--defines` appends extra symbols on top. +- Entry points may be `async Task`/`Task` — they are awaited asynchronously (the editor keeps + pumping, so awaits resuming on Unity's context work naturally) and `Task.Result` is returned. + The wait is bounded by `timeout_ms`; on expiry the task keeps running detached. +- Runtime exceptions come back with `file:line` mapped to your source (a source-mapped PDB is + always emitted for executing runs; they compile unoptimized). +- `--mode hotpatch` instead applies `[CodeReload]` in-place method replacements (delegates to + `reload_file`); `entry`/`args`/`dry_run` are rejected there and `references`/`defines` don't apply. + +## 5. Quick C# eval (Runtime) + +For genuinely ad-hoc one-liners only — anything longer belongs in a file run via `run_script`. + +```bash +unity command eval "return 2 + 2;" +# Or evaluate a .cs file on disk (contents run through the same path): +unity command eval_file Assets/Scratch.cs +``` + +## 5. Project audit (Editor) + +Static-analysis scan via Project Auditor, producing a CSV of issues to fix. Trigger, poll, read. + +```bash +unity command audit # optional: --categories Code,ProjectSetting --output my.csv +unity command audit_status # repeat until terminal status +``` + +`audit_status` is terminal on `completed` (with `csvPath` + `issueCount`), `failed`, `unavailable`, or +`interrupted` (a domain reload killed the scan — just re-run `audit`). Polling stays responsive while a +Code-category scan compiles assemblies and holds the main thread. One scan at a time: a second `audit` +returns `busy`. There is no cancel — stop polling to abandon a scan. + +CSV columns: `Category, Severity, Areas, Description, RelativePath, Line, DescriptorId, Recommendation` +(diagnostics only, so every row is something to fix; `Recommendation` says how). + +> **Requires Project Auditor plus its rules.** `unavailable` means the Editor has no Project Auditor, +> or it has no analysis rules — in a built-in-module Editor the rules live in the separate +> `com.unity.project-auditor-rules` package (`unity command package_add --identifier +> com.unity.project-auditor-rules --confirm true`). Read the `message` field; the command never reports +> an empty `completed` scan that would look like a clean project. + +## Gotchas + +- **`set_autotick` first.** Without it, recompile and tests can hang while the editor is + unfocused. The package's watchdog relies on the tick loop staying alive. +- **A stuck command may mean a modal dialog is open**, not a hang — a dialog blocks the main + thread until dismissed. If a command runs long, check `unity command editor_status` (answers + instantly even when blocked); `status: "blocked_by_dialog"` means stop retrying and tell the + human what's blocking (its `dialog.title`/`message`/`buttons`) — it can't be clicked over CLI. +- **Code reload needs the game running.** `reload_file` applies to a live + game — enter Editor Play Mode (`unity command editor_play`) first, or run a dev Player. +- **Player-only commands need a dev Player.** `log`, `set_timescale`, `runtime_status`, etc. hit + the Runtime server, which does not run in the Editor. +- **Async commands poll.** `recompile`→`recompile_status`, `run_tests --async_tests`→ + `test_status`. Never assume completion from the trigger call's response. +- **Target a specific instance** with `--instance host:port` or `--project-path ` + when more than one is running. diff --git a/AIClient/Packages/com.unity.pipeline/.signature b/AIClient/Packages/com.unity.pipeline/.signature new file mode 100644 index 0000000..cc80ac6 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/.signature @@ -0,0 +1 @@ +{"timestamp":1789141928,"signature":"crpfmI3LnQCNoOwEW623mwuNDp5ggQAsQ4rqDDXqjY2D8pW41oRle0sYLtZo+w4nEX5ZFjoD5ByM4oJ0obxDdR00UH7Nk+vvh92pckG22pfhohvztPpleny6pFGnTJYaM6smhnyzV5nsA6kplXA0IATP/tWZC/ufFD6L7jrUr/ySyc1n1R0WwIjDyweod+RIrSNZovC7c7j5UFOprIBRqFMr606qLiEkW0vioMNDAOIZ6smTPml6a/s/CJvSr4FzddWGnj76cWWfBoxlhjICwlJ5Wbzr2G44AXLLTAK+1VP8McmY080Nq0eb2OMOUYdWE2DeQ/Wowe+Yo958pOYGe5KNvi2GtlyfFVbHzCCTsUlyZ3+D7XFya/uXZ4+cLacgSHZl9kOSPWskVuyNR30iG9vV24gXyecxJhKbO4orFUb0kUz/DRT1Iq8HMV4U54DAfa6Se0l8lAXbq2g79/NwTMkzVUwKy8bSCrwF9WtWLctAPRN5yetOMpBWDjSDtp0I","publicKey":"LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlJQm9qQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FZOEFNSUlCaWdLQ0FZRUFzdUhXYUhsZ0I1cVF4ZEJjTlJKSAordHR4SmoxcVY1NTdvMlZaRE1XaXhYRVBkRTBEMVFkT1JIRXNSS1RscmplUXlERU83ZlNQS0ZwZ1A3MU5TTnJCCkFHM2NFSU45aHNQVDhOVmllZmdWem5QTkVMenFkVmdEbFhpb2VpUnV6OERKWFgvblpmU1JWKytwbk9ySTRibG4KS0twelJlNW14OTc1SjhxZ1FvRktKT0NNRlpHdkJMR2MxSzZZaEIzOHJFODZCZzgzbUovWjBEYkVmQjBxZm13cgo2ZDVFUXFsd0E5Y3JZT1YyV1VpWXprSnBLNmJZNzRZNmM1TmpBcEFKeGNiaTFOaDlRVEhUcU44N0ZtMDF0R1ZwCjVNd1pXSWZuYVRUemEvTGZLelR5U0pka0tldEZMVGdkYXpMYlpzUEE2aHBSK0FJRTJhc0tLTi84UUk1N3UzU2cKL2xyMnZKS1IvU2l5eEN1Q20vQWJkYnJMbXk0WjlSdm1jMGdpclA4T0lLQWxBRWZ2TzV5Z2hSKy8vd1RpTFlzUQp1SllDM0V2UE16ZGdKUzdGR2FscnFLZzlPTCsxVzROY05yNWdveVdSUUJ0cktKaWlTZEJVWmVxb0RvSUY5NHpCCndGbzJJT1JFdXFqcU51M3diMWZIM3p1dGdtalFra3IxVjJhd3hmcExLWlROQWdNQkFBRT0KLS0tLS1FTkQgUFVCTElDIEtFWS0tLS0tCg"} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/CHANGELOG.md b/AIClient/Packages/com.unity.pipeline/CHANGELOG.md new file mode 100644 index 0000000..c2f009a --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/CHANGELOG.md @@ -0,0 +1,158 @@ +# Changelog + +All notable changes to this package will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.7.0-exp.1] - 2026-09-10 + +### Changed + +- [AUTHAPI-71] The Pipeline runtime assemblies and the bundled Roslyn DLLs are no longer included in non-development Player builds. Enabling the runtime server for a release build now has no effect instead of warning. Add the `ENABLE_RUNTIME_PIPELINE` scripting define symbol to include them in a build that is not a Development Build. +- [AUTHAPI-71] The code reload attributes moved to their own `Unity.Pipeline.Attributes` assembly, so code tagged with them still compiles for a release build, where they do nothing. An assembly definition that referenced `Unity.Pipeline` to get the attributes must add `Unity.Pipeline.Attributes` to its references; scripts that are not in an assembly definition need no change. +- [UUM-151473] `console` is now robust across domain reloads, Editor restarts and play-mode transitions. It reports the capture session alongside its cursor and refuses a cursor it cannot honor rather than returning an empty result; it backfills from the Editor console's own store, so compile errors logged before capture started are visible; and it re-arms itself when Unity drops the log callback. Every response also carries the Editor's own console counts and compile-failure flag, so a client can tell in one call when the buffer and the Console window disagree. +- [UUM-151473] `clear_console` moved to the runtime assembly beside `console` and `console_status`, so all three console commands live in one file and `clear_console` now works in player builds too (where it clears the captured buffer; there is no Editor console to clear). + +### Added + +- [AUTHAPI-25] Added server-side condition waiting: a wait command that polls an editor/object state until it holds (or times out), synchronously or in the background with status polling and cancelation. +- [AUTHAPI-51] `CommandRegistry.RegisterCommand`/`UnregisterCommand`: register commands at runtime without a `[CliCommand]` attribute, for command sets that depend on runtime state. A dynamic registration behaves exactly like an attribute-declared one — same `/api/commands` metadata, same `[CliArg]` parameter discovery on the handler, same `/api/exec` execution — and additionally accepts an instance-bound delegate, so a command can run against a specific object. Registrations survive a discovery-mechanism swap and last until unregistered or the domain reloads — one made while in Play Mode is dropped when Play Mode exits, so a handler registered from `Awake` re-registers cleanly on the next entry even with domain reload disabled. A name already in use throws rather than shadowing the existing command. See `Documentation~/creating-commands.md`. +- [UUM-151473] `console` responses carry `counts` (entries the buffer retains per severity) and `groundTruth` (the Editor's own `compilationFailed`, `compiling`, console entry counts, whether the buffer was seeded, and the sample's `ageMs`), so a client can spot the buffer disagreeing with the Console window in one round trip. +- [UUM-151473] New `console_status` command: the same counters and compile-failure flag without the entries, cheap enough to poll while a compile runs. +- [UUM-151473] `console` entries carry `logType` (Unity's exact `LogType` name, keeping the Exception/Assert distinction that `level` collapses) and `seeded` (read from the Editor console store rather than captured live, so the timestamp is the read time). +- [UUM-151473] `recompile_status` reports `compilationFailed`. + +### Fixed + +- [UUM-151473] Fixed `console` returning an empty result that was indistinguishable from "nothing new" when the `since` cursor came from an earlier Editor session. Sequence numbers restart with the process (the buffer is persisted under `Temp/`, which Unity deletes at every launch), so such a cursor filtered out every entry held. Responses now carry a `session`, `console` accepts `since_session`, and a cursor that cannot be honored returns the tail with `reset=true` and `dropped=true`. +- [UUM-151473] Fixed `ConsoleLogBuffer.Load` discarding entries logged since the snapshot it restores, and lowering the sequence counter when the snapshot was stale. It now merges by sequence number and never rewinds a cursor already handed out. +- [UUM-151473] Fixed `console` never reporting Editor compile errors logged before capture started. Those are logged as sticky entries that survive every console clear until the next compile completes, so they can stand in the Console window indefinitely; the buffer is now backfilled once per session from the Editor console's own store. +- [UUM-151473] Fixed console capture staying dead after Unity unregistered the native log callback with no observable symptom. The Editor now samples the console's own counts and re-arms capture when they move while the buffer's cursor does not. +- [UUM-151473] Fixed `recompile` reporting `up_to_date` while compile errors were still standing. A failed editor compile suppresses the domain reload and leaves the errors in place, so a repeat call with nothing changed compiled nothing and erased the recorded failure. Both `recompile` and `recompile_status` now consult Unity's native compile-failure flag, which also covers the status file being deleted with `Temp/` at every Editor launch. +- [UUM-151473] Fixed `clear_console` clearing only one of the package's two console buffers, so `console` kept returning entries that had been cleared. +- [UUM-151968] The runtime instance descriptor now writes to `Application.persistentDataPath` on Android instead of beside `Application.dataPath`, which is read-only there. +- [AUTHAPI-49] `Pipeline_SessionStopped` now fires on `EditorApplication.wantsToQuit` instead of `EditorApplication.quitting`, since the Analytics service is already shutting down by the time `quitting` runs and the event was never actually sent. + +### Removed + +- [UUM-151473] Removed `get_console_logs`, which duplicated `console` over a second buffer of its own — every log line was captured twice, and `clear_console` cleared only one of them. Use `console`; its new `logType` field carries the exact log type `get_console_logs` reported. + +## [0.6.0-exp.1] - 2026-08-31 + +### Changed +- Hot reload is now called **code reload** throughout. The attributes are `[CodeReload]`, `[OnCodeReload]` and `[CodeReloadOverrideMethod]` in namespace `Unity.Pipeline.CodeReload`; the registry is `CodeReloadRegistry`; the commands `hotreload_status` and `cleanup_hotreload` are now `codereload_status` and `cleanup_codereload` (tag `scripts/codereload`); the sample lives under `Samples~/CodeReload`; the documentation page is `code-reload.md`. The watcher and the folder push now pick up `.cs` files that mention `CodeReload` instead of `HotReload`. The `[HotReload]` family no longer exists, so user code must be updated. +- [AUTHAPI-49] `BasePipelineServer.OnTransactionProcessed(requestJson, responseJson)` is replaced by `OnCommandDone(in CommandExecutionInfo)`, which also carries the command that ran, whether it succeeded, and how long it took. A detached job now reports when it actually completes, not only when its job handle was returned. +- [UUM-149580] Reorganized the Pipeline Runtime settings page (Project Settings > Pipeline > Runtime) into "Server" and "Runtime Behavior" groups, moved the status/security HelpBox to the top, and added an always-visible feature description when there's nothing to warn about. All fields except Max Work Items Per Frame are now read-only while in Play Mode, since edits to them would silently not apply until the next Play session or build; Max Work Items Per Frame stays live-editable — `RuntimePipelineDriver` polls it fresh every frame (cheaply, gated on the settings file's timestamp), matching the pre-redesign component's behavior for that field. +- [UUM-149580] Every field except Enable In Builds itself is now greyed out on the Pipeline Runtime settings page while Enable In Builds is off, instead of staying editable for a server that will not run. +- `reload_file` result contract, stated: a reload that compiles but applies NO methods now fails with the per-method reasons (previously a silent success); a file whose `[HotReload]` methods all match the compiled baseline reports an explicit "up to date" success — naming any stale overrides it reverted — instead of "hot reload successful with 0 methods". +- [AUTHAPI-26] A non-positive `timeout`/`timeout_ms` on `eval`, `eval_file`, or `run_script` now returns a clear `400 Bad Request` instead of an opaque dispatcher timeout. +- Reformatted CHANGELOG.md to more accurately track [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) +- [AUTHAPI-59] Test fixtures and test-only helper classes under `Tests/` are now `internal` instead of `public` — they were never part of the package's public API surface. +- [AUTHAPI-59] Command handler classes and their result/DTO types under `Editor/Commands/` and `Runtime/Commands/` are now `internal` instead of `public`. Command registration and dispatch work via reflection regardless of accessibility (see `Documentation~/creating-commands.md`), so this was never functionally required. +- [AUTHAPI-59] `EditorPipelineManager`, `EditorPipelineManagerEditor`, `PipelineServerStartup`, `EditorPipelineServer`, `PipelineRuntimeBuildProcessor`, `HotReloadInPlaceILPostProcessor`, and `SecurityTokenManager` are now `internal` instead of `public`. `[CustomEditor]`, `[InitializeOnLoad]`, the build pipeline, and `ILPostProcessor` discovery all work via reflection regardless of accessibility, and none of these types were referenced outside the package. +- [AUTHAPI-59] `RuntimePipelineConfigEditor`, `RuntimePipelineSettingsProvider`, `PushEnvelope`, `PushVerifier`, `PushVerifyStatus`, `RotatingFileBackup`, and the `Unity.Pipeline.Telemetry` eval-usage helper types are now `internal` instead of `public` — same rationale: `[CustomEditor]`/`[SettingsProvider]` discovery is reflection-based, and none of these are referenced outside the package. + +### Removed +- The separate-override-file hot reload workflow: the `reload_file_override` command, the `[HotReloadWithOverrides]` attribute, `HotReloadHelper`, and the `HotReload_WithHelpers` sample. Tag methods `[HotReload]` and edit them in place with `reload_file` instead (see `Documentation~/hot-reload.md`). The unused `[HotReloadableComponent]`, `[HotReloadComponent]` and `[HotReloadTarget]` attributes are gone too. + +### Fixed +- Code reload: a `var` local whose inferred type is nested in the reloaded class (`var inp = new BufferedInput { ... }`) no longer fails to compile with "The type name 'var' does not exist in the type ..."; a `using` alias for such a type is left alone too. +- Code reload: when a reload fails to compile, each diagnostic now names the user's file and line, the compiler error code, and the generated line that failed, and the full generated source is written to `Temp/CodeReload/.failed.cs` for inspection. +- Code reload in the Editor no longer depends on the runtime Pipeline server being enabled. `[CodeReload]` targets were only discovered by the runtime driver, which is not created when `enableInBuilds` is off (the default), so an in-editor reload compiled but bound 0 methods with a misleading "added after the running build" reason. Entering Play Mode now registers the targets either way, and an empty registry is reported as such. +- Interpreter backend: `new S { x = 1 }` and `default(S)` on a host struct bound boxed (the auto-bind default, e.g. a `struct` nested in the reloaded MonoBehaviour) failed at runtime with "Non-static field requires a target". The default box is now created, both for `initobj` and for the initobj-free form Roslyn emits when every field is assigned (`S s; s.x = 1; s.y = 2;`), so object initializers, field-by-field construction and nullable-struct fields work in reloaded bodies. Reading or writing a host field on a null object now reports the field name and source line instead of the bare reflection error, and an exception escaping a reloaded body is logged with its script location before it propagates. +- `build`: a scripted build with `Development` in `options` no longer trips the "enableInBuilds without a Development Build" security dialog (the guard only looked at the Build Settings toggle, so a `build` command from the CLI stalled on a modal, or was cancelled). +- `reload_file_player_interpreter`: a push made before the player's signing handshake has arrived now waits up to 10 s for it instead of 2 s; the first push to a freshly connected IL2CPP player was dropped at 2 s. +- [UUM-149991] AutoStaticsCleanup: Fixed usage-analysis findings. +- [UUM-149991] Fixed `CommandRegistry` staying on reflection-based command discovery after exiting Play Mode without a domain reload; `PipelineServerStartup` now restores TypeCache discovery on `EnteredEditMode`. +- [UUM-149977] Removed the "Editor is not in automated mode" console warning. Now surfaced as `info` on the instance descriptor instead. +- [AUTHAPI-36] Fixed `TestResultCollector.RunFinished` throwing `InvalidOperationException` (double-complete) when a run had already been completed by `SetError`/`Cancel` (e.g. a timed-out or errored run): a late `RunFinished` is now a no-op and the original error/cancellation is preserved. +- [UUM-149580] The Pipeline server no longer permanently enables Player Settings "Run In Background" on start; the runtime driver now saves and restores the project's original value around start/stop. +- [UUM-149580] Transient `RuntimePipelineConfig`/`RuntimePipelineBuildInfo` assets left behind by an interrupted build are now purged at the start of every build, so a disabled build can no longer ship the runtime Pipeline server. +- [UUM-149580] Reading Runtime settings (Project Settings page, `get_runtime_pipeline_settings`, or a refused/dry-run `set_runtime_pipeline_settings`) no longer writes the settings file. +- [UUM-149580] `set_runtime_pipeline_settings` now rejects a `port`, `requestTimeoutMs`, or `maxWorkItemsPerFrame` outside the same bounds the Project Settings page enforces, instead of silently persisting an invalid value (a `maxWorkItemsPerFrame` of 0 permanently starved the dispatcher's work queue). + +### Added + +- [AUTHAPI-68] `POST /api/exec` accepts an unparsed command line as `commandLine` (a string the server tokenizes) or `argv` (pre-split tokens), binding positional and `--flag` arguments against the command's declared parameters server-side. Exactly one of `command`, `commandLine` or `argv` may be present, and `parameters` cannot accompany the raw forms. Argument failures return `400` with `errorCode: "INVALID_COMMAND_ARGS"`, a machine-readable `argProblems` array, and the command's `commandSchema`; successful raw-form replies echo the bound `parameters`. Servers advertise `exec.argv` / `exec.commandLine` in `capabilities` on `/api/status` and in the port descriptor. `command` is no longer a JSON-required property, so a body carrying none of the three forms is now rejected by request validation as `400 {"error":"Invalid Request","errorDetails":"Command name is required"}` instead of by deserialization as `400 {"error":"Invalid JSON"}`. +- [AUTHAPI-64] Added a new endpoint reporting currently-open modal dialogs, and command execution now reports any dialogs shown while it ran. Main-thread commands are rejected with a busy status while a dialog is open, and status polling reports that a dialog is blocking it. Requires a recent enough trunk build. +- [AUTHAPI-29] Instrument `eval`/`eval_file` usage: each call logs a JSONL record (timing, success, statement/expression shape, and an API fingerprint of top-level member accesses) to `/Library/Pipeline/eval-usage.jsonl`, editor-only and local-first — raw source isn't stored unless `Store Eval Source` is enabled. Toggle via `Eval Telemetry Enabled`. +- [AUTHAPI-29] New `report_evals` command: ranks logged eval fingerprints by frequency and cross-references the command catalog to surface patterns not yet covered by an existing command. +- [AUTHAPI-49] Editor analytics: `Pipeline_SessionStarted` on the first command a client executes, `Pipeline_CommandExecuted` per command executed, and `Pipeline_SessionStopped` when the Editor quits. `isEvalWithExistingCommandAvailable` reuses the AUTHAPI-29 eval fingerprints and coverage map, so it agrees with `report_evals` by construction. Only commands shipped in the package report their name and tags; a project-declared command reports `` and no tags. See `Documentation~/analytics.md`. +- [UUM-149580] `runtime_status` now reports `pipelineDriver` (isServerRunning, actualPort, and the enableInBuilds/requestTimeoutMs/enableAuditLogging/autoStart/maxWorkItemsPerFrame values actually governing the running driver, not just what Project Settings currently shows) — `null` if no driver was ever bootstrapped. +- [UUM-149580] New `get_runtime_pipeline_settings`/`set_runtime_pipeline_settings` commands: structured, `confirm`/`dry_run`-gated read/write access to Pipeline Runtime settings (Project Settings > Pipeline > Runtime), matching the existing Audio/Graphics/Input/Physics/Player/Quality/Time settings command family. Refused while in Play Mode. +- [AUTHAPI-27] New `batch` command: run up to 200 ordered operations in one request, with later ops referencing earlier results. Transactional by default (single Undo step, rolled back on failure); supports `on_error`, `dry_run`, `time_budget_ms`, and detached `job` execution. See `Documentation~/commands/batch.md` for details. +- [AUTHAPI-26] New `run_script` command: compile a single C# file in memory (no domain reload) and execute a named static entry point. Supports `ephemeral` (compile→run→discard) and `hotpatch` modes, JSON-coerced args, custom references/defines, and `dry_run` compilation. Returns `{ result, diagnostics, compileMs, executeMs, assemblyName }`; runtime errors include source `file:line`. +- [AUTHAPI-21] Leaner `/api/exec` responses by default: compact JSON, no null envelope keys, no always-on metadata — a minimal success is just `{"success":true,"result":...}`. Use `"verbose": true` to restore the full envelope, or `"omitNulls": true` to also drop nulls inside `result`. Added `format="value"` to `get_serialized_fields` to return raw values instead of a full descriptor. +- [AUTHAPI-21] New `warnings` array on responses for non-fatal corrective guidance (e.g. an ignored/invalid query parameter). +- [AUTHAPI-21] `/api/job`, `/api/job/cancel`, and `/api/progress` now include null keys explicitly; pass `omit_nulls=true` to drop them. +- [AUTHAPI-21] `POST /api/exec` now rejects a literal JSON `null` body with a structured 400 instead of an internal error. +- Add an IL interpreter (IlInterpreter) that works in IL2CPP players and the editor. Opt in with the `reload_file_editor_interpreter` command or by pushing to a connected device with `reload_file_player_interpreter`; the hot-reload watch always uses it. A shipped Roslyn analyzer (MS002–MS023) marks the supported C# subset in `[HotReload]` method bodies. +- Add an `[OnHotReload]` attribute to react to code being hot-reloaded. +- Add a `.cs` change watcher, enabled from the Pipeline settings, that hot-reloads changed code without a domain reload — in editor play mode, or in a player connected via the profiler connection. + +## [0.5.0-exp.1] - 2026-08-10 + +### Added +- [CLI-488] New `GET /api/progress` endpoint reporting the currently executing command's progress, served off the main thread so it responds even during a blocking command. Command authors report via `CliProgress.Report(...)` or `CliEditorProgress.DisplayProgressBar`; `UnityEditor.Progress` items are mirrored automatically. Powers live progress bars in the `unity` CLI. (with CLI-335) +- [CLI-335] Detached command jobs: `POST /api/exec` with `"job": true` runs in the background and returns a job id immediately; poll `GET /api/job?id=…` for state/progress/result. `POST /api/job/cancel` cancels a queued job or requests cooperative cancellation of a running one via the new `PipelineCancellation` API. Results are retained for 1 hour / last 100 jobs. +- [CLI-488] New `audit`/`audit_status` commands: run a Project Auditor static-analysis scan and poll it, producing an issue CSV. Works via reflection so the package still runs without Project Auditor installed; reports `unavailable` with install guidance when analysis rules are missing. +- [AUTHAPI-35] Report `settling` on `/api/status` and reject main-thread commands with `503 Server Busy` while the Editor is still importing/compiling after a cold start. Background commands (`recompile_status`, `package_status`, `console`, `editor_status`) stay servable throughout. + +### Changed +- [CLI-335] Raised the `eval` timeout cap from 30 seconds to 24 hours. +- [CLI-335] The HTTP server now processes requests concurrently — `/api/status` and `/api/progress` answer immediately even during a long-running command. Command execution itself remains strictly serialized. +- [CLI-335] Hardening: a command's own timeout (not a fixed 60s) governs `/api/exec`'s wait; `editor_status`/`test_status` queue behind the exec gate; progress/job state is scoped per server instance; detached jobs are capped at 100 concurrent (further submissions get `429`). + +### Fixed +- Fixed `executedAt` returning a zero-value instead of the actual execution time for `eval`/`eval_file`, `hot-reload`, and `run_tests`/`test_status`. +- [UUM-148802] Fixed `get_console_logs`/`clear_console`/`console` losing console capture after exiting Play Mode by re-subscribing to Unity's log callback on every play-mode transition. +- [UUM-148605] `set_autotick`'s enabled/interval state now persists across domain reloads via SessionState. Added a `persist` flag (default `true`) to opt out. +- [UUM-149016] Fixed `InvalidOperationException`s after repeated `run_tests` runs caused by a stale `TestResultCollector` still registered with Unity's TestRunnerApi. + +## [0.4.0-exp.1] - 2026-07-23 +- Persist the pipeline server auth token across editor domain reloads so long-lived clients (MCP/IDE) no longer get `401` after a recompile. (CLI-412) +- `capture_game_view` gains a `source` parameter: `camera` (default, unchanged) or `screen`. `source=screen` captures the composited game view backbuffer so Screen Space - Overlay UI (HUDs, menus) is included — the camera path never sees overlay canvases. Screen capture requires Play Mode; in Edit Mode it returns a clear error. (AUTHAPI-10) +- `capture_game_view`/`capture_scene_view` with `save_path` now return a path-only result (no base64) so agent tool results stay small; pass `include_inline_image=true` for the old behavior. Add `max_resolution` to cap the inline image size. (AUTHAPI-8) +- Object-reference string handles now accept authoring-root-relative asset paths (e.g. `Materials/Floor.mat`, not just `Assets/Materials/Floor.mat`): a relative string with a file extension is treated as an asset path and normalized under the authoring root, and a failed lookup now reports every strategy tried instead of a misleading hierarchy-path-only error. (AUTHAPI-9) + +## [0.3.1-exp.1] - 2026-07-16 +- Update docs + +## [0.3.0-exp.1] - 2026-07-13 + +- Improve security by ensuring token usage and enforcing read control on the token. +- Fix all upm-pvp warnings. +- Fix Samples installation. +- All server works if the App is minimized (in the RunInBackground). +- Rework all docs. +- Improve connectivity regaridng IPv4 vs IPv6 support. +- Add `eval_file` command: evaluate C# code read from a `.cs` file on disk, as a file-based alternative to `eval` (which takes inline `code`). Both commands run the source through the same evaluation path. +- Add a large set of Editor automation commands for agentic content-pipeline control: + - **Assets & files:** `create_asset`, `import_asset`, `move_asset`, `copy_asset`, `rename_asset`, `delete_asset`, `find_assets`, `create_folder`, `get_import_settings`, `set_import_settings`, `read_text_file`, `write_text_file`. + - **Scenes:** `create_scene`, `open_scene`, `save_scene`, `save_all`, `list_open_scenes`, `set_active_scene`, `get_scene_hierarchy`, `add_scene_to_build`, `remove_scene_from_build`. + - **GameObjects & components:** `create_gameobject`, `create_gameobjects`, `delete_gameobject`, `find_gameobjects`, `rename_gameobject`, `set_parent`, `set_transform`, `set_active`, `set_tag`, `set_layer`, `add_component`, `remove_component`, `get_component_properties`, `set_component_properties`. + - **Prefabs:** `create_prefab`, `create_prefab_variant`, `instantiate_prefab`, `apply_prefab_overrides`, `revert_prefab_overrides`, `unpack_prefab`, `save_prefab_contents`. + - **Scripts & serialized fields:** `create_script`, `attach_script`, `get_serialized_fields`, `set_serialized_field`. + - **Selection & search:** `get_selection`, `set_selection`, `search`. + - **Capture & screenshots:** `screenshot`, `capture_game_view`, `capture_scene_view`, `capture_editor_element`, `capture_runtime_element`. + - **Build:** `build`, `build_status`. + - **Console & diagnostics:** `console`, `clear_console`, `get_console_logs`, `get_performance_stats`. + - **Editor menus & authoring root:** `menu`, `get_authoring_root`, `set_authoring_root`. + - **Materials & shaders:** `get_material_properties`, `set_material_properties`, `get_shader_properties`, `list_shaders`. + - **Animation & Animator:** `create_animation_clip`, `get_animation_clip`, `set_animation_curve`, `remove_animation_curve`, `create_animator_controller`, `get_animator_controller`, `add_animator_layer`, `add_animator_parameter`, `add_animator_state`, `add_animator_transition`. + - **Timeline:** `create_timeline`, `get_timeline`, `add_timeline_track`, `add_timeline_clip`. + - **Lighting:** `bake_lighting`, `cancel_lighting_bake`, `lighting_bake_status`, `clear_baked_lighting`, `get_lighting_settings`, `set_lighting_settings`. + - **NavMesh:** `bake_navmesh`, `bake_navmesh_surfaces`, `cancel_navmesh_bake`, `navmesh_bake_status`, `clear_navmesh`, `get_navmesh_settings`, `set_navmesh_settings`. + - **Occlusion culling:** `bake_occlusion_culling`, `cancel_occlusion_bake`, `occlusion_bake_status`, `clear_occlusion_culling`. +- Update Wrench +- Warn user if Unity Editor is started in non-automated mode. + +## [0.2.0-exp.2] - 2026-06-24 + +- Fix security audit flaws +- First official published version + +## [0.1.0-exp.1] - 2026-06-09 + +### This is the first release of _Unity Pipeline_. diff --git a/AIClient/Packages/com.unity.pipeline/CHANGELOG.md.meta b/AIClient/Packages/com.unity.pipeline/CHANGELOG.md.meta new file mode 100644 index 0000000..5411dc5 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/CHANGELOG.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 75cd0dccc034c6543afb4f969beca6af +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/CLAUDE.md b/AIClient/Packages/com.unity.pipeline/CLAUDE.md new file mode 100644 index 0000000..c271ad0 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/CLAUDE.md @@ -0,0 +1,64 @@ +# com.unity.pipeline + +Unity package for **remote-controlling a running Unity Editor (or dev Player) over HTTP**. +A client — CLI, CI, or an agent — connects and executes registered commands: recompile, +run tests, eval C#, code-reload files, play-mode control, status/heartbeat. + +## Layout (standard UPM package) + +| Folder | Assembly | Notes | +|--------|----------|-------| +| `Runtime/` | `Unity.Pipeline` | Ships in **development** player builds only (`defineConstraints: UNITY_EDITOR \|\| DEVELOPMENT_BUILD \|\| ENABLE_RUNTIME_PIPELINE`). HTTP server base, command registry, models, runtime commands, code reload, player server. | +| `Runtime/Attributes/` | `Unity.Pipeline.Attributes` | The `[CodeReload]` / `[OnCodeReload]` attributes, **unconstrained** so user code tagged with them still compiles for release builds (where they are inert — nothing weaves them). | +| `Runtime/IlInterpreter/` | `Unity.Pipeline.IlInterpreter` | IL interpreter (IlInterpreter VM) that executes eval snippets and reloaded method bodies where `Reflection.Emit` is unavailable (IL2CPP). Referenced by both `Unity.Pipeline` and `Unity.Pipeline.Editor`. | +| `Runtime/Analyzers/` | — | Shipped `IlInterpreterAnalyzer.dll` — Roslyn analyzer (MS002–MS023) surfacing the interpreter's C# subset on `[CodeReload]` method bodies. Built from `IlInterpreter/analyzer/` at the repo root (see its `README.md`); auto-synced on Release builds — never edit the DLL by hand. | +| `Editor/` | `Unity.Pipeline.Editor` | Editor-only. Live server + its owner, settings asset, editor commands, test runner, code-reload watcher, build processors (`Editor/BuildProcessors/`, incl. the code-reload `link.xml` generator). | +| `CodeGen/` | `Unity.Pipeline.CodeGen` | ILPostProcessor (Mono.Cecil) for in-place code reload. Root-level by Unity convention (cf. Burst/Entities) — leave as-is. | +| `Tests/Editor/` | `Unity.Pipeline.Tests.Editor` | **EditMode** suite (the main one). | +| `Tests/Runtime/` | `Unity.Pipeline.Tests.Runtime` | **PlayMode** suite. | +| `Samples~/` | — | Code-reload sample scenes. | + +## Architecture entry points + +- **`Runtime/Common/BasePipelineServer.cs`** — shared HTTP listener + routing (`/api/exec`, + `/api/status`, `/api/commands`, …). Subclassed by `Editor/EditorPipelineServer.cs` and + `Runtime/PlayerSupport/RuntimePipelineServer.cs`. +- **`Editor/EditorPipelineStartup.cs`** (`PipelineServerStartup`) — `[InitializeOnLoad]` static + owner of the live editor server; survives domain reloads; auto-enables autotick. +- **`Editor/EditorPipelineManager.cs`** — inspectable settings asset (`Window/Pipeline/Settings...` menu). +- Commands are discovered via `[CliCommand]` attributes. Editor command groups live under + `Editor/Commands/` (Assets, Scenes, GameObjects, Prefabs, Scripts, Build, PackageManager, + ProjectSettings, …); runtime commands under `Runtime/`. +- **Interpreter path (IL2CPP-safe eval & code reload)** — `Runtime/IlInterpreter/ScriptInterpreter.cs` + is the VM core; `Runtime/Compilation/IlInterpreterHostBindings.cs` (`CreateStandard()`) builds the + host surface it may call — consumed by eval, code reload, and the `link.xml` generator + (`Editor/BuildProcessors/CodeReloadLinkXmlGenerator.cs`); see the repo-root `CONTEXT.md` glossary + for the drift invariant. `Runtime/Compilation/InterpreterCodeReloadExecutor.cs` routes reloaded + method bodies into the VM; `Editor/EditorCodeReloadWatcher.cs` owns the file-watch → push-reload + loop. +- **`Editor/Authoring/`** — helpers shared by state-changing commands: `AuthoringUndoScope` + (collapses a command's `Undo`-registered mutations into one step) and `ProjectPaths`/`ObjectResolver` + (authoring-root path resolution + object handles). + Destructive/overwriting commands gate on `confirm`/`dry_run` inline (see `delete_asset`). Structured + multi-field command args implement `IStructuredCommandInput` (`Runtime/Common/`). See + `Documentation~/safety-and-mutations.md`, `Documentation~/authoring-commands.md`, and + `Documentation~/creating-commands.md`. + +## Driving & verifying (agents) + +Use the **`unity-pipeline` skill**, which drives the live editor via the `unity` CLI. +Canonical verb is `command`; the auth token is the `evalToken` field inside the port file +`/Library/Pipeline/.unity-pipeline-port`, sent as `Authorization: Bearer `. + +Edit→verify loop: make a logical change (may span several files) → `command recompile` → +poll `command recompile_status` → `command run_tests --filter `. The server keeps the +editor ticking while unfocused, so compiles proceed even when focus is elsewhere. + +## Conventions + +- Private instance fields: `m_PascalCase`. Private static fields: `s_PascalCase`. Consts: `PascalCase`. + Exception: `Runtime/IlInterpreter/` keeps its `_camelCase` style. +- Don't `git commit`/`push` without an explicit request. +- Changelog entries: `[JIRA-KEY] ` in Unreleased. No justification/why — state what changed, stop. + Plain English, minimal code snippets/API names — describe the change, don't quote the implementation. + diff --git a/AIClient/Packages/com.unity.pipeline/CLAUDE.md.meta b/AIClient/Packages/com.unity.pipeline/CLAUDE.md.meta new file mode 100644 index 0000000..f7d3930 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/CLAUDE.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 6433e36ff8e1bc44fb3cde740ee86080 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/CODEOWNERS b/AIClient/Packages/com.unity.pipeline/CODEOWNERS new file mode 100644 index 0000000..3c2cce5 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/CODEOWNERS @@ -0,0 +1,2 @@ +# see https://github.com/Unity-Technologies/com.unity.pipeline for more information +* @Unity-Technologies/core-authoring \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/CODEOWNERS.meta b/AIClient/Packages/com.unity.pipeline/CODEOWNERS.meta new file mode 100644 index 0000000..629037e --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/CODEOWNERS.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: cbc57dbad3c6f114d94ced75a1f9737d +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/CodeGen.meta b/AIClient/Packages/com.unity.pipeline/CodeGen.meta new file mode 100644 index 0000000..1713e89 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/CodeGen.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8b1d193bfb6e52d44975ae298a3c060a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/CodeGen/CodeReloadInPlaceILPostProcessor.cs b/AIClient/Packages/com.unity.pipeline/CodeGen/CodeReloadInPlaceILPostProcessor.cs new file mode 100644 index 0000000..0187c64 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/CodeGen/CodeReloadInPlaceILPostProcessor.cs @@ -0,0 +1,460 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.Cecil.Rocks; +using Unity.CompilationPipeline.Common.Diagnostics; +using Unity.CompilationPipeline.Common.ILPostProcessing; + +namespace Unity.Pipeline.CodeGen +{ + /// + /// Weaves a code-reload dispatch prologue into every method tagged [CodeReload] at compile + /// time, so a running method can route to a reloaded override with no domain reload. The + /// injected prologue is: + /// + /// if (CodeReloadRegistry.TryInvokeCodeReload("Type.Method", this, args)) return; + /// // ... original body ... + /// + /// Weaves instance AND static methods (a static method dispatches with a null instance), + /// returning void, a value (via TryInvokeCodeReloadResult), or a System.Collections.IEnumerator + /// coroutine. Parameters are supported (boxed into object[]). Only IEnumerable/generic + /// iterator returns are skipped with a diagnostic. + /// + class CodeReloadInPlaceILPostProcessor : ILPostProcessor + { + private const string RuntimeAssemblyName = "Unity.Pipeline"; + // Full name: a user attribute merely named CodeReloadAttribute must not get a dispatch + // prologue — runtime discovery checks the real type, so its overrides would never bind. + private const string AttributeFullName = "Unity.Pipeline.CodeReload.CodeReloadAttribute"; + private const string RegistryTypeFullName = "Unity.Pipeline.CodeReload.CodeReloadRegistry"; + private const string DispatchMethodName = "TryInvokeCodeReload"; + private const string ResultDispatchMethodName = "TryInvokeCodeReloadResult"; + private const string HasOverrideMethodName = "HasOverride"; + private const string ThrowNullResultMethodName = "ThrowOverrideReturnedNull"; + + /// Unity requires a fresh instance per compilation; this processor is stateless, so returns itself. + /// This instance. + public override ILPostProcessor GetInstance() => this; + + /// Whether this assembly should be woven: only those referencing the runtime assembly can use [CodeReload]. + /// The assembly about to be processed. + /// True if the assembly references the Unity.Pipeline runtime assembly. + public override bool WillProcess(ICompiledAssembly compiledAssembly) + { + // Only assemblies that reference the runtime assembly can use [CodeReload] or call + // the registry. This naturally excludes the runtime assembly itself (it does not + // reference itself) and the CodeGen assembly (no runtime reference). + return compiledAssembly.References.Any( + r => Path.GetFileNameWithoutExtension(r) == RuntimeAssemblyName); + } + + /// Weave the code-reload dispatch prologue into every [CodeReload] method in the assembly. + /// The assembly to process. + /// The woven assembly bytes plus any diagnostics. + public override ILPostProcessResult Process(ICompiledAssembly compiledAssembly) + { + var diagnostics = new List(); + + using (var resolver = new PostProcessorAssemblyResolver(compiledAssembly.References)) + using (var assembly = ReadAssembly(compiledAssembly, resolver)) + { + var module = assembly.MainModule; + + var targets = module.GetTypes() + .SelectMany(t => t.Methods) + .Where(m => m.HasBody && m.CustomAttributes.Any(a => a.AttributeType.FullName == AttributeFullName)) + .ToList(); + + // A user attribute merely NAMED CodeReloadAttribute never weaves (full-name match + // above) — say so, or the author of a [CodeReload] imported from the wrong + // namespace debugs a silent no-op. Runs before the targets early-out: a module + // whose only tagged methods carry the impostor still gets the warning. + WarnForeignCodeReloadAttributes(module, diagnostics); + + if (targets.Count == 0) + return new ILPostProcessResult(null, diagnostics); + + // Resolve failures below leave every [CodeReload] method unwoven — the per-cause + // warning alone reads like a detail, so state the consequence explicitly. + var dispatch = ResolveDispatchMethod(module, resolver, diagnostics); + var hasOverride = dispatch == null ? null : ResolveHasOverrideMethod(module, resolver, diagnostics); + if (dispatch == null || hasOverride == null) + { + diagnostics.Add(Warn($"{targets.Count} [CodeReload] method(s) in {module.Name} were NOT woven — " + + "code reload will not work for this assembly (see the preceding warning for the cause).")); + return new ILPostProcessResult(null, diagnostics); + } + + // Value-returning [CodeReload] methods dispatch through the out-result overload; may be + // absent in an older runtime, in which case those methods are skipped (below). + var resultDispatch = ResolveResultDispatchMethod(module, resolver, diagnostics); + + // Guard helper for value-type returns (see WeaveDispatchPrologue); absent in an + // older runtime, in which case the unguarded (pre-existing) IL is woven. + var throwNullResult = ResolveThrowNullResultMethod(module, resolver, diagnostics); + + int wovenCount = 0; + foreach (var method in targets) + { + bool isVoid = method.ReturnType.MetadataType == MetadataType.Void; + + // Coroutines returning System.Collections.IEnumerator weave like any other + // value-returning method: the woven stub dispatches at iterator CREATION + // (per StartCoroutine call), and the override's state machine — compiled + // (Mono) or interpreted via the ScriptEnumerator bridge (IL2CPP) — is what + // the scheduler drives. IEnumerable/generic iterator returns stay excluded: + // nothing in the coroutine workflow produces them and the interpreter bridge + // only implements non-generic IEnumerator. + if (!isVoid && IsExcludedIteratorReturn(method.ReturnType)) + { + diagnostics.Add(Warn($"[CodeReload] '{method.FullName}' returns an IEnumerable or generic iterator and was skipped (coroutines must return System.Collections.IEnumerator).")); + continue; + } + + if (!isVoid && resultDispatch == null) + { + diagnostics.Add(Warn($"[CodeReload] '{method.FullName}' returns a value but the runtime has no {ResultDispatchMethodName}; skipped.")); + continue; + } + + WeaveDispatchPrologue(method, dispatch, resultDispatch, hasOverride, throwNullResult); + wovenCount++; + } + + if (wovenCount == 0) + return new ILPostProcessResult(null, diagnostics); + + return new ILPostProcessResult(WriteAssembly(assembly), diagnostics); + } + } + + /// + /// Warn for every method tagged with an attribute that shares the simple name + /// CodeReloadAttribute but is not the Unity.Pipeline one: it gets no dispatch prologue by + /// design (runtime discovery checks the real type), and without the warning that reads as + /// code reload silently not working. + /// + private static void WarnForeignCodeReloadAttributes(ModuleDefinition module, List diagnostics) + { + foreach (var method in module.GetTypes().SelectMany(t => t.Methods)) + { + if (!method.HasCustomAttributes) + continue; + var impostor = method.CustomAttributes.FirstOrDefault(a => + a.AttributeType.Name == "CodeReloadAttribute" && + a.AttributeType.FullName != AttributeFullName); + if (impostor != null) + diagnostics.Add(Warn($"'{method.FullName}' is tagged [{impostor.AttributeType.FullName}], " + + $"which is not {AttributeFullName} — no dispatch prologue was woven, code reload will not apply to it.")); + } + } + + /// True for System.Nullable`1, whose unbox.any accepts null (empty Nullable). + private static bool IsNullable(TypeReference rt) + => rt is GenericInstanceType git && git.ElementType.FullName == "System.Nullable`1"; + + /// True for the iterator returns that stay excluded from weaving: IEnumerable + /// (both) and generic IEnumerator`1. Plain System.Collections.IEnumerator — the Unity + /// coroutine shape — weaves through the result dispatch (see the weave site). + private static bool IsExcludedIteratorReturn(TypeReference rt) + { + var name = rt.GetElementType().FullName; + return name == "System.Collections.IEnumerable" + || name == "System.Collections.Generic.IEnumerator`1" + || name == "System.Collections.Generic.IEnumerable`1"; + } + + /// + /// Inject, at the very top of the method: + /// if (CodeReloadRegistry.HasOverride("Type.Method") + /// && CodeReloadRegistry.TryInvokeCodeReload("Type.Method", this, args)) return; + /// + /// The HasOverride guard is a cheap dictionary lookup that runs first, so the (boxed) argument + /// array is only built when an override is actually active — a woven method with no override + /// allocates nothing per call. + /// + private static void WeaveDispatchPrologue( + MethodDefinition method, MethodReference dispatch, MethodReference resultDispatch, + MethodReference hasOverride, MethodReference throwNullResult) + { + var body = method.Body; + body.SimplifyMacros(); + + var il = body.GetILProcessor(); + var first = body.Instructions[0]; + var methodId = $"{method.DeclaringType.Name}.{method.Name}"; + bool isVoid = method.ReturnType.MetadataType == MetadataType.Void; + + // A value-returning method holds the dispatched result in a local, then unboxes it. + VariableDefinition resultLocal = null; + if (!isVoid) + { + resultLocal = new VariableDefinition(method.Module.TypeSystem.Object); + body.Variables.Add(resultLocal); + } + + var prologue = new List + { + // Guard: skip straight to the original body (no allocation) when no override is active. + Instruction.Create(OpCodes.Ldstr, methodId), + Instruction.Create(OpCodes.Call, hasOverride), + Instruction.Create(OpCodes.Brfalse, first), + // An override exists: build the dispatch call and its argument array. + Instruction.Create(OpCodes.Ldstr, methodId), + // The dispatch's instance argument: `this`, or null for a static method (the + // override ABI keeps a leading instance parameter either way; it arrives null). + method.IsStatic + ? Instruction.Create(OpCodes.Ldnull) + : Instruction.Create(OpCodes.Ldarg_0), + }; + + // Build the object[] of parameters (null when parameterless). + var ps = method.Parameters; + if (ps.Count == 0) + { + prologue.Add(Instruction.Create(OpCodes.Ldnull)); + } + else + { + prologue.Add(Instruction.Create(OpCodes.Ldc_I4, ps.Count)); + prologue.Add(Instruction.Create(OpCodes.Newarr, method.Module.TypeSystem.Object)); + for (int i = 0; i < ps.Count; i++) + { + prologue.Add(Instruction.Create(OpCodes.Dup)); + prologue.Add(Instruction.Create(OpCodes.Ldc_I4, i)); + prologue.Add(Instruction.Create(OpCodes.Ldarg, ps[i])); + if (ps[i].ParameterType.IsValueType || ps[i].ParameterType.IsGenericParameter) + prologue.Add(Instruction.Create(OpCodes.Box, ps[i].ParameterType)); + prologue.Add(Instruction.Create(OpCodes.Stelem_Ref)); + } + } + + if (isVoid) + { + // if (TryInvokeCodeReload(id, this, args)) return; else + prologue.Add(Instruction.Create(OpCodes.Call, dispatch)); + prologue.Add(Instruction.Create(OpCodes.Brfalse, first)); // no override -> run original body + prologue.Add(Instruction.Create(OpCodes.Ret)); // override ran -> skip body + } + else + { + // if (TryInvokeCodeReloadResult(id, this, args, out object r)) return (TRet)r; else + prologue.Add(Instruction.Create(OpCodes.Ldloca, resultLocal)); // out object result + prologue.Add(Instruction.Create(OpCodes.Call, resultDispatch)); + prologue.Add(Instruction.Create(OpCodes.Brfalse, first)); // no override -> run original body + var loadResult = Instruction.Create(OpCodes.Ldloc, resultLocal); + // A null result cannot unbox to a value type — without this guard the unbox.any + // below throws an opaque NullReferenceException at the call site. Nullable + // stays unguarded: unbox.any legitimately converts null to an empty Nullable. + if (throwNullResult != null && method.ReturnType.IsValueType && !IsNullable(method.ReturnType)) + { + prologue.Add(Instruction.Create(OpCodes.Ldloc, resultLocal)); + prologue.Add(Instruction.Create(OpCodes.Brtrue, loadResult)); + prologue.Add(Instruction.Create(OpCodes.Ldstr, methodId)); + prologue.Add(Instruction.Create(OpCodes.Call, throwNullResult)); // never returns + } + prologue.Add(loadResult); + // unbox.any handles both value types (unbox) and reference types (castclass). + prologue.Add(Instruction.Create(OpCodes.Unbox_Any, method.ReturnType)); + prologue.Add(Instruction.Create(OpCodes.Ret)); // override ran -> return its result + } + + foreach (var instr in prologue) + il.InsertBefore(first, instr); + + body.OptimizeMacros(); + } + + /// + /// Resolve a CodeReloadRegistry method (static, non-generic; picks + /// the overload) from the runtime assembly and import it into the target module. + /// is the warning added when the registry or the method + /// can't be found; null makes absence silent — for overloads an older runtime may not have. + /// + private static MethodReference ResolveRegistryMethod( + ModuleDefinition module, PostProcessorAssemblyResolver resolver, List diagnostics, + Func match, string missingMessage) + { + var runtimeRef = module.AssemblyReferences.FirstOrDefault(a => a.Name == RuntimeAssemblyName); + if (runtimeRef == null) + { + if (missingMessage != null) + diagnostics.Add(Warn($"Could not find a reference to {RuntimeAssemblyName} while weaving {module.Name}.")); + return null; + } + + var runtime = resolver.Resolve(runtimeRef); + var registry = runtime?.MainModule.GetType(RegistryTypeFullName); + if (registry == null) + { + if (missingMessage != null) + diagnostics.Add(Warn($"Could not resolve {RegistryTypeFullName} in {RuntimeAssemblyName}.")); + return null; + } + + var method = registry.Methods.FirstOrDefault(m => m.IsStatic && !m.HasGenericParameters && match(m)); + if (method == null) + { + if (missingMessage != null) + diagnostics.Add(Warn(missingMessage)); + return null; + } + + return module.ImportReference(method); + } + + /// + /// Resolve CodeReloadRegistry.TryInvokeCodeReload(string, object, object[]) from the runtime + /// assembly and import it into the target module. + /// + private static MethodReference ResolveDispatchMethod( + ModuleDefinition module, PostProcessorAssemblyResolver resolver, List diagnostics) + { + return ResolveRegistryMethod(module, resolver, diagnostics, + m => m.Name == DispatchMethodName && + m.Parameters.Count == 3 && + m.Parameters[0].ParameterType.MetadataType == MetadataType.String && + m.Parameters[1].ParameterType.MetadataType == MetadataType.Object, + $"Could not find non-generic {DispatchMethodName}(string, object, object[]) on {RegistryTypeFullName}."); + } + + /// + /// Resolve CodeReloadRegistry.TryInvokeCodeReloadResult(string, object, object[], out object) + /// -> bool for value-returning methods. Returns null (not an error) when the runtime predates + /// the overload — callers then skip value-returning methods with a diagnostic. + /// + private static MethodReference ResolveResultDispatchMethod( + ModuleDefinition module, PostProcessorAssemblyResolver resolver, List diagnostics) + { + return ResolveRegistryMethod(module, resolver, diagnostics, + m => m.Name == ResultDispatchMethodName && + m.Parameters.Count == 4 && + m.Parameters[0].ParameterType.MetadataType == MetadataType.String && + m.Parameters[1].ParameterType.MetadataType == MetadataType.Object && + m.Parameters[3].ParameterType.IsByReference, + missingMessage: null); + } + + /// + /// Resolve CodeReloadRegistry.ThrowOverrideReturnedNull(string) — the woven null guard for + /// value-type returns. Resolved from the runtime like the dispatch methods (importing + /// exception types from the post-processor's own corlib would not resolve in a player). + /// Returns null (not an error) when the runtime predates the helper — the unguarded IL is + /// woven then, matching the old behavior. + /// + private static MethodReference ResolveThrowNullResultMethod( + ModuleDefinition module, PostProcessorAssemblyResolver resolver, List diagnostics) + { + return ResolveRegistryMethod(module, resolver, diagnostics, + m => m.Name == ThrowNullResultMethodName && + m.Parameters.Count == 1 && + m.Parameters[0].ParameterType.MetadataType == MetadataType.String, + missingMessage: null); + } + + /// + /// Resolve CodeReloadRegistry.HasOverride(string) -> bool from the runtime assembly and import + /// it into the target module (used by the woven prologue's no-allocation guard). + /// + private static MethodReference ResolveHasOverrideMethod( + ModuleDefinition module, PostProcessorAssemblyResolver resolver, List diagnostics) + { + return ResolveRegistryMethod(module, resolver, diagnostics, + m => m.Name == HasOverrideMethodName && + m.Parameters.Count == 1 && + m.Parameters[0].ParameterType.MetadataType == MetadataType.String && + m.ReturnType.MetadataType == MetadataType.Boolean, + $"Could not find {HasOverrideMethodName}(string) on {RegistryTypeFullName}."); + } + + private static AssemblyDefinition ReadAssembly(ICompiledAssembly compiledAssembly, IAssemblyResolver resolver) + { + var pdb = compiledAssembly.InMemoryAssembly.PdbData; + var hasSymbols = pdb != null && pdb.Length > 0; + + var readerParameters = new ReaderParameters + { + AssemblyResolver = resolver, + ReadingMode = ReadingMode.Immediate, + ReadWrite = true, + ReadSymbols = hasSymbols, + SymbolReaderProvider = hasSymbols ? new PortablePdbReaderProvider() : null, + SymbolStream = hasSymbols ? new MemoryStream(pdb) : null, + }; + + var peStream = new MemoryStream(compiledAssembly.InMemoryAssembly.PeData); + return AssemblyDefinition.ReadAssembly(peStream, readerParameters); + } + + private static InMemoryAssembly WriteAssembly(AssemblyDefinition assembly) + { + var pe = new MemoryStream(); + var pdb = new MemoryStream(); + var writerParameters = new WriterParameters + { + SymbolWriterProvider = new PortablePdbWriterProvider(), + WriteSymbols = true, + SymbolStream = pdb, + }; + + assembly.Write(pe, writerParameters); + return new InMemoryAssembly(pe.ToArray(), pdb.ToArray()); + } + + private static DiagnosticMessage Warn(string message) => new DiagnosticMessage + { + DiagnosticType = DiagnosticType.Warning, + MessageData = "CodeReloadInPlace: " + message, + }; + } + + /// + /// Minimal IAssemblyResolver that resolves referenced assemblies from the compiled assembly's + /// reference paths (which are absolute file paths supplied by the compilation pipeline). + /// + internal sealed class PostProcessorAssemblyResolver : IAssemblyResolver + { + private readonly string[] _referencePaths; + private readonly Dictionary _cache = new Dictionary(); + + public PostProcessorAssemblyResolver(string[] referencePaths) + { + _referencePaths = referencePaths; + } + + public AssemblyDefinition Resolve(AssemblyNameReference name) + => Resolve(name, new ReaderParameters(ReadingMode.Deferred)); + + public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters) + { + lock (_cache) + { + if (_cache.TryGetValue(name.Name, out var cached)) + return cached; + + var path = _referencePaths.FirstOrDefault( + r => Path.GetFileNameWithoutExtension(r) == name.Name); + if (path == null || !File.Exists(path)) + return null; + + parameters.AssemblyResolver = this; + var definition = AssemblyDefinition.ReadAssembly(path, parameters); + _cache[name.Name] = definition; + return definition; + } + } + + public void Dispose() + { + lock (_cache) + { + foreach (var def in _cache.Values) + def.Dispose(); + _cache.Clear(); + } + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/CodeGen/CodeReloadInPlaceILPostProcessor.cs.meta b/AIClient/Packages/com.unity.pipeline/CodeGen/CodeReloadInPlaceILPostProcessor.cs.meta new file mode 100644 index 0000000..3bdc215 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/CodeGen/CodeReloadInPlaceILPostProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3eb482c6630e46b98100dd9c13a3f7d3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/CodeGen/Unity.Pipeline.CodeGen.asmdef b/AIClient/Packages/com.unity.pipeline/CodeGen/Unity.Pipeline.CodeGen.asmdef new file mode 100644 index 0000000..535ad30 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/CodeGen/Unity.Pipeline.CodeGen.asmdef @@ -0,0 +1,21 @@ +{ + "name": "Unity.Pipeline.CodeGen", + "rootNamespace": "Unity.Pipeline.CodeGen", + "references": [], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": true, + "precompiledReferences": [ + "Mono.Cecil.dll", + "Mono.Cecil.Mdb.dll", + "Mono.Cecil.Pdb.dll", + "Mono.Cecil.Rocks.dll" + ], + "autoReferenced": false, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": true +} diff --git a/AIClient/Packages/com.unity.pipeline/CodeGen/Unity.Pipeline.CodeGen.asmdef.meta b/AIClient/Packages/com.unity.pipeline/CodeGen/Unity.Pipeline.CodeGen.asmdef.meta new file mode 100644 index 0000000..2a94d5b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/CodeGen/Unity.Pipeline.CodeGen.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3d86918fcc1e40b8a17542a4bacf8dbc +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Documentation~/TableOfContents.md b/AIClient/Packages/com.unity.pipeline/Documentation~/TableOfContents.md new file mode 100644 index 0000000..1d5add2 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Documentation~/TableOfContents.md @@ -0,0 +1,28 @@ +* [Home](index.md) +* Guides + * [Creating commands](creating-commands.md) + * [Creating authoring commands](authoring-commands.md) + * [Safety & mutations](safety-and-mutations.md) + * [Connectivity](connectivity.md) + * [Runtime connection & setup](runtime-setup.md) + * [Reloading code](code-reload.md) + * [Tests architecture](testing.md) + * [Analytics](analytics.md) +* Command reference + * [Batch command](commands/batch.md) + * [Asset & file commands](commands/assets-and-files.md) + * [Scene commands](commands/scenes.md) + * [GameObject & component commands](commands/gameobjects-and-components.md) + * [Prefab commands](commands/prefabs.md) + * [Script commands](commands/scripts.md) + * [Animation commands](commands/animation.md) + * [Material & shader commands](commands/materials.md) + * [Baking commands](commands/baking.md) + * [Navigation & selection commands](commands/navigation.md) + * [Capture commands](commands/capture.md) + * [Wait commands](commands/wait.md) + * [Build, compilation & test commands](commands/build-and-compilation.md) + * [Project settings commands](commands/project-settings.md) + * [Package Manager commands](commands/package-manager.md) + * [Editor lifecycle & observability commands](commands/editor-lifecycle-and-observability.md) + * [Runtime commands](commands/runtime.md) diff --git a/AIClient/Packages/com.unity.pipeline/Documentation~/analytics.md b/AIClient/Packages/com.unity.pipeline/Documentation~/analytics.md new file mode 100644 index 0000000..86f7604 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Documentation~/analytics.md @@ -0,0 +1,138 @@ +# Analytics + +The Editor server reports how the pipeline is used through Unity's editor analytics +(`EditorAnalytics.SendAnalytic`). The data answers questions the package has no other way to +answer: whether sessions are interactive or automated, which commands clients actually reach for, +how often they fail, how long they take, and how much traffic is raw `eval` rather than a +concrete command. + +Three things bound what is collected: + +- **Editor only.** A server running in a development Player reports nothing — `EditorAnalytics` + does not exist there. +- **The editor's own opt-out applies.** With analytics disabled in Unity preferences, + `SendAnalytic` does nothing and no event leaves the machine. There is no separate pipeline + switch to turn off. +- **Nothing about a command's content is collected.** Not its parameters, not the code passed to + `eval`, not paths, not results. +- **Nothing a project declared about its own commands is collected.** Only commands shipped in the + package report their name and tags; anything a project declared itself reports + `` and no tags — see + [What is and is not collected](#what-is-and-is-not-collected). + +## Events + +### `Pipeline_SessionStarted` + +Sent once when a client executes its first command, which is the moment the pipeline actually +started handling work — not when the Editor launched or the server bound its port. + +| Field | Meaning | +|-------|---------| +| `batchmode` | The Editor was launched with `-batchmode`. | +| `automated` | The Editor was launched with `-automated`. | +| `browserAllowed` | The server accepts sandboxed browser clients (the limited-CORS path). Off unless enabled in the Pipeline settings. | +| `dynamicPortAssignation` | The port was auto-assigned from the server's range rather than pinned in the settings asset. | +| `hotReloadWatcherEnabled` | The `.cs` change watcher is running. | + +A session spans a Unity **process**. The latch lives in `SessionState`, which survives domain +reloads, so a script recompile does not open a second session. + +### `Pipeline_CommandExecuted` + +Sent once per command a client executes. + +| Field | Meaning | +|-------|---------| +| `commandName` | The registered command name — but only for commands that ship with the package. A project-declared command reports the literal `` instead. | +| `commandTags` | The command's tags, in declaration order — but only for commands that ship with the package. Empty for an untagged command, and always empty for a project-declared one. | +| `commandSuccess` | Whether the command succeeded. False both when it threw and when it returned a result carrying its own failure — `eval`, `reload_file`, `run_script` and `run_tests` all report failure the second way. | +| `commandDuration` | Milliseconds spent inside the command, excluding the wait for the one-command-at-a-time gate. | +| `isUserDefinedCommand` | The command was declared by the project rather than shipped in the package. | +| `isEval` | The command is a code evaluation (tagged `scripts/eval`: `eval`, `eval_file`, `run_script`). | +| `isEvalWithExistingCommandAvailable` | Whether the evaluated snippet touches an API that a shipped command already covers — the "you did not need eval for this" signal. Same judgement `report_evals` makes, applied to one invocation: see [How the eval-coverage flag is decided](#how-the-eval-coverage-flag-is-decided). | + +What counts as one execution: + +- One event per `/api/exec` call, including a `job: true` submission — reported when the job + actually **finishes**, not when its job handle is returned. +- A `batch` reports one event, for `batch` itself. Its sub-operations are not reported + individually. +- A request rejected before anything ran (oversized body, malformed JSON, unknown command, + settling host, full job queue) reports nothing: no command executed. +- The internal executions behind `/api/editor_status` and `/api/test-status` report nothing. + Clients poll those endpoints, and the polling would swamp everything else. + +### `Pipeline_SessionStopped` + +Sent when the Editor quits, and only if `Pipeline_SessionStarted` was sent — an Editor that never +served a command closes no session. + +| Field | Meaning | +|-------|---------| +| `sessionDuration` | Milliseconds between the session starting and the Editor quitting. | + +## How the eval-coverage flag is decided + +`isEvalWithExistingCommandAvailable` reuses the eval instrumentation from AUTHAPI-29 rather than +inventing a second opinion. Per invocation: + +1. `EvalUsageFingerprinter.Analyze` turns the snippet into API fingerprints — dotted member-access + paths, with no literals or raw source in them. +2. Each fingerprint is looked up in `EvalCoverageMap.Default`, a small curated hint map from API to + the command that would cover it. +3. The flag is true only if a mapped command is **actually in the live catalog**. A mapping to a + command that does not exist yet (`AssetDatabase.Refresh` → `refresh_assets`) is a gap for + `report_evals` to surface, not an avoidable eval. + +This is deliberately the same rule as `report_evals`' `covered` list, so the two can never disagree. +Two consequences worth knowing when reading the data: + +- **It is a floor, not a measure.** The map has a handful of entries and matching is on the whole + fingerprint, so `PlayerSettings.GetScriptingBackend(...)` matches while + `UnityEditor.PlayerSettings.GetScriptingBackend(...)` and + `PlayerSettings.GetScriptingBackend(...).ToString()` do not — they fingerprint as different paths. + A `false` means "no mapped-and-present command matched", never "no command could cover this". +- **`run_script` always reports `false`.** It runs a project file through a named entry point rather + than a snippet, and the fingerprinter parses script-kind bodies, so it is not fingerprinted. + `eval` (inline body) and `eval_file` (body read back from its file) are judged. + +## What is and is not collected + +A command's name and tags are text the project's own authors wrote, so either can name an +unannounced feature or an internal system. Tags are constrained in shape +(`^[a-z0-9_]+(/[a-z0-9_]+)*$`) and shipped commands must use the documented taxonomy, but nothing +holds a project to it, so a tag carries a project-chosen word exactly as a name does. + +So both are withheld. `commandName` and `commandTags` describe only commands that ship in the +package (`Unity.Pipeline`, `Unity.Pipeline.Editor`); every other `[CliCommand]` reports the literal +`` and an empty tag array. The remaining fields — success, duration, `isEval` — +are facts about the execution, not about what the project called it, so they are reported for every +command. + +What this costs: project-declared traffic is countable but not breakable down by area. That is the +deliberate trade — `isUserDefinedCommand` answers how much of the surface is project-declared, which +is the question worth asking, and nothing identifying is needed to answer it. + +Command **arguments** are never collected. Neither is anything a command reads or writes. + +## Adding post-command work + +Analytics is one consumer of a single seam rather than a special case. When a command finishes, +`BasePipelineServer.OnCommandDone` receives a `CommandExecutionInfo` describing both the raw +transaction and the execution. It runs on the HTTP thread, so `EditorPipelineServer` splits by what +each consumer needs: the transaction log is appended there directly (thread-safe file I/O by +design), and anything needing Unity APIs is handed to the server dispatcher with +`Dispatcher.Post`, which runs it in `OnCommandDoneMainThread` on the next main-thread pump. + +New post-command work goes in one of those two, depending on which thread it needs. `Post` is the +general fire-and-forget counterpart to `Dispatcher.Invoke`: it returns immediately instead of +parking the request thread until the next pump, and swallows-and-logs failures because there is no +caller left to throw to. Work still queued when the server stops is dropped, so a report can be +lost in the frame the Editor quits or reloads its domain. + +## See also + +- [Creating commands](creating-commands.md) — where a command's name and tags come from. +- [Connectivity](connectivity.md) — the port and CORS settings the session event reports. +- [Code reload](code-reload.md) — the watcher whose state the session event reports. diff --git a/AIClient/Packages/com.unity.pipeline/Documentation~/authoring-commands.md b/AIClient/Packages/com.unity.pipeline/Documentation~/authoring-commands.md new file mode 100644 index 0000000..42fc2da --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Documentation~/authoring-commands.md @@ -0,0 +1,319 @@ +# Creating authoring commands + +*Authoring commands* are the subset of commands that **create or mutate project content** — assets, +scenes, GameObjects, components — on behalf of an agent. They build on the base command API in +[Creating commands](creating-commands.md); this page covers the four concerns that are specific to +content authoring: + +- **The authoring root** — the sandbox that bare paths resolve against and writes are confined to. +- **`ObjectRef`** — how a command *receives* a reference to an existing object. +- **`AuthoringResult`** — how a command *returns* the identity of an object it created or touched. +- **Undo/redo** — grouping a command's scene mutations into a single, revertible step. + +Together these let one command's output feed the next command's input, so an agent can chain calls +(`create_gameobject` → `add_component` → `set_component_properties` → `create_prefab`) without ever +handling a raw Unity object itself. If you want to support a content type the package doesn't cover +yet (materials, audio, lighting, terrain, …), this is the pattern to follow. + +Read [Creating commands](creating-commands.md) first — this page assumes you know how `[CliCommand]`, +`[CliArg]`, `MainThreadRequired`, and the response envelope work. + +## Authoring vs. management commands + +Not every state-changing command is an *authoring* command. This page — and the [checklist](#checklist-for-a-new-authoring-command) +at the end — applies to commands that **create or mutate project content** (assets, scenes, +GameObjects, components) and hand the agent back an object identity. + +**Management commands** change *configuration* or *drive tooling* rather than author content: +project settings (`Editor/Commands/ProjectSettings/`), builds (`Build/`), and packages +(`PackageManager/`). They are a **different category** and deliberately do +**not** follow the full authoring contract. They share only the cross-cutting safety conventions +(the `confirm`/`dry_run` gate and, where relevant, `ObjectResolver`/`ProjectPaths`) — see +[Safety & mutations](safety-and-mutations.md). + +| Concern | Authoring command | Management command | +|---|---|---| +| Object input | `ObjectRef` → `ObjectResolver.TryResolve` | same, when it references an object (e.g. a scene in the build list) | +| Path input | `ProjectPaths.Resolve` (confined to the authoring root) | as needed; may be unconfined by design (e.g. a build output path) | +| Undo | scene/object mutations wrapped in `AuthoringUndoScope` + registered `Undo` APIs | **none** — settings / AssetDatabase / UPM writes don't participate in Undo, so no scope; note `Not undoable via Ctrl+Z.` in the description instead | +| Destructive gate | `confirm`/`dry_run` where destructive | `confirm`/`dry_run` where destructive (same convention) | +| Return value | `AuthoringResult` via `ObjectResolver.Describe` | a domain model (e.g. `ProjectSettingsResponse`, `PackageMutationResponse`) or a plain result object | +| Failure | **throw** (`ArgumentException` / `InvalidOperationException`) | throw, **or** return a structured `{ success = false, code, error }` object — consistent within the area | + +If you're adding a config/build/package command, follow the management column and the shared safety +conventions; the checklist below is for content-authoring commands. + +## The building blocks + +| Type | Namespace | Role | +|------|-----------|------| +| `ProjectPaths` | `Unity.Pipeline.Editor.Authoring` | Resolve/confine agent-supplied paths to the authoring root. | +| `ObjectRef` | `Unity.Pipeline.Models` | Input handle to an existing object (asset or scene object). | +| `AuthoringResult` | `Unity.Pipeline.Models` | Output identity of an object your command created or acted on. | +| `ObjectResolver` | `Unity.Pipeline.Editor.Authoring` | `TryResolve(ObjectRef …)` (handle → object) and `Describe(object)` (object → `AuthoringResult`). | +| `AuthoringUndoScope` | `Unity.Pipeline.Editor.Authoring` | Collapses all `Undo`-registered mutations in its lifetime into one editor undo step. | + +Authoring commands are Editor-only. Put them under `Editor/Commands//` in the +`Unity.Pipeline.Editor.Commands.` namespace (see `Editor/Commands/Authoring/AuthoringConfigCommands.cs`). + +## The authoring root (`set_authoring_root`) + +Agents pass **bare, relative paths** (`"Materials/Stone"`), not full project paths. `ProjectPaths` +resolves those against a configurable **authoring root** and *confines* every write to it. The root +defaults to `Assets` (full project access); an agent can narrow it to a sub-folder to sandbox itself: + +``` +get_authoring_root → { "root": "Assets" } +set_authoring_root --root Assets/AgentWork +``` + +These are just thin commands over `ProjectPaths.AuthoringRoot` (`Editor/Commands/Authoring/AuthoringConfigCommands.cs`): + +```csharp +[CliCommand("set_authoring_root", "Set the base folder (under Assets/) that bare authoring paths resolve against and are confined to. Use 'Assets' for full project access.")] +public static object SetAuthoringRoot( + [CliArg("root", "Project-relative folder under Assets/, e.g. Assets/AgentWork. Use 'Assets' to allow the whole project.", Required = true)] string root) +{ + // Throws ArgumentException for invalid roots (outside Assets/ or containing ".."); the + // server surfaces that message to the caller. + ProjectPaths.AuthoringRoot = root; + return new { root = ProjectPaths.AuthoringRoot }; +} +``` + +**Every path parameter your command accepts must go through `ProjectPaths.Resolve`.** This is the +sandbox boundary — it rejects `..` traversal and anything that escapes the root, and it lets callers +omit the `Assets/` prefix. Do not build asset paths by string concatenation. + +```csharp +var normalized = ProjectPaths.Resolve(path, out var error); +if (normalized == null) + throw new ArgumentException(error); // e.g. "Path '../secrets' must not contain '..'." +// normalized is now a project-relative path guaranteed to live under the authoring root. +``` + +Resolution rules (`Editor/Authoring/ProjectPaths.cs`): + +- Bare paths (`"Materials/Stone"`) are taken relative to the root → `Assets/AgentWork/Materials/Stone`. +- Explicit `Assets/…` / `Packages/…` paths are used as-is (but still confined to the root). +- Absolute paths must live under the project root and are converted to project-relative. +- `..` anywhere, or a result outside the root, returns `null` + an `error` string. + +## Receiving objects: `ObjectRef` + +When a command needs to act on an object that *already* exists, take an `ObjectRef` parameter. The +agent supplies **one** of several forms; `ObjectResolver.TryResolve` tries them in order — `globalId`, +`path`, `guid` (+ optional `fileId`), `instanceId`, `hierarchyPath` — and hands you the live object: + +```csharp +public static Renderer ResolveRenderer(ObjectRef target) +{ + if (!ObjectResolver.TryResolve(target, out var obj, out var error)) + throw new ArgumentException(error); + + var go = obj as GameObject ?? (obj as Component)?.gameObject; + var renderer = go != null ? go.GetComponent() : null; + if (renderer == null) + throw new ArgumentException($"Object '{target}' has no Renderer."); + return renderer; +} +``` + +Resolve **outside** any undo scope / before mutating, so a bad handle fails before your command +changes anything (see `create_gameobject`, which resolves its `parent` before entering the scope). + +When the handle is a plain string (the usual agent input), a value with a file extension and no +leading `/` — e.g. `"Materials/Floor.mat"` — is taken as an asset path and normalized under the +authoring root, so the `Assets/` prefix is optional (mirroring path-taking commands). A leading `/` +or an extension-less value stays a `hierarchyPath`; a dotted scene name like `"Cube.001"` still +resolves because the `path` branch falls back to a hierarchy lookup. + +## Returning objects: `AuthoringResult` + +Any command that creates or modifies an object should return its identity so the agent can reference +it in a follow-up call. Don't build this by hand — call `ObjectResolver.Describe(obj)`, which fills in +the right fields for the object kind: + +- **Assets** get `assetPath`, `guid`, `fileId`, `type` (+ `globalId`). +- **Scene / loaded objects** get `instanceId`, `hierarchyPath`, `type` (+ `globalId`). + +```csharp +var result = ObjectResolver.Describe(asset) ?? new AuthoringResult { Type = nameof(Material) }; +result.AssetPath = assetPath; // ensure the path is set even if Describe returned a fresh result +return result; +``` + +`AuthoringResult` is **identity only** — no success flag, no message. Success/failure and timing live +in the outer `CommandExecutionResponse` (the server adds them). To report a failure, **throw** +(`ArgumentException` for bad input, `InvalidOperationException` for an operation that failed); the +server converts the exception into a failure envelope. For a batch, return a model that holds an +`AuthoringResult[]` (see `CreateGameObjectsResult`). + +## Undo/redo + +Undo is Unity's native `UnityEditor.Undo`, grouped per command by `AuthoringUndoScope` so a single +call reverts as a single Ctrl+Z step. Register each mutation with the matching `Undo` API **inside** +the scope: + +```csharp +using (new AuthoringUndoScope("Set Material")) +{ + Undo.RecordObject(renderer, "Set Material"); // record BEFORE mutating + renderer.sharedMaterial = material; + EditorSceneManager.MarkSceneDirty(renderer.gameObject.scene); +} +``` + +Which `Undo` call to use: + +| Mutation | Call | +|----------|------| +| New scene object | `Undo.RegisterCreatedObjectUndo(obj, name)` | +| Change fields on an existing object | `Undo.RecordObject(obj, name)` / `RegisterCompleteObjectUndo` (before the change) | +| Add a component | `Undo.AddComponent(go, type)` | +| Reparent | `Undo.SetTransformParent(child, parent, name)` | +| Serialized properties | `SerializedObject` + `so.ApplyModifiedProperties()` (registers undo itself) | + +> **Important caveat.** `AssetDatabase` operations are **not** part of Unity's undo system. Creating a +> folder or asset, importing, `AssetDatabase.CreateAsset`, `SaveAsPrefabAsset`, and file writes are +> **not undone** by Ctrl+Z. `AuthoringUndoScope` only covers scene/object mutations. If your command +> writes to disk, say so in its description and don't rely on undo to clean up — validate up front and +> fail before writing. + +## Worked example — a new content type + +Say the package has no material (rendering) commands and you want to add them. Two commands cover the +whole pattern: one that **creates an asset** (path handling + `AuthoringResult` out, no undo because +it's an `AssetDatabase` op) and one that **mutates a scene object** (`ObjectRef` in + undo). + +```csharp +using System.IO; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Models; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; + +namespace Unity.Pipeline.Editor.Commands.Rendering +{ + /// Authoring commands for materials (rendering). + public static class MaterialCommands + { + [CliCommand("create_material", + "Create a Material asset (default shader 'Standard') under the authoring root. " + + "NOTE: asset creation is not undoable via Ctrl+Z.")] + public static AuthoringResult CreateMaterial( + [CliArg("path", "Asset path relative to the authoring root; the Assets/ prefix and the .mat extension are optional. e.g. Materials/Stone", Required = true)] string path, + [CliArg("shader", "Shader name to assign. Defaults to 'Standard'.")] string shader = "Standard") + { + // 1. Resolve + confine the path (the sandbox boundary). + var normalized = ProjectPaths.Resolve(path, out var error); + if (normalized == null) + throw new ArgumentException(error); + if (!normalized.EndsWith(".mat", System.StringComparison.OrdinalIgnoreCase)) + normalized += ".mat"; + + var found = Shader.Find(shader); + if (found == null) + throw new ArgumentException($"Shader '{shader}' was not found."); + + // 2. Do the work (AssetDatabase op — no undo scope; it wouldn't be undoable anyway). + EnsureParentFolder(normalized); + var material = new Material(found); + AssetDatabase.CreateAsset(material, normalized); + AssetDatabase.SaveAssets(); + + // 3. Return the created object's identity so the agent can reference it next. + var result = ObjectResolver.Describe(material) ?? new AuthoringResult { Type = nameof(Material) }; + result.AssetPath = normalized; + return result; + } + + [CliCommand("set_material", "Assign a material asset to a Renderer on a scene GameObject.")] + public static AuthoringResult SetMaterial( + [CliArg("target", "Handle of the GameObject (or Renderer) to modify.", Required = true)] ObjectRef target, + [CliArg("material", "Handle of the material asset to assign (path/guid/globalId).", Required = true)] ObjectRef material) + { + // Resolve both handles up front, before mutating, so a bad handle changes nothing. + var renderer = ResolveRenderer(target); + if (!ObjectResolver.TryResolve(material, out var matObj, out var matError)) + throw new ArgumentException(matError); + if (matObj is not Material mat) + throw new ArgumentException($"'{material}' is not a Material."); + + using (new AuthoringUndoScope("Set Material")) + { + Undo.RecordObject(renderer, "Set Material"); // record BEFORE the change + renderer.sharedMaterial = mat; + EditorSceneManager.MarkSceneDirty(renderer.gameObject.scene); + } + + return ObjectResolver.Describe(renderer); + } + + private static Renderer ResolveRenderer(ObjectRef target) + { + if (!ObjectResolver.TryResolve(target, out var obj, out var error)) + throw new ArgumentException(error); + + var go = obj as GameObject ?? (obj as Component)?.gameObject; + var renderer = go != null ? go.GetComponent() : null; + if (renderer == null) + throw new ArgumentException($"Object '{target}' has no Renderer."); + return renderer; + } + + // Mirrors the shared helper used by the built-in asset commands. + private static void EnsureParentFolder(string assetPath) + { + var parent = Path.GetDirectoryName(assetPath)?.Replace('\\', '/'); + if (string.IsNullOrEmpty(parent) || AssetDatabase.IsValidFolder(parent)) + return; + // Create intermediate folders (see create_folder / CreateFolderRecursive). + Directory.CreateDirectory(ProjectPaths.ProjectRoot + "/" + parent); + AssetDatabase.Refresh(); + } + } +} +``` + +An agent chains them by feeding the first result into the second: + +``` +create_material --path Materials/Stone --shader Standard + → { "assetPath": "Assets/AgentWork/Materials/Stone.mat", "guid": "…", "type": "Material" } + +set_material --target '{"hierarchyPath":"/Ground"}' --material '{"path":"Assets/AgentWork/Materials/Stone.mat"}' + → { "instanceId": …, "hierarchyPath": "/Ground", "type": "MeshRenderer" } +``` + +## Checklist for a new authoring command + +For *content-authoring* commands. Config/build/package commands follow the lighter +[management-command conventions](#authoring-vs-management-commands) instead. + +- [ ] Editor-only, under `Editor/Commands//`, `static` (any accessibility — `public`/`internal`/`private`), tagged `[CliCommand]`. +- [ ] Every path parameter resolved through `ProjectPaths.Resolve` (never concatenated). +- [ ] Existing-object inputs taken as `ObjectRef`, resolved via `ObjectResolver.TryResolve`; resolve **before** mutating. +- [ ] Scene/object mutations wrapped in an `AuthoringUndoScope` and registered with the matching `Undo` API. +- [ ] `AssetDatabase` writes noted as non-undoable in the description; validate before writing. +- [ ] Returns `AuthoringResult` (via `ObjectResolver.Describe`) or a model containing `AuthoringResult[]`. +- [ ] Reports failures by throwing; never build the response envelope yourself. + +## Build & verify + +New commands register automatically after the next recompile (see +[Creating commands → Discovery](creating-commands.md#discovery)). Drive the live editor to verify: + +``` +command recompile +command recompile_status # poll until done +command create_material --path Materials/Stone +``` + +## See also + +- [Creating commands](creating-commands.md) — the base command API this page builds on. +- [Asset & file commands](commands/assets-and-files.md) — reference for the built-in asset commands. +- [GameObject & component commands](commands/gameobjects-and-components.md) — the scene-mutation commands. diff --git a/AIClient/Packages/com.unity.pipeline/Documentation~/code-reload.md b/AIClient/Packages/com.unity.pipeline/Documentation~/code-reload.md new file mode 100644 index 0000000..0c81380 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Documentation~/code-reload.md @@ -0,0 +1,177 @@ +# Reloading Code + +Update C# methods with the `[CodeReload]` attribute without restarting Play Mode in the editor or rebuilding the Player. Two backends are supported: + +| Command | Backend | Where | Language | Pipeline server needed in player | +|---------|---------|-------|----------|----------------------------------| +| `reload_file` | `Assembly.Load` (default) | Editor Play Mode, Desktop Mono dev builds | Full C# | yes | +| `reload_file_editor_interpreter`, `reload_file_player_interpreter` | IlInterpreter | Any dev build, **including IL2CPP** | A C# subset (see [constraints](#interpreter-constraints)) | no | + +The watch UI and device pushes always use the interpreter: an IL2CPP player has no Roslyn and no `Assembly.Load`, so the editor compiles and the device interprets. Code reload is gated to the editor and development builds (`UNITY_EDITOR || DEVELOPMENT_BUILD || ENABLE_RUNTIME_PIPELINE`) — the whole `Unity.Pipeline` assembly carries that define constraint, so a release build contains none of it unless you opt in with `ENABLE_RUNTIME_PIPELINE` (see `runtime-setup.md`). `[CodeReload]` itself lives in the unconstrained `Unity.Pipeline.Attributes` assembly, so a tagged method still compiles for a release build; it simply runs its original body, with no dispatch prologue woven in. + +## Tagging a method + +Tag the method you want to reload with `[CodeReload]`: + +```csharp +using Unity.Pipeline.CodeReload; +using UnityEngine; + +public class Spinner : MonoBehaviour +{ + public float rotationSpeed = 90f; + + [CodeReload] + public void Update() + { + transform.Rotate(Vector3.up, rotationSpeed * Time.deltaTime); + } +} +``` + +The attribute must be there before entering Play Mode or building a player, because the dispatch check is woven in at compile time (see [How it works](#how-it-works)). Edit the body of `Update`, then apply the file with one of the commands below. The running instance picks up the new body. + +**Constraints.** The `[CodeReload]` method must be **`public`** (instance **or static**) and must return **`void` or `System.Collections.IEnumerator`** (a coroutine). Methods returning anything else are skipped at build time with a warning. The `Assembly.Load` backend adds one more rule, described in its section: the body may only touch public members of its host type. + +### Supported changes + +**New methods:** a reload can declare a method the compiled type doesn't have yet and call it from a reloaded body (instance and static methods, expression bodies included; not generics, properties, or fields). A new method cannot be a reload *entry point* — nothing compiled calls it until the next real compile — so tagging it `[CodeReload]` registers nothing for it (the reload response says so) while the rest of the file still applies. + +**Method groups and delegates:** a reloaded body can pass a method as a callback — `_root.Add(new Button(Click))`, `button.clicked += Click`, `RegisterCallback(OnClick)` — whether the method already exists compiled or was just added, and event `-=` unsubscribes as expected. Lambdas and closures work too, and delegate *values* combine (`a += b` on an `Action` local/field). Limits: at most 4 delegate parameters and no ref/out parameters. One caveat for a method group over a *new* method: the receiver is evaluated when the delegate fires, not captured at subscription, and `-=` of such a group won't match the `+=`. + +**Coroutines:** a `[CodeReload] IEnumerator` method picks up the new body at iterator **creation** — each `StartCoroutine` call uses the latest reload, while coroutines already running keep executing the body they were created from (use `[OnCodeReload]` to stop/restart long-lived ones). `yield return null`, `WaitForSeconds`, and nested coroutines all work; `IEnumerable`/generic iterator returns are not supported. Two caveats: an exception thrown inside a reloaded coroutine body surfaces from the coroutine scheduler with no automatic fallback to the original body (unlike void methods), and on the interpreter backend a `try/finally` around a `yield` runs its `finally` on the normal path and on `Dispose`, but **not** when the body throws. Coroutines are the main use case for the `[OnCodeReload]` callbacks described below. + +## Reload callbacks — `[OnCodeReload]` + +Tag a **parameterless instance method** with `[OnCodeReload]` to run code after a reload lands — a place to re-initialize state the swapped code depends on (think a domain-reload-free `OnEnable`): + +```csharp +[OnCodeReload] +void OnCodeReloaded() +{ + StopAllCoroutines(); + StartCoroutine(MainLoop()); // restart so the loop picks up the new body +} +``` + +It fires once per reload that changes at least one method on the declaring type, on **every live instance** (`UnityEngine.Object`-derived types only), on the main thread. Exceptions are logged, not propagated. Both backends and the watcher trigger it. Typical uses: restarting long-lived coroutines, disabling and re-enabling MonoBehaviours, and refreshing caches computed by the old code. + +## `Assembly.Load` backend: the `reload_file` command + +This backend compiles the edited C# in the process that runs it, so reloading in a player does not need a running editor. It does need the runtime Pipeline server in the player, since the command arrives over HTTP. + +```bash +unity command reload_file "/Spinner.cs" + +# Emit debug symbols so breakpoints bind (compiles unoptimized): +unity command reload_file "/Spinner.cs" --pdb +``` + +`reload_file` parameters: + +| Arg | Default | Meaning | +|-----|---------|---------| +| `filename` | *(required)* | Source file containing `[CodeReload]` methods. | +| `timeout` | `30000` | Compilation timeout (ms). | +| `assemblyDir` | `null` | Optional directory to also save the compiled assembly to disk (default: in-memory only). | +| `pdb` | `false` | Emit a portable PDB mapped to the original source so debugger breakpoints bind. Compiles unoptimized. | + +**Public members only.** The reloaded body may only access public members of its host type. The compiled code loads as a separate assembly and Mono enforces accessibility, so a private field or method would fail at dispatch; the reload rejects it up front with the offending members listed. + +## Interpreter backend: the `reload_file_*_interpreter` commands + +The editor compiles the edited file to IL, and the IlInterpreter runs that IL where the reload lands: in the editor process, or in a connected player. No `Assembly.Load` is involved, so this backend works in IL2CPP players. Both commands compile in the editor, so reloading a player needs the editor running and the player connected. + +### `reload_file_editor_interpreter` + +Same as `reload_file`, but the reloaded methods run through the interpreter in the editor process. Use it to check that an edit stays within the interpreter's subset and host surface before pushing it to a device. + +```bash +unity command reload_file_editor_interpreter "/Spinner.cs" +``` + +| Arg | Default | Meaning | +|-----|---------|---------| +| `filename` | *(required)* | Source file containing `[CodeReload]` methods. | +| `timeout` | `30000` | Compilation timeout (ms). | +| `assemblyDir` | `null` | Optional directory to also save the compiled IL to disk (default: in-memory only). | +| `pdb` | `false` | Emit a portable PDB mapped to the original source. Runtime errors already report source lines on this backend, so this only matters if you also want the `.pdb` on disk. | + +The public-members-only constraint of `reload_file` does not apply: the interpreter reaches private members by reflection. + +### `reload_file_player_interpreter` + +Compiles a file's (or a folder's) `[CodeReload]` methods in the editor and pushes the IL to connected development players over PlayerConnection (the Profiler's channel, so no open port is needed and it tunnels over USB). Folders are walked recursively; a `.cs` file is only compiled if it mentions `CodeReload`, and files that don't are skipped rather than reported as errors. + +```bash +# Compile a file's [CodeReload] methods and push to every connected player +unity command reload_file_player_interpreter "Assets/Scripts/Player.cs" + +# Push a whole folder, targeting one player by id (-1 = broadcast, the default) +unity command reload_file_player_interpreter "Assets/Scripts" --player 2 +``` + +| Arg | Default | Meaning | +|-----|---------|---------| +| `filename` | *(required)* | Source `.cs` file or a folder containing `[CodeReload]` methods (e.g. `Assets/pong.cs` or `Assets/Scripts`). | +| `player` | `-1` | Target connected player id. `-1` broadcasts to all connected players. | + +Points to know: + +- The push compiles with the **player's** preprocessor defines, not the editor's. +- The player needs the runtime Pipeline driver enabled (see [Runtime connection & setup](runtime-setup.md)); the HTTP server is not required. +- The response reports the compile result and any host-surface members the pushed code uses that the player does not expose (see [Available APIs](#interpreter-constraints)). The player acks the apply asynchronously to the editor console. +- Unlike the watcher, the command pushes every tagged method in the file, not just the ones that changed. That is the escape hatch when the connected player was not built from the sources you are editing. + +### Interpreter constraints + +The `Assembly.Load` backend runs plain C# — anything Roslyn compiles works. The interpreter backend does not: it executes a **C# subset** against a **fixed host surface**. The subset is checked before the code runs; the host surface only bites at runtime, on a device. + +**Language subset.** The shipped Roslyn analyzer (diagnostics **MS002–MS023**) marks violations in your IDE, on `[CodeReload]` method bodies only. Not supported: + +- `await` / `Task`, `try`/`catch`/`finally`, `lock`, LINQ query syntax (`from x in …`), `checked` +- `decimal`, `dynamic`, reflection types (`Type`, `MethodInfo`, …), threading types +- `ref`/`out`/`in` parameters, `ref` returns and locals, multi-dimensional arrays (`int[,]` — jagged `int[][]` is fine), generic methods +- declaring static fields, value-type nullables (`T?`), new type declarations inside the file, `yield` in a local function + +`long`, `ulong`, and `double` work (the VM runs them in 64-bit slots). Lambdas, closures, delegates, `goto`, string interpolation, and coroutine `yield` all work — see the delegate and coroutine notes above for their edges. + +**Available APIs.** Interpreted code can only call the UnityEngine/BCL members the interpreter exposes, plus the reloaded type's own members. In the editor, missing members bind on demand; on a device they cannot (IL2CPP strips unreferenced code), so an unexposed member throws when the reloaded code reaches it. A device push checks this up front and lists the missing members as warnings in the push response. + +### Watching for changes + +Instead of running `reload_file_player_interpreter` or `reload_file_editor_interpreter` by hand, let the editor watch for saves: **Window → Pipeline → Settings… → Code Reload Interpreter Watch → Start Watching**. The watch covers the whole Assets tree; a saved `.cs` only compiles if it mentions `CodeReload`. + +![Watcher panel](./images/codereload-watcher-panel.png) + +Each save picks its target automatically: + +- **A development player is connected** (Autoconnect Profiler, or attached via Profiler/Console) → the save compiles in the editor and is pushed to every connected player over PlayerConnection, always on the interpreter backend. +- **No player** → the save applies in this editor process, also on the interpreter backend. + +Plugging in or disconnecting a device mid-watch reroutes the next save; no restart needed. + +The workflow: start the watch, enter Play Mode, edit `[CodeReload]` bodies, save. Points to know: + +- **Auto-refresh is off while watching**, so a save reloads instead of triggering a domain reload. Other assets won't import until you refresh manually (Cmd/Ctrl+R). **Stop Watching** restores your setting. +- Only methods that **changed since the watch started** reload; untouched ones keep running compiled. +- The watch **survives domain reloads**, re-applies reloads that a Play Mode domain reload wiped, and re-pushes state to a player that reconnects (a restarted player boots the original code) — governed by the **Re-push On Connect** setting. +- The inspector shows liveness: watcher event count, last apply, and the resolved target. Compile errors and binding warnings land in the Console. + +To push once without a watch, run [`reload_file_player_interpreter`](#reload_file_player_interpreter) directly. + +## How it works + +Every `[CodeReload]` method gets a small check woven in when your project builds: on each call it runs the latest reloaded body if one exists, otherwise the original. That is why edits apply without touching call sites, and why a reload only ever changes tagged methods. + +An applied reload compiles the edited source **in memory**; nothing is written to disk unless you pass `assemblyDir`. The result then either loads next to the original assembly (`Assembly.Load` backend, Mono only) or is executed by the interpreter (works everywhere, including IL2CPP). + +## Supporting commands + +- `codereload_status` — list which methods currently have a reload applied. +- `cleanup_codereload` — delete saved reload assemblies and revert every method to its compiled body. + +## See also + +- [Runtime connection & setup](runtime-setup.md) — enabling code reload in a Player build. +- [Command reference](commands/runtime.md) diff --git a/AIClient/Packages/com.unity.pipeline/Documentation~/commands/animation.md b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/animation.md new file mode 100644 index 0000000..e983ada --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/animation.md @@ -0,0 +1,191 @@ +# Animation commands + +Author animation assets: AnimationClips (and their float curves), AnimatorControllers (parameters, layers, states, transitions), and Timeline assets. Create commands write under the authoring root and follow the shared `confirm`/`dry_run` convention. + +## AnimationClips + +### `create_animation_clip` +Create an empty .anim AnimationClip asset under the authoring root, with an optional frame rate and loop flag. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `path` | yes | `–` | Asset path ending in .anim, relative to the authoring root. The Assets/ prefix is optional. | +| `frameRate` | no | `60` | Sampling frame rate of the clip. | +| `loop` | no | `false` | If true, set the clip's loop-time flag in its AnimationClipSettings. | +| `confirm` | no | `false` | Required (true) only when overwriting an existing asset at the path. | +| `dry_run` | no | `false` | If true, validate inputs and report what would be created without writing anything. | + +**Returns:** `AuthoringResult` + +### `set_animation_curve` +Add or replace a single float curve binding on an AnimationClip (via AnimationUtility.SetEditorCurve). Replacing an existing binding overwrites it rather than duplicating. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `clip` | yes | `–` | Reference to the AnimationClip to edit (path / guid / globalId). | +| `path` | no | `""` | GameObject path relative to the animated root the property lives on. Empty string targets the root. | +| `type` | yes | `–` | Component type the property lives on, e.g. "Transform", "UnityEngine.Light". Resolved via the component TypeResolver. | +| `property` | yes | `–` | Curve property name, e.g. "m_LocalPosition.x", "m_LocalScale.y", "localEulerAnglesRaw.z". | +| `keys` | yes | `–` | Keyframes: `[{ time, value, inTangent?, outTangent?, weightedMode?: "None"\|"In"\|"Out"\|"Both" }]`. Omitted tangents default to 0 (flat); this is NOT Unity's Auto tangent mode. | +| `dry_run` | no | `false` | If true, validate type/property/keys without writing the curve. | + +**Returns:** `SetAnimationCurveResult` + +### `get_animation_clip` +Read an AnimationClip's metadata and all float curve bindings (optionally with keyframes). + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `clip` | yes | `–` | Reference to the AnimationClip to read (path / guid / globalId). | +| `includeKeys` | no | `false` | If true, include each binding's keyframes. | + +**Returns:** `AnimationClipInfo` + +### `remove_animation_curve` +Remove a float curve binding from an AnimationClip (SetEditorCurve(clip, binding, null)). Destructive: requires confirm=true. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `clip` | yes | `–` | Reference to the AnimationClip to edit (path / guid / globalId). | +| `path` | no | `""` | GameObject path relative to the animated root the binding lives on. Empty string targets the root. | +| `type` | yes | `–` | Component type of the binding to remove, e.g. "Transform". Resolved via the component TypeResolver. | +| `property` | yes | `–` | Curve property name to remove, e.g. "m_LocalPosition.x". | +| `confirm` | no | `false` | Must be true to actually remove the binding (destructive guard). | +| `dry_run` | no | `false` | If true, report the binding that would be removed without removing it. | + +**Returns:** `SetAnimationCurveResult` + +## AnimatorControllers + +### `create_animator_controller` +Create an .controller AnimatorController asset (with a default Base Layer) under the authoring root. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `path` | yes | `–` | Asset path ending in .controller, relative to the authoring root. The Assets/ prefix is optional. | +| `confirm` | no | `false` | Required (true) only when overwriting an existing asset at the path. | +| `dry_run` | no | `false` | If true, validate inputs and report what would be created without writing anything. | + +**Returns:** `AuthoringResult` + +### `add_animator_parameter` +Add a parameter (Float | Int | Bool | Trigger) to an AnimatorController. A duplicate name returns code 'duplicate_parameter'. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `controller` | yes | `–` | Reference to the AnimatorController to edit (path / guid / globalId). | +| `name` | yes | `–` | Parameter name. | +| `type` | yes | `–` | Parameter type: Float \| Int \| Bool \| Trigger. | +| `defaultValue` | no | `–` | Default value for Float/Int/Bool (ignored for Trigger). | +| `dry_run` | no | `false` | If true, validate inputs without writing the parameter. | + +**Returns:** `object` + +### `add_animator_layer` +Add a layer to an AnimatorController. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `controller` | yes | `–` | Reference to the AnimatorController to edit (path / guid / globalId). | +| `name` | yes | `–` | Layer name. | +| `weight` | no | `1` | Layer weight. | +| `blendingMode` | no | `Override` | Blending mode: Override \| Additive. | +| `dry_run` | no | `false` | If true, validate inputs without writing the layer. | + +**Returns:** `object` + +### `add_animator_state` +Add a state to a layer, optionally with a motion (AnimationClip or BlendTree) and as the layer default. A layer name with no match returns code 'layer_not_found'. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `controller` | yes | `–` | Reference to the AnimatorController to edit (path / guid / globalId). | +| `layer` | no | `0` | Layer index (int) or name (string). Default 0 (Base Layer). | +| `name` | yes | `–` | State name. | +| `motion` | no | `–` | Optional AnimationClip or BlendTree asset to assign as the state's motion. | +| `isDefault` | no | `false` | If true, set this state as the layer's default state. | +| `position` | no | `–` | Optional [x, y] node position in the graph (cosmetic). | +| `dry_run` | no | `false` | If true, validate inputs without writing the state. | + +**Returns:** `object` + +### `add_animator_transition` +Add a transition between two states (or from AnyState/Entry, to Exit) on a layer, with optional conditions. Validates that the states exist and each condition's parameter exists and its mode matches the parameter type. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `controller` | yes | `–` | Reference to the AnimatorController to edit (path / guid / globalId). | +| `layer` | no | `0` | Layer index (int) or name (string). Default 0 (Base Layer). | +| `fromState` | yes | `–` | Source state name, or the special "AnyState" / "Entry". | +| `toState` | yes | `–` | Destination state name, or the special "Exit". | +| `conditions` | no | `–` | Optional conditions: `[{ parameter, mode: "If"\|"IfNot"\|"Greater"\|"Less"\|"Equals"\|"NotEqual", threshold? }]`. | +| `hasExitTime` | no | `false` | If true, the transition uses exit time. | +| `exitTime` | no | `0` | Normalized exit time (0..1) when hasExitTime is set. | +| `duration` | no | `0.25` | Transition duration in seconds. | +| `hasFixedDuration` | no | `true` | If true, duration is in seconds; otherwise normalized. | +| `dry_run` | no | `false` | If true, validate everything (states, parameters, mode/type) without writing the transition. | + +**Returns:** `object` + +### `get_animator_controller` +Read an AnimatorController's full structure: parameters, layers, states (with motion / default), and transitions (with conditions). + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `controller` | yes | `–` | Reference to the AnimatorController to read (path / guid / globalId). | + +**Returns:** `AnimatorControllerInfo` + +## Timeline + +The Timeline commands require the `com.unity.timeline` package. + +### `create_timeline` +Create a .playable TimelineAsset under the authoring root (optional frame rate). + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `path` | yes | `–` | Asset path ending in .playable, relative to the authoring root. The Assets/ prefix is optional. | +| `frameRate` | no | `60` | Timeline frame rate. | +| `confirm` | no | `false` | Required (true) only when overwriting an existing asset at the path. | +| `dry_run` | no | `false` | If true, validate inputs and report what would be created without writing anything. | + +**Returns:** `object` + +### `add_timeline_track` +Add a track (Animation | Audio | Activation | Control | Playable | Signal | Marker) to a TimelineAsset, optionally nested under a parent group/track. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `timeline` | yes | `–` | Reference to the TimelineAsset to edit (path / guid / globalId). | +| `trackType` | yes | `–` | Track type: Animation \| Audio \| Activation \| Control \| Playable \| Signal \| Marker. | +| `name` | no | `–` | Optional track display name. | +| `parentTrack` | no | `–` | Optional name of an existing group/track to nest the new track under. | +| `dry_run` | no | `false` | If true, validate inputs without writing the track. | + +**Returns:** `object` + +### `add_timeline_clip` +Add a clip to a named track on a TimelineAsset. For Animation tracks pass an AnimationClip asset; for Audio tracks an AudioClip. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `timeline` | yes | `–` | Reference to the TimelineAsset to edit (path / guid / globalId). | +| `track` | yes | `–` | Target track name. | +| `start` | yes | `–` | Clip start time in seconds. | +| `duration` | yes | `–` | Clip duration in seconds. | +| `asset` | no | `–` | Source asset: for Animation tracks an AnimationClip; for Audio tracks an AudioClip. Required for those track types. | +| `dry_run` | no | `false` | If true, validate inputs without writing the clip. | + +**Returns:** `object` + +### `get_timeline` +Read a TimelineAsset's structure: frame rate, duration, and its tracks with their clips. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `timeline` | yes | `–` | Reference to the TimelineAsset to read (path / guid / globalId). | + +**Returns:** `object` + +See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md). diff --git a/AIClient/Packages/com.unity.pipeline/Documentation~/commands/assets-and-files.md b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/assets-and-files.md new file mode 100644 index 0000000..50ee6f0 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/assets-and-files.md @@ -0,0 +1,150 @@ +# Asset & file commands + +Commands for creating, importing, moving, copying, renaming, deleting and finding project assets, plus folder and text-file operations. Every agent-supplied path is funnelled through the authoring-root sandbox (it rejects `../` and out-of-project writes); destructive or overwriting operations require `confirm=true` and support `dry_run`. AssetDatabase create/move/copy/rename/delete are not part of Unity's Undo system. + +### `create_asset` +Create a new ScriptableObject (or other UnityEngine.Object) asset of the given type at a path under the authoring root. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `path` | yes | – | Asset path relative to the authoring root, including extension (e.g. Data/Config.asset or Materials/Wall.mat). The Assets/ prefix is optional. | +| `type` | yes | – | Fully-qualified or short type name to instantiate (e.g. UnityEngine.Material, MyGame.GameConfig). Must derive from UnityEngine.Object and be creatable. | +| `shader` | no | `–` | Material-only (ignored otherwise): shader name to assign (e.g. Standard, "Universal Render Pipeline/Lit"). When omitted, defaults to "Universal Render Pipeline/Lit" if a Scriptable Render Pipeline is active, otherwise the built-in "Standard" shader (falling back to "Standard" if URP/Lit is unavailable). | +| `confirm` | no | `false` | Required (true) only when overwriting an existing asset at the path. Ignored when the path is empty. | +| `dry_run` | no | `false` | If true, validate inputs and report what would be created without writing anything. | + +**Returns:** `AuthoringResult` +**Notes:** `confirm=true` required to overwrite an existing asset; supports `dry_run`. + +### `import_asset` +Import an external file (e.g. a texture, model, audio clip) into the project by copying it to a path under the authoring root, then importing it. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `source` | yes | – | Absolute filesystem path to the external file to import. | +| `path` | yes | – | Destination asset path relative to the authoring root, including extension. The Assets/ prefix is optional. | +| `confirm` | no | `false` | Required (true) only when overwriting an existing asset at the destination path. | +| `dry_run` | no | `false` | If true, validate inputs and report what would be imported without writing anything. | + +**Returns:** `AuthoringResult` +**Notes:** `confirm=true` required to overwrite an existing asset; supports `dry_run`. + +### `move_asset` +Move (or rename via a new path) an asset to a new location under the authoring root. Preserves the asset's GUID. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `asset` | yes | – | Reference to the asset to move (path / guid / globalId). | +| `destination` | yes | – | Destination asset path relative to the authoring root, including extension. The Assets/ prefix is optional. | +| `dry_run` | no | `false` | If true, validate the move (via AssetDatabase.ValidateMoveAsset) without performing it. | + +**Returns:** `AuthoringResult` +**Notes:** Supports `dry_run`. + +### `copy_asset` +Copy an asset to a new path under the authoring root. The copy gets a fresh GUID. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `asset` | yes | – | Reference to the asset to copy (path / guid / globalId). | +| `destination` | yes | – | Destination asset path relative to the authoring root, including extension. The Assets/ prefix is optional. | +| `confirm` | no | `false` | Required (true) only when overwriting an existing asset at the destination path. | +| `dry_run` | no | `false` | If true, validate inputs and report what would be copied without writing anything. | + +**Returns:** `AuthoringResult` +**Notes:** `confirm=true` required to overwrite an existing asset; supports `dry_run`. + +### `rename_asset` +Rename an asset in place (keeps it in the same folder, keeps its GUID). + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `asset` | yes | – | Reference to the asset to rename (path / guid / globalId). | +| `new_name` | yes | – | New file name WITHOUT a folder path. The extension is preserved if omitted. | +| `dry_run` | no | `false` | If true, validate the rename without performing it. | + +**Returns:** `AuthoringResult` +**Notes:** Supports `dry_run`. + +### `delete_asset` +Delete an asset from the project. Destructive: requires confirm=true. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `asset` | yes | – | Reference to the asset to delete (path / guid / globalId). | +| `confirm` | no | `false` | Must be true to actually delete. Without it the command refuses (destructive guard). | +| `dry_run` | no | `false` | If true, report the asset that would be deleted without deleting it. | + +**Returns:** `AuthoringResult` +**Notes:** Destructive — `confirm=true` required; supports `dry_run`. Not undoable via Unity's Undo. + +### `find_assets` +Find assets by type and/or name and/or label, returning their path, GUID and type. At least one filter is required. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `type` | no | `–` | Type name to filter by (e.g. Material, GameObject, ScriptableObject, MyGame.GameConfig). Resolved to a System.Type and matched against each asset's actual main type. | +| `name` | no | `–` | Name substring to filter by (AssetDatabase name filter). | +| `label` | no | `–` | Asset label to filter by (AssetDatabase 'l:' filter). | +| `search_in` | no | `–` | Folder to scope the search to, relative to the authoring root (default: the authoring root). | +| `limit` | no | `200` | Maximum number of results to return (default 200). | + +**Returns:** `FindAssetsResult` +**Notes:** At least one of `type`, `name`, or `label` is required. + +### `set_import_settings` +Set import settings on an asset's AssetImporter (e.g. a texture's isReadable) and re-import it. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `asset` | yes | – | Reference to the asset whose importer to edit (path / guid / globalId). | +| `settings` | yes | – | JSON object of importer property/field names to values, e.g. {"isReadable": true, "textureType": "NormalMap"}. | +| `dry_run` | no | `false` | If true, validate which settings would apply (and which are unknown) without writing or re-importing. | + +**Returns:** `SetImportSettingsResult` +**Notes:** Supports `dry_run`. Import settings live in the asset's .meta file and are not part of Unity's Undo system. + +### `get_import_settings` +Read an asset's import settings, structured by importer type (texture/model/audio), including the default-platform fields and (for textures/audio) one platform override block. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `asset` | yes | – | Reference to the asset whose importer to read (path / guid / globalId). | +| `platform` | no | `Default` | Platform whose override to read: Default \| Standalone \| iOS \| Android \| WebGL \| tvOS. | + +**Returns:** `GetImportSettingsResult` + +### `create_folder` +Create a folder under the authoring root (creates intermediate folders). + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `path` | yes | – | Folder path relative to the authoring root (default Assets/); the Assets/ prefix is optional. e.g. Gameplay/Enemies or Assets/Gameplay/Enemies | + +**Returns:** `AuthoringResult` + +### `read_text_file` +Read a UTF-8 text file under the authoring root and return its contents. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `path` | yes | – | Text file path relative to the authoring root. The Assets/ prefix is optional. | +| `max_bytes` | no | `1048576` | Reject files larger than this many bytes (default 1048576 = 1 MiB) to avoid huge payloads. | + +**Returns:** `ReadTextFileResult` +**Notes:** `MainThreadRequired = true`. + +### `write_text_file` +Write UTF-8 text to a file under the authoring root, then import it. Overwriting an existing file requires confirm=true. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `path` | yes | – | Text file path relative to the authoring root, including extension. The Assets/ prefix is optional. | +| `contents` | yes | – | The full text content to write (replaces the file). | +| `confirm` | no | `false` | Required (true) only when overwriting an existing file at the path. | +| `dry_run` | no | `false` | If true, validate inputs and report what would be written without writing anything. | + +**Returns:** `AuthoringResult` +**Notes:** `confirm=true` required to overwrite an existing file; supports `dry_run`. Filesystem writes are not part of Unity's Undo system. + +See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md). diff --git a/AIClient/Packages/com.unity.pipeline/Documentation~/commands/baking.md b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/baking.md new file mode 100644 index 0000000..a716346 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/baking.md @@ -0,0 +1,140 @@ +# Baking commands + +Bake and clear precomputed scene data: lightmaps, NavMesh, and occlusion culling. Each `bake_*` runs asynchronously (returns immediately) — poll the matching `*_bake_status` until `completed`. The `clear_*` commands are destructive and require `confirm=true`. The `get_*_settings` / `set_*_settings` pairs read and tune the bake parameters. + +## Lighting + +### `bake_lighting` +Trigger an async lightmap bake of the open scene(s) via Lightmapping.BakeAsync(). Returns immediately; poll `lighting_bake_status` until completed. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `confirm` | no | `false` | Recommended (true): a bake overwrites existing lightmap data. Accepted for parity; not required. | +| `dry_run` | no | `false` | If true, validate there is an open bakeable scene and return the current lighting settings without baking. | + +**Returns:** `object` + +### `lighting_bake_status` +Get the status of the last lighting bake: idle | baking | completed. + +**Returns:** `string` + +### `cancel_lighting_bake` +Cancel an in-progress lighting bake (Lightmapping.Cancel()). + +**Returns:** `object` + +### `clear_baked_lighting` +Clear baked lightmap data for the open scene(s). Destructive: requires confirm=true. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `confirm` | no | `false` | Must be true to actually clear (destructive, not undoable via Unity's Undo). | +| `include_disk_cache` | no | `false` | If true, also clear the GI disk cache (Lightmapping.ClearDiskCache()). | +| `dry_run` | no | `false` | If true, report what would be cleared without clearing. | + +**Returns:** `object` + +### `get_lighting_settings` +Read the active LightingSettings (lightmapper, bounces, resolution, directional mode, AO, etc.). + +**Returns:** `LightingSettingsResult` + +### `set_lighting_settings` +Apply a subset of lighting settings to the active LightingSettings. Returns `{ applied[], unknown[] }`. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `settings` | yes | `–` | JSON object with a subset of lighting fields to set (same names/enums as get_lighting_settings). | +| `dry_run` | no | `false` | If true, validate the keys and report applied/unknown without changing anything. | + +**Returns:** `object` + +## NavMesh + +### `bake_navmesh` +Trigger an async legacy NavMesh bake of the open scene(s) via UnityEditor.AI.NavMeshBuilder. Returns immediately; poll `navmesh_bake_status` until completed. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `confirm` | no | `false` | Accepted for parity (a bake overwrites the existing NavMesh); not required. | +| `dry_run` | no | `false` | If true, validate there is an open scene and return current NavMesh settings without baking. | + +**Returns:** `object` + +### `navmesh_bake_status` +Get the status of the last NavMesh bake: idle | baking | completed. + +**Returns:** `string` + +### `cancel_navmesh_bake` +Cancel an in-progress NavMesh bake (NavMeshBuilder.Cancel()). + +**Returns:** `object` + +### `clear_navmesh` +Clear the baked NavMesh for the open scene(s). Destructive: requires confirm=true. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `confirm` | no | `false` | Must be true to actually clear (destructive, not undoable via Unity's Undo). | +| `dry_run` | no | `false` | If true, report what would be cleared without clearing. | + +**Returns:** `object` + +### `get_navmesh_settings` +Read the default agent's legacy NavMesh bake settings (agentRadius/Height/Slope/Climb, minRegionArea, voxelSize). + +**Returns:** `NavMeshSettingsResult` + +### `set_navmesh_settings` +Apply a subset of legacy NavMesh bake settings to the default agent. Returns `{ applied[], unknown[] }`. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `settings` | yes | `–` | JSON object with a subset of NavMesh fields to set (same names as get_navmesh_settings). | +| `dry_run` | no | `false` | If true, validate the keys and report applied/unknown without changing anything. | + +**Returns:** `object` + +### `bake_navmesh_surfaces` +Bake NavMeshSurface components (AI Navigation package). v1 stub: returns package_not_found when the package is absent. + +**Returns:** `object` + +## Occlusion culling + +### `bake_occlusion_culling` +Trigger an async occlusion-culling bake of the open scene(s) via StaticOcclusionCulling.GenerateInBackground(). Returns immediately; poll `occlusion_bake_status` until completed. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `smallest_occluder` | no | `–` | Smallest object that will occlude others (meters). Defaults to Unity's current value. | +| `smallest_hole` | no | `–` | Smallest gap geometry can have that the view can see through (meters). Defaults to Unity's current value. | +| `backface_threshold` | no | `–` | Backface threshold (1-100); lower trims more backfaces. Defaults to Unity's current value. | +| `confirm` | no | `false` | Accepted for parity (a bake overwrites existing occlusion data); not required. | +| `dry_run` | no | `false` | If true, validate there is an open scene and report the parameters that would be used without baking. | + +**Returns:** `object` + +### `occlusion_bake_status` +Get the status of the last occlusion bake: idle | baking | completed. + +**Returns:** `string` + +### `cancel_occlusion_bake` +Cancel an in-progress occlusion bake (StaticOcclusionCulling.Cancel()). + +**Returns:** `object` + +### `clear_occlusion_culling` +Clear baked occlusion-culling data for the open scene(s). Destructive: requires confirm=true. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `confirm` | no | `false` | Must be true to actually clear (destructive, not undoable via Unity's Undo). | +| `dry_run` | no | `false` | If true, report what would be cleared without clearing. | + +**Returns:** `object` + +See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md). diff --git a/AIClient/Packages/com.unity.pipeline/Documentation~/commands/batch.md b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/batch.md new file mode 100644 index 0000000..91d0799 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/batch.md @@ -0,0 +1,102 @@ +# Batch command + +The `batch` command runs several existing pipeline commands in a single request, with cross-operation result references, atomic Undo, and dry-run validation. It exists to collapse the round-trips of a "create → add components → wire fields" job (otherwise 10–90 sequential calls) into one request, and to add what `eval` structurally lacks: **transactionality and rollback**, so a failure mid-way never leaves partial state on a user-owned scene. + +**Scope guard:** `batch` is transactional object CRUD with references. It intentionally has **no** `invoke`/loop/conditional op types — arbitrary logic belongs in code-on-disk (`run_script`/`eval`), not in JSON. This keeps the command surface auditable and allowlistable. + +### `batch` +Run multiple registered commands in one transactional request. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `operations` | yes | – | Ordered list of operations, each `{ id?, command, params }`. Max 200. | +| `transactional` | no | `true` | Group every op into one Editor Undo step and revert all applied ops if any op fails. Forced `false` when `on_error=continue`. Rejects commands whose mutations Undo cannot revert (see [Transactional restrictions](#transactional-restrictions)). | +| `on_error` | no | `abort` | `abort`: stop at the first failing op. `continue`: run every op, collecting per-op errors (forces `transactional=false`). | +| `dry_run` | no | `false` | Validate command names, parameters, reference topology, and excluded/non-batchable commands without mutating anything. | +| `result_fields` | no | – | Optional per-op result projection: a map of op id-or-index → array of result field paths to keep (context economy). | +| `time_budget_ms` | no | `50000` | Cooperative time budget for the whole batch, in milliseconds (max 3600000). Checked before each op after the first; when exhausted, the remaining ops are skipped and a transactional batch rolls back. | + +**Returns:** `BatchResult` — `{ results: [{ id?, command, success, result? | error?, skipped?, resultTruncated?, revertible? }], applied, reverted, transactional, onError, error?, undoGroup?, dryRun?, valid? }`. The batch-level `error` is set only for aborts not attributable to a single op ("batch time budget exceeded", "batch canceled"). + +**Notes:** Runs on the main thread. Each sub-operation goes through the same dispatch path as `/api/exec`, so its result is shaped identically to running that command standalone. + +#### Operation shape + +Each entry of `operations` is: + +```json +{ "id": "createHead", "command": "add_component", "params": { "target": "$root.instanceId", "type": "Rigidbody" } } +``` + +- `id` (optional) — a name for referencing this op's result from a later op. Must be unique within the batch and match `^[A-Za-z_][A-Za-z0-9_-]*$` (purely numeric ids would be ambiguous with index selectors, and `.` collides with the reference path separator). +- `command` — the registered command to run (any command except the non-batchable ones below). +- `params` — the command's parameters, same shape as `/api/exec` `parameters`. Operations are **always** `command` + `params`; the `argv`/`commandLine` raw forms are exec-only and are not accepted inside a batch operation. + +#### Cross-operation references + +Any **string** value in a later op's `params` may reference an earlier op's result: + +``` +"$." +``` + +- `` names an earlier op by its `id` or its 0-based index (an `id` match takes precedence). +- `` is a Newtonsoft SelectToken path into that op's result, e.g. `instanceId`, `components[0].instanceId`. +- `"$$"` escapes a literal `$` (so `"$$5"` is the literal string `"$5"`). +- References are **backward-only** and resolved as **whole values** (the entire string must be the reference). The substituted JSON token keeps its type, so a numeric `instanceId` deserializes into an `ObjectRef` parameter exactly as a literal would. References may appear anywhere in the parameter tree (including inside nested objects/arrays). +- Referencing an op that **failed** or was **skipped** errors explicitly (this can happen under `on_error=continue`); referencing a succeeded op that **returned no result** errors with "returned no result". A reference never silently resolves to `null`. +- References always resolve against the **full** result of the earlier op, even when the reported copy was truncated or projected via `result_fields`. +- **Result size bounds** (both measured in serialized UTF-8 bytes, i.e. wire size): a single op's reported result above **16 KiB** is replaced by a truncation marker (`resultTruncated: true` + a preview), and the **aggregate** of all reported results in one batch is bounded to **256 KiB** — past that, later results are elided the same way (the ops still execute; only the echoed copy is dropped). Use `result_fields` to project results down when a batch reads large objects. +- A malformed `result_fields` path never fails its op (the op has already executed); the bad path is reported inside the projection as `invalidResultFields`. + +Example — create a GameObject, add a Rigidbody to it, then set the Rigidbody's mass: + +```json +{ + "operations": [ + { "command": "create_gameobject", "params": { "name": "Ball" } }, + { "command": "add_component", "params": { "target": "$0.instanceId", "type": "Rigidbody" } }, + { "command": "set_serialized_field", "params": { "target": "$1.instanceId", "field": "m_Mass", "value": 2.5 } } + ] +} +``` + +#### Atomicity + +The whole batch runs inside one `AuthoringUndoScope`, so every op (each of which registers its own Undo operations) collapses into a **single** Editor Undo step. When `transactional` (the default) and the batch aborts — an op fails under `on_error=abort`, the time budget runs out, or the job is canceled — every applied op is reverted with `Undo.RevertAllDownToGroup` (including partial mutations registered by the failing op itself), the scene returns to its pre-batch state, and nothing is left on the Undo stack. `reverted: true` and the failing op's `error` are reported. + +#### Transactional restrictions + +Rollback is only real for **Undo-tracked** mutations (scene objects, components, serialized fields). Commands that mutate state **outside** the Undo system — asset and file writes, scene saves, Build Settings, project settings, baked data — cannot be rolled back, so a transactional batch **rejects** them with a structured `not_batchable_transactional` error. Run them with `transactional: false`, or call them standalone. Their per-op result reports `revertible: false` so the limitation is visible. + +The non-revertible set (v1 — a curated list, pending per-command `Revertible` metadata): + +- **Assets & files:** `create_asset`, `import_asset`, `move_asset`, `copy_asset`, `rename_asset`, `delete_asset`, `create_folder`, `set_import_settings`, `write_text_file`, `create_script` +- **Prefab assets:** `create_prefab`, `create_prefab_variant`, `apply_prefab_overrides`, `save_prefab_contents` (scene-side prefab ops — `instantiate_prefab`, `unpack_prefab`, `revert_prefab_overrides` — are Undo-tracked and stay fully batchable) +- **Scene persistence & build list:** `save_scene`, `save_all`, `add_scene_to_build`, `remove_scene_from_build`, `set_build_settings` +- **Settings:** `set_audio_settings`, `set_graphics_settings`, `set_input_settings`, `set_lighting_settings`, `set_navmesh_settings`, `set_physics_settings`, `set_player_settings`, `set_quality_settings`, `set_tags_layers`, `set_time_settings`, `set_authoring_root` +- **Animation / Timeline assets:** `create_animation_clip`, `set_animation_curve`, `remove_animation_curve`, `create_animator_controller`, `add_animator_layer`, `add_animator_parameter`, `add_animator_state`, `add_animator_transition`, `create_timeline`, `add_timeline_track`, `add_timeline_clip` +- **Materials:** `set_material_properties` (persists the `.mat` asset to disk) +- **Baking:** `bake_lighting`, `clear_baked_lighting`, `bake_navmesh`, `bake_navmesh_surfaces`, `clear_navmesh`, `bake_occlusion_culling`, `clear_occlusion_culling` + +`open_scene` and `create_scene` are **always** rejected inside a batch (even with `transactional: false`): they clear the Editor Undo stack, which would silently destroy the batch's ability to revert anything that ran before them. + +#### Timing, budget and cancellation + +The batch executes in a **single main-thread turn** — the Editor UI is frozen for its duration, bounded by `time_budget_ms` (frame-spanning execution is future work). The elapsed time is checked cooperatively before each op after the first; when the budget is exhausted, the remaining ops are reported `skipped: true`, the batch-level `error` is set to "batch time budget exceeded", and a transactional batch rolls back. For long batches, submit the request as a detached job (`"job": true` on `/api/exec`) and raise `time_budget_ms` — jobs also make the batch cancelable: cooperative cancellation (`POST /api/job/cancel`) is checked between ops and aborts the batch the same way ("batch canceled"). Per-op progress is reported (`op i/n: `) and visible via `GET /api/progress`. + +#### Dry run + +`dry_run: true` validates without executing anything: it catches unknown commands, excluded/non-batchable (`not_batchable`) commands, transactional rejections (`not_batchable_transactional`), unknown/missing parameters, and unresolvable reference topology (unknown or forward references). It mutates nothing and reports `valid` plus a per-op `success`/`error`. + +#### Excluded commands + +The following are rejected with a structured `not_batchable` error: + +- **Out of scope:** `build`, `switch_build_target`, `package_*`, `editor_play`/`editor_stop`/`editor_pause`, `recompile` +- **Arbitrary code:** `eval`, `eval_file`, `run_script`, and nested `batch` +- **Modal-dialog hazard:** `menu` (menu items can open modal dialogs that wedge an unattended batch) +- **Cannot make progress:** synchronous `wait_for` — the batch holds the main thread for its whole turn, so the editor state a condition watches cannot change; the wait would just burn its timeout inside the batch. Run an async `wait_for` before/after the batch instead (`wait_status`/`wait_cancel` are quick reads and stay batchable) +- **Undo-stack wipe:** `open_scene`, `create_scene` +- **Async commands** (`run_tests`, `list_tests`, and any command returning `Task`): they are completed by `EditorApplication.update` callbacks, which cannot fire while the batch holds the main thread — dispatching one would freeze the Editor permanently +- **Runtime-only commands** (e.g. `set_timescale`): they belong to the Player server surface and cannot execute on the editor server diff --git a/AIClient/Packages/com.unity.pipeline/Documentation~/commands/build-and-compilation.md b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/build-and-compilation.md new file mode 100644 index 0000000..7ae55d4 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/build-and-compilation.md @@ -0,0 +1,188 @@ +# Build, compilation & test commands + +These commands drive the build/compile/test dev loop, plus build configuration: triggering Player builds and reading the resulting BuildReport, switching the active build target, enumerating targets, reading/writing EditorUserBuildSettings, and listing Build Profiles. Several commands are asynchronous: trigger the operation, then poll a matching `*_status` command until it reports completion. The client must tolerate connection errors during a domain reload (recompile, target switch) or a long blocking build. + +### `build` +Trigger an async Player build and report the full BuildReport. Returns immediately (queued); poll build_status until status is 'completed'. DetailedBuildReport is included by default unless 'options' is supplied. Use dry_run to validate without building. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `target` | no | `–` | BuildTarget name (e.g. StandaloneWindows64). Defaults to the active target. Must be installed. | +| `outputPath` | no | `–` | Output path (absolute, or relative to the project root). Defaults to the last/auto path. | +| `profileName` | no | `–` | Build Profile name to activate before building (Unity 6 only; ignored otherwise). | +| `options` | no | `–` | BuildOptions names. Omit to get just DetailedBuildReport; supplying any disables that default. | +| `scenes` | no | `–` | Scene asset paths to build (e.g. Assets/Scenes/Main.unity). Defaults to EditorBuildSettings. | +| `confirm` | no | `false` | Acknowledge and run the build; without it the call is refused. Use `dry_run` to validate only. | +| `dry_run` | no | `false` | Validate target/outputPath/scenes without building. | + +Supported `options` values (case-insensitive): `Development`, `AllowDebugging`, `ConnectWithProfiler`, `EnableHeadlessMode`, `SymlinkSources`, `BuildAdditionalStreamedScenes`, `CleanBuildCache`, `DetailedBuildReport`. Any unrecognized value is a validation error. + +**Returns:** `object` (transient payloads: `queued` / `busy` / `dry_run` / `error`; the finished report is read via `build_status`). +**Notes:** `MainThreadRequired = false`. Async — validates + queues, returns `queued` immediately, then an editor tick runs the (blocking) build; poll `build_status` until status is `completed`. Only one build at a time (returns `busy` otherwise). Mutating: gated by the `confirm`/`dry_run` convention — pass `confirm=true` for a real build, or `dry_run=true` to validate target/outputPath/scenes without building (nothing is queued on a dry run or on validation failure). + +### `build_status` +Status of the current/most recent build: idle | queued | building | completed, with the full BuildReport (files, packedAssets, buildSteps, errors, warnings) once completed. Retained until the next build. + +No parameters. + +**Returns:** `string` (JSON). `idle` when no build has run; `queued`/`building` (the latter with live `elapsedMs`) while in progress; a full `BuildReportResult` once `completed`. + +`BuildReportResult` fields (returned when `status` is `completed`): + +| Field | Description | +|-------|-------------| +| `status` | Always `completed` here. | +| `buildId` | Id returned by the triggering `build` call. | +| `result` | `Succeeded` \| `Failed` \| `Cancelled` \| `Unknown`. | +| `platform` | Build target the report is for. | +| `outputPath` | Final output location. | +| `totalSizeBytes` | Total build size in bytes. | +| `buildTimeMs` | Total build duration in milliseconds. | +| `buildStartedAt` / `buildEndedAt` | ISO-8601 timestamps (omitted when unset). | +| `totalWarnings` / `totalErrors` | Aggregate counts from the report summary. | +| `files` | Output files (path, role, sizeBytes). Present only on success. | +| `packedAssets` | Packed bundles with per-asset breakdown. Present only on success and requires DetailedBuildReport. | +| `buildSteps` | Per-step name, durationMs, depth, and messages. | +| `errors` / `warnings` | Build issues, each with `message` and best-effort `file`. | + +**Notes:** `MainThreadRequired = false`. Reads a Temp status file off-thread, so polling keeps working while a build holds the main thread. The file also survives the domain reload a build can incur, so the last report is retained until the next build. + +### `switch_build_target` +Switch the active build target (destructive, long-running: triggers a full reimport + domain reload). Requires confirm=true. Returns immediately; poll switch_build_target_status. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `target` | yes | `–` | BuildTarget name to switch to (must be installed; see list_build_targets). | +| `confirm` | no | `false` | Apply the switch. Without it the call is refused. | + +**Returns:** `object` (`switching` / `busy` / `completed` / `error`). Returns `completed` immediately if already on the requested target. +**Notes:** `MainThreadRequired = false`. Async — validates + queues, returns `switching` immediately, then an editor tick performs the (blocking) switch; poll `switch_build_target_status` until `completed`. Only one switch at a time (returns `busy` otherwise). Mutating and confirm-gated: without `confirm=true` the call is refused. The status file survives the domain reload the switch causes, and is reconciled against the active target on the next load. + +### `switch_build_target_status` +Status of the last target switch: idle | switching | completed (with success + activeBuildTarget). + +No parameters. + +**Returns:** `string` (JSON). `idle`, `switching`, or `completed` (with `success` and `activeBuildTarget`, or `errors` on failure). +**Notes:** `MainThreadRequired = false`. Reads a Temp status file off-thread, so it keeps answering while the switch holds the main thread. + +### `list_build_targets` +List the known BuildTarget values with their group and whether build support is installed. + +No parameters. + +**Returns:** `object` (list of `BuildTargetInfo`: `name`, `displayName`, `targetGroup`, `isInstalled`), sorted by group then name. Obsolete and sentinel targets are excluded. +**Notes:** `MainThreadRequired = true`. + +### `get_build_settings` +Read the current build configuration from EditorUserBuildSettings / EditorBuildSettings. + +No parameters. + +**Returns:** `object` (`BuildSettingsResult`). + +`BuildSettingsResult` fields: + +| Field | Description | +|-------|-------------| +| `activeBuildTarget` | Active BuildTarget name. | +| `activeBuildTargetGroup` | Active BuildTargetGroup name. | +| `developmentBuild` | Whether a Development Player is configured. | +| `allowDebugging` | Whether script debugging is allowed. | +| `connectWithProfiler` | Whether the Profiler auto-connects. | +| `buildScriptsOnly` | Whether only scripts are built (skip data). | +| `symlinkSources` | Whether runtime/plugin sources are symlinked. | +| `il2CppCodeGeneration` | `OptimizeSpeed` \| `OptimizeSize` for the active target. | +| `scenes` | Build Settings scene list (each: `path`, `guid`, `enabled`). | + +**Notes:** `MainThreadRequired = true`. + +### `set_build_settings` +Set mutable EditorUserBuildSettings fields. Does NOT manage scenes (use add_scene_to_build / remove_scene_from_build) or switch target (use switch_build_target). Use dry_run to preview. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `settings` | no | `–` | Fields to change; omitted fields are left unchanged. | +| `confirm` | no | `false` | Apply the changes. Without it the call is refused. | +| `dry_run` | no | `false` | Preview the change without applying it. | + +`settings` fields (a structured input DTO; every field is optional — only supplied fields change): + +| Field | Description | +|-------|-------------| +| `developmentBuild` | Build a Development Player (enables the debugger/profiler). | +| `allowDebugging` | Allow script debugging (only effective with developmentBuild=true). | +| `connectWithProfiler` | Auto-connect the Profiler (only effective with developmentBuild=true). | +| `buildScriptsOnly` | Build only the scripts (skip data) for faster iteration. | +| `symlinkSources` | Symlink runtime/plugin sources instead of copying (where supported). | +| `il2CppCodeGeneration` | IL2CPP code generation for the active target: OptimizeSpeed \| OptimizeSize. | + +**Returns:** `object` (`SetBuildSettingsResult`: `success`, `dryRun`, `applied` map of fields that changed, `skipped` map of supplied fields that already matched, `message`). +**Notes:** `MainThreadRequired = true`. Mutating: refused unless `confirm=true` (or `dry_run=true` to preview). Fields already at the requested value are reported under `skipped` rather than re-applied. Fails if no `settings` object is provided. + +### `list_build_profiles` +List Build Profile assets in the project (Unity 6 only). Returns feature_unavailable on earlier versions. + +No parameters. + +**Returns:** `object` (list of `BuildProfileInfo`: `name`, `guid`, `platform`, `isActive`), or `{ error, code = "feature_unavailable" }` on editors older than Unity 6. +**Notes:** `MainThreadRequired = true`. + +### `recompile` +Force a script recompile (works while unfocused/minimized). Poll recompile_status for completion. + +No parameters. + +**Returns:** `object` +**Notes:** `MainThreadRequired = true`. Async — poll `recompile_status` until status is `completed` or `up_to_date`. A successful compile triggers a domain reload, so the triggering request cannot stay open. + +### `recompile_status` +Get the status of the last recompile: idle | triggered | compiling | completed | up_to_date. + +No parameters. + +**Returns:** `string` +**Notes:** `MainThreadRequired = false`. + +### `list_tests` +List all available tests (EditMode and/or PlayMode) without running them. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `mode` | no | `all` | Test mode: all, editor, playmode (default: all) | + +**Returns:** `TestListResponse` +**Notes:** `MainThreadRequired = true`. + +### `run_tests` +Execute Unity tests with filtering options. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `mode` | no | `all` | Test mode: all, editor, playmode (default: all) | +| `filter` | no | `–` | Test name filter pattern (case-insensitive partial match) | +| `filter_type` | no | `testName` | Filter type: testName, assembly, category (default: testName) | +| `include_explicit` | no | `false` | Include tests marked with [Explicit] attribute | +| `async_tests` | no | `false` | Run asynchronously - return immediately, poll /test-status for results | +| `timeout` | no | `300` | Test execution timeout in seconds (default: 300) | + +**Returns:** `TestExecutionResponse` +**Notes:** `MainThreadRequired = true`. Synchronous by default; with `async_tests=true` it returns immediately — poll `test_status` for results. + +### `test_status` +Get status of running async test execution. + +No parameters. + +**Returns:** `string` +**Notes:** `MainThreadRequired = false`. + +### `cancel_tests` +Cancel running test execution. + +No parameters. + +**Returns:** `object` +**Notes:** `MainThreadRequired = true`. + +See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md). diff --git a/AIClient/Packages/com.unity.pipeline/Documentation~/commands/capture.md b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/capture.md new file mode 100644 index 0000000..ccc222c --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/capture.md @@ -0,0 +1,61 @@ +# Capture commands + +Commands that render a camera, the Scene View, or a UI Toolkit element to a PNG and return it base64-encoded so an agent can "see" the editor (or a running player) without a display. + +### `capture_game_view` +Render the game view to a PNG. Returns it inline as base64, unless `save_path` is set — then the result is **path-only** (no base64) so agent tool results stay small; pass `include_inline_image=true` to get both. + +`source` selects what is captured. `camera` (default) renders a camera and **does not include Screen Space - Overlay UI** (HUDs, menus, damage numbers on overlay canvases) — overlay canvases composite straight to the screen and never render through a camera. `screen` captures the composited game view backbuffer, so overlay UI is included; because overlay UI only exists at runtime, `source=screen` **requires Play Mode** (in Edit Mode it returns a clear error — use `source=camera`). The screen capture reads the game view at its true pixel resolution — independent of OS display scaling — and preserves the on-screen color tone, so the PNG matches what the Game window shows. + +Parameter interactions: `include_inline_image` is only meaningful together with `save_path` (without one, the inline image is always returned). `max_resolution` only applies when an inline image is actually returned — i.e. no `save_path`, or `save_path` + `include_inline_image=true`; it has **no effect** when `save_path` is set without `include_inline_image=true`. `camera` is ignored when `source=screen`. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `width` | no | `1280` | Output width in px (default 1280; capped 4096). | +| `height` | no | `720` | Output height in px (default 720; capped 4096). | +| `camera` | no | `–` | Optional camera name (`source=camera` only); defaults to Camera.main, else the first enabled camera. | +| `save_path` | no | `–` | Optional project-relative path to write the PNG (e.g. Screenshots/foo.png). When set, the result omits the inline base64 image unless `include_inline_image=true`. | +| `include_inline_image` | no | `false` | Also return the image inline as base64 when `save_path` is set. | +| `max_resolution` | no | `0` | Cap on the inline image's longest edge (e.g. 512), preserving aspect ratio. No effect when `save_path` is set without `include_inline_image=true`. The `save_path` file keeps the requested resolution; a downscaled inline copy is reported via `inlineWidth`/`inlineHeight`. | +| `source` | no | `camera` | `camera` renders a camera (misses Screen Space - Overlay UI); `screen` captures the composited game view incl. overlay canvases (**Play Mode only**). | + +**Returns:** `CaptureResult` + +### `capture_scene_view` +Render the active Scene View to a PNG. Same result contract and parameter interactions as `capture_game_view`: inline base64, or path-only when `save_path` is set (opt back in with `include_inline_image=true`; `max_resolution` has no effect when `save_path` is set without it). + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `width` | no | `1280` | Output width in px (default 1280; capped 4096). | +| `height` | no | `720` | Output height in px (default 720; capped 4096). | +| `save_path` | no | `–` | Optional project-relative path to write the PNG (e.g. Screenshots/foo.png). When set, the result omits the inline base64 image unless `include_inline_image=true`. | +| `include_inline_image` | no | `false` | Also return the image inline as base64 when `save_path` is set. | +| `max_resolution` | no | `0` | Cap on the inline image's longest edge (e.g. 512), preserving aspect ratio. No effect when `save_path` is set without `include_inline_image=true`. The `save_path` file keeps the requested resolution; a downscaled inline copy is reported via `inlineWidth`/`inlineHeight`. | + +**Returns:** `CaptureResult` + +### `capture_editor_element` +Capture a UI Toolkit VisualElement (by selector) from an EditorWindow to a PNG; returns path + base64. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `window` | yes | `–` | EditorWindow type name (e.g. InspectorWindow) or window title to capture from. | +| `selector` | yes | `–` | Element selector: '#name', '.class', a type name (e.g. Button), descendant (space) / child ('>') chains, optional pseudo-states (:checked,:hover,:focus,:active,:enabled,:disabled,:not(...)). | +| `output` | no | `–` | Output PNG path (absolute, or relative to the project root). Defaults to a timestamped file under /Temp/pipeline-screenshots/. | + +**Returns:** `CaptureElementResponse` +**Notes:** `MainThreadRequired = true`. Unity 6000.7+ only. + +### `capture_runtime_element` +Capture a UI Toolkit VisualElement (by selector) from a live runtime panel (UIDocument or PanelRenderer) to a PNG; returns path + base64. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `panel` | no | `–` | Name of the target panel: matches the PanelSettings asset name or the host GameObject name (UIDocument or PanelRenderer). Optional when exactly one panel exists. | +| `selector` | yes | `–` | Element selector: '#name', '.class', a type name (e.g. Button), descendant (space) / child ('>') chains, optional pseudo-states (:checked,:hover,:focus,:active,:enabled,:disabled,:not(...)). | +| `output` | no | `–` | Output PNG path (absolute, or relative to Application.persistentDataPath). Defaults to a timestamped file under Application.persistentDataPath. | + +**Returns:** `CaptureElementResponse` +**Notes:** `MainThreadRequired = true`, `RuntimeOnly`. Unity 6000.7+ only. + +See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md). diff --git a/AIClient/Packages/com.unity.pipeline/Documentation~/commands/editor-lifecycle-and-observability.md b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/editor-lifecycle-and-observability.md new file mode 100644 index 0000000..32de8ea --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/editor-lifecycle-and-observability.md @@ -0,0 +1,187 @@ +# Editor lifecycle & observability commands + +Commands to control Editor play mode, focus, and menus, and to observe the Editor's state, console, and performance. + +### `editor_play` +Enter Unity Editor play mode. + +No parameters. + +**Returns:** `string` + +### `editor_stop` +Exit Unity Editor play mode. + +No parameters. + +**Returns:** `string` + +### `editor_pause` +Toggle pause state of Unity Editor play mode (calling it again while paused resumes play mode). + +No parameters. + +**Returns:** `string` + +### `editor_status` +Get detailed Unity Editor status and state information. + +No parameters. + +**Returns:** `StatusResponse` + +### `editor_focus` +Bring the Unity Editor window to the foreground. + +No parameters. + +**Returns:** `string` +**Notes:** `MainThreadRequired = true`. + +### `menu` +Execute an Editor menu item by path, or list available items when no path is given. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `path` | no | `–` | Menu item path to execute, e.g. "Assets/Reimport All". Omit to list available menu items. | + +**Returns:** `MenuResponse` +**Notes:** `MainThreadRequired = true`. + +### `screenshot` +Capture the Scene or Game view as a PNG and return its file path. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `view` | no | `game` | Which view to capture: 'game' (default) or 'scene' | +| `output` | no | `–` | Output PNG path (absolute, or relative to the project root). Defaults to a timestamped file under /Temp/pipeline-screenshots/. | +| `width` | no | `0` | Output width in pixels. 0 (default) uses the view camera's current width. | +| `height` | no | `0` | Output height in pixels. 0 (default) uses the view camera's current height. | + +**Returns:** `ScreenshotResponse` +**Notes:** `MainThreadRequired = true`. + +### `set_autotick` +Keep the editor ticking while unfocused by forcing EditorApplication.SignalTick at a throttled rate. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `enable` | no | `true` | Enable (true) or disable (false) auto-tick mode | +| `interval_ms` | no | `16` | Minimum milliseconds between forced ticks. 0 = every update (max rate, pegs a CPU core). Default 16 (~60Hz). | +| `persist` | no | `true` | Persist this choice to SessionState so it survives a domain reload. Set `false` for a one-off/expensive setting (e.g. `interval_ms=0`) that should revert to the last persisted choice (or the default) after the next recompile instead of sticking for the rest of the session. | + +**Returns:** `string` +**Notes:** `MainThreadRequired = true`. Persisted in SessionState by default: your enabled/interval choice survives a domain reload (dies with the editor process/session). + +Use `persist=false` for a change you only want in effect until the next unrelated recompile — e.g. a short profiling run at `interval_ms=0` (pegs a CPU core) or a one-off test/CI script — so it can't outlive its purpose and silently burn CPU for the rest of the session. Leave `persist` at its default `true` for a setting you want to remain in effect across recompiles, such as the normal always-on 16ms tick. + +### `get_performance_stats` +Read render, memory, and frame-timing stats (structured, read-only). + +No parameters. + +**Returns:** `PerformanceStats` + +### `audit` +Run a Project Auditor static-analysis scan. Returns immediately; poll `audit_status` until status is `completed`, then read the CSV. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `categories` | no | `–` | Comma-separated issue categories to scan (e.g. `Code,ProjectSetting,Texture`). Default: all categories. An unknown name is rejected with an error listing the valid values. | +| `output` | no | `–` | CSV output path (absolute, or relative to the project root). Defaults to `/Temp/pipeline-audit/.csv`. | + +**Returns:** `object` — `{ status, scanId, csvPath }` on start, or `{ status: "unavailable" | "error" | "busy", message }`. +**Notes:** Requires Project Auditor in the Editor. Only one scan runs at a time (a second call returns `busy`). Not cancellable: stop polling to abandon a scan. + +### `audit_status` +Get the status of the last audit: `idle` | `scanning` | `completed` | `failed` | `interrupted` | `unavailable`. + +No parameters. + +**Returns:** `AuditStatus` (JSON) — `issueCount` and `csvPath` are populated when `completed`; `error` when `failed`; `message` when `unavailable`. +**Notes:** `MainThreadRequired = false`, so it answers while a scan holds the main thread (Code analysis compiles assemblies). `interrupted` means a domain reload killed an in-flight scan — re-run `audit`. + +#### Project Auditor prerequisites + +`audit` needs both Project Auditor **and** its rules: + +- **Project Auditor absent** — `audit` returns `unavailable` immediately. +- **Rules absent** — when Project Auditor ships as a built-in editor module, its rules (descriptors, + API/obsolete databases, Roslyn analyzers) come from the separate `com.unity.project-auditor-rules` + package. Without it Project Auditor registers no analysis modules and cannot analyze anything, so + `audit` returns `scanning` and the first `audit_status` poll reports `unavailable` with a message + naming the package to install. It never reports an empty `completed` scan, which would read as a + clean project. + +The CSV columns are `Category, Severity, Areas, Description, RelativePath, Line, DescriptorId, Recommendation`; +only diagnostics (things to fix) are emitted, not raw inventory rows. + +### `report_evals` +Aggregate the local eval-usage telemetry into a ranked report: API fingerprint frequency, one-liner percentage, error rate, and command-coverage suggestions (read-only). See [Eval usage telemetry](#eval-usage-telemetry) below. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `top` | no | `50` | Maximum entries in each ranked list: the fingerprint ranking and the uncovered patterns suggested as commands. Accepted range: 0 or greater; negative values fall back to the default. | + +**Returns:** `EvalUsageReport` +**Notes:** `MainThreadRequired = false` (stays servable while the Editor is settling). Reads `/Library/Pipeline/eval-usage.jsonl` merged with the rotated `eval-usage.old.jsonl` (oldest first), so the report covers the full retained history — bounded to roughly 2× the size cap. Returns a zeroed report if no evals have been recorded. The report's `distinctFingerprints` field carries the uncapped total of distinct fingerprints so truncation of the ranked list is always visible; coverage suggestions are computed from the full ranking, not the capped list. + +## Eval usage telemetry + +The `eval`/`eval_file` commands are the workhorse of autonomous agent sessions, but they are opaque: raw C# through the protocol, unauditable, and hard to displace with typed commands without knowing what agents actually run. This telemetry closes that loop by recording, **locally**, what each eval does — so the [eval-displacement epic (AUTHAPI-24)](https://jira.unity3d.com/browse/AUTHAPI-24) can be triaged from data instead of anecdotes. + +### What is recorded, and where + +Every `eval`/`eval_file` invocation appends one JSON object (one line, JSONL) to `/Library/Pipeline/eval-usage.jsonl`: + +| Field | Meaning | +|-------|---------| +| `time` | ISO-8601 UTC timestamp. | +| `command` | `eval` or `eval_file`. | +| `success` / `error` | Whether it succeeded; short error category on failure. | +| `payloadLength` / `lineCount` | Size/shape of the eval body. | +| `executionTimeMs` | How long it took. | +| `classification` | `single-expression` (a one-liner: one invoke / read / assignment) or `statements` (multi-statement bodies, e.g. polling loops, bulk setup). | +| `fingerprints` | The top-level member-access paths from the syntax tree — e.g. `AssetDatabase.Refresh`, `PlayerSettings.SetScriptingBackend`, `Object.FindFirstObjectByType`, `MatchManager.Instance.State`. Rendering is a strict whitelist: the only source text that can appear in a fingerprint is an identifier, type name, or member name. Literals, interpolated strings, and any other expression form are replaced by the neutral `` placeholder (`"…".Length` records as `.Length`); object creations record as `new TypeName` (constructor arguments never appear); casts unwrap to the inner expression; generic type arguments normalise to ``. A fingerprint that would be nothing but the placeholder is dropped. | +| `source` | The raw eval source — **absent by default**; present only when the opt-in below is enabled, and truncated at 64 K characters with an explicit `…[truncated]` marker (`payloadLength` still reports the full length). | + +**Local-first, privacy-first, editor-only.** Nothing is transmitted off the machine, and nothing is recorded outside the Editor: player builds — including development players, where eval itself is available — never write telemetry (recording compiles to a no-op there). The fingerprint is derived from the C# syntax tree, so the log captures *which APIs* agents reach for without capturing *what data* they operate on. Conditional-access chains (`a?.B.C`) are fingerprinted with `?.` normalised to `.` so they rank with their unconditional form. The fingerprint deliberately undercounts a few forms (arguments nested inside a chain's receiver call, bare object creations) — see the `EvalUsageFingerprinter` class doc for the full blind-spot list before treating absence as proof of non-use. + +**Zero eval latency.** Recording is fire-and-forget: when an eval completes, the source and outcome plus the current settings are snapshotted, and the parse → fingerprint → append runs on a background thread from that snapshot — the eval response is never delayed by telemetry. The JSONL is bounded by a size cap and rotates to `eval-usage.old.jsonl`; the rotated file is merged back into `report_evals`, so retained history is bounded to roughly 2× the cap. + +### Settings + +Configured on the `EditorPipelineManager` settings asset (`Window/Pipeline/Settings...`). Edits apply live from the inspector, and the stored values are re-applied on every server start: + +- **Eval Telemetry Enabled** (default on) — master switch. When off, nothing is recorded (and, as always, nothing is transmitted). +- **Store Eval Source** (default off) — the explicit opt-in to also persist the raw eval `source` in each record, for local debugging only. + +### The feedback loop: report → backlog triage + +Run `report_evals` to aggregate the log into an `EvalUsageReport`: + +- **Ranked fingerprints** with counts — what agents actually eval, most-used first. +- **One-liner percentage** and **error rate** — the shape of eval usage (the evidence base for AUTHAPI-24 is that ~80% of eval calls are one-liners). +- **Coverage suggestions** — each fingerprint is cross-referenced against the live command catalog: + - `covered`: patterns already served by an existing command (e.g. `PlayerSettings.SetScriptingBackend` → `set_player_settings`) — these are habit, and should move off eval. + - `topUncovered`: the highest-frequency patterns with no covering command (e.g. `AssetDatabase.Refresh` → proposed `refresh_assets`) — these are the next typed commands to build ([AUTHAPI-17](https://jira.unity3d.com/browse/AUTHAPI-17)). + +This turns backlog triage into a lookup: "12× `AssetDatabase.Refresh`, no command → build it; 60× state-read loops → `wait_for`". Re-run across sessions to demonstrate eval's shrinking share as typed commands land. + +### `get_authoring_root` +Get the base folder (under Assets/) that bare authoring paths resolve against. + +No parameters. + +**Returns:** `object` + +### `set_authoring_root` +Set the base folder (under Assets/) that bare authoring paths resolve against and are confined to. Use 'Assets' for full project access. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `root` | yes | `–` | Project-relative folder under Assets/, e.g. Assets/AgentWork. Use 'Assets' to allow the whole project. | + +**Returns:** `object` + +See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md). diff --git a/AIClient/Packages/com.unity.pipeline/Documentation~/commands/gameobjects-and-components.md b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/gameobjects-and-components.md new file mode 100644 index 0000000..ca1e4cc --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/gameobjects-and-components.md @@ -0,0 +1,169 @@ +# GameObject & component commands + +Commands for creating GameObjects, querying the scene hierarchy, mutating the core GameObject/Transform surface, and adding/removing components and editing their serialized properties. Scene mutations are wrapped in Unity's Undo system (so a multi-step action reverts as one collapsible step) and are blocked during Play mode. Objects are referenced by an `ObjectRef` handle (globalId/path/guid/instanceId/hierarchyPath), and results come back as `AuthoringResult` identities you can chain into a follow-up call. + +### `create_gameobject` +Create an empty GameObject or a built-in primitive (cube/sphere/capsule/cylinder/plane/quad) in the active scene. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `name` | no | `–` | Name for the new GameObject. Defaults to 'GameObject' (or the primitive name). | +| `primitive` | no | `–` | Optional primitive type: cube, sphere, capsule, cylinder, plane, quad. Omit for an empty GameObject. | +| `parent` | no | `–` | Optional parent handle (globalId/path/guid/instanceId/hierarchyPath). The new object becomes a child of it. | + +**Returns:** `AuthoringResult` +**Notes:** Undo-able; blocked during Play mode. + +### `create_gameobjects` +Batch-create N empty GameObjects or primitives in one call. Optional positions/rotations/scales are arrays of [x,y,z] (length must equal count). Returns the created identities. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `name` | no | `–` | Base name. With count>1 and no explicit names, objects are suffixed Name1..NameN. | +| `primitive` | no | `–` | Optional primitive type: cube, sphere, capsule, cylinder, plane, quad. Omit for empty GameObjects. | +| `parent` | no | `–` | Optional parent handle. Every created object becomes a child of it. | +| `count` | no | `1` | How many GameObjects to create. Default 1. | +| `positions` | no | `–` | Local positions, one [x,y,z] per object. Length must equal count when supplied. | +| `rotations` | no | `–` | Local Euler rotations (degrees), one [x,y,z] per object. Length must equal count when supplied. | +| `scales` | no | `–` | Local scales, one [x,y,z] per object. Length must equal count when supplied. | + +**Returns:** `CreateGameObjectsResult` +**Notes:** Undo-able (the whole batch reverts as one step); blocked during Play mode. + +### `find_gameobjects` +Find GameObjects in loaded scenes by name, tag, component type, and/or hierarchy path (filters are combined). Returns structured identities. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `name` | no | `–` | Exact name to match. | +| `tag` | no | `–` | Tag to match (e.g. 'Player'). | +| `type` | no | `–` | Component type name to match (e.g. 'Rigidbody', 'UnityEngine.Camera'). | +| `hierarchy_path` | no | `–` | Exact hierarchy path to match (e.g. '/Root/Child'). | +| `include_inactive` | no | `true` | Include inactive GameObjects. Default true. | + +**Returns:** `FindGameObjectsResult` + +### `set_transform` +Set a GameObject's local position/rotation(euler)/scale. Omitted channels are left unchanged. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `target` | yes | – | Handle of the GameObject to modify. | +| `position` | no | `–` | Local position as [x,y,z]. | +| `rotation` | no | `–` | Local rotation as Euler angles [x,y,z] in degrees. | +| `scale` | no | `–` | Local scale as [x,y,z]. | + +**Returns:** `AuthoringResult` +**Notes:** Undo-able; blocked during Play mode. + +### `set_parent` +Reparent a GameObject under a new parent, or detach it to scene root when no parent is given. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `target` | yes | – | Handle of the GameObject to reparent. | +| `parent` | no | `–` | Handle of the new parent. Omit (or empty) to move the object to the scene root. | +| `world_position_stays` | no | `true` | Keep the object's world position when reparenting. Default true. | + +**Returns:** `AuthoringResult` +**Notes:** Undo-able; blocked during Play mode. + +### `set_active` +Set a GameObject's active self-state (activeSelf). + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `target` | yes | – | Handle of the GameObject. | +| `active` | yes | – | Desired active state. | + +**Returns:** `AuthoringResult` +**Notes:** Undo-able; blocked during Play mode. + +### `set_tag` +Set a GameObject's tag (the tag must already exist in the project). + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `target` | yes | – | Handle of the GameObject. | +| `tag` | yes | – | Tag to assign (must exist in the Tag Manager). | + +**Returns:** `AuthoringResult` +**Notes:** Undo-able; blocked during Play mode. + +### `set_layer` +Set a GameObject's layer by name or numeric index (0-31). + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `target` | yes | – | Handle of the GameObject. | +| `layer` | yes | – | Layer name (e.g. 'UI') or numeric index 0-31. | + +**Returns:** `AuthoringResult` +**Notes:** Undo-able; blocked during Play mode. + +### `rename_gameobject` +Rename a GameObject. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `target` | yes | – | Handle of the GameObject. | +| `name` | yes | – | New name. | + +**Returns:** `AuthoringResult` +**Notes:** Undo-able; blocked during Play mode. + +### `delete_gameobject` +Delete a GameObject from the scene (reversible via Undo). + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `target` | yes | – | Handle of the GameObject to delete. | + +**Returns:** `AuthoringResult` +**Notes:** Undo-able; blocked during Play mode. The result describes the object's identity captured before destruction. + +### `add_component` +Add a component (by type name) to a GameObject. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `target` | yes | – | Handle of the GameObject. | +| `type` | yes | – | Component type name (e.g. 'Rigidbody' or 'UnityEngine.Camera'). | + +**Returns:** `AuthoringResult` +**Notes:** Undo-able; blocked during Play mode. + +### `remove_component` +Remove a component from a GameObject. Provide either a component handle (target) or a GameObject handle (target) plus a type name. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `target` | yes | – | Handle of the component to remove, OR of the GameObject when 'type' is given. | +| `type` | no | `–` | Component type name to remove from the target GameObject (omit when 'target' already points at a component). | + +**Returns:** `AuthoringResult` +**Notes:** Undo-able; blocked during Play mode. + +### `get_component_properties` +Get a component's serialized properties as a JSON map. Address the component by handle, or by GameObject handle + type. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `target` | yes | – | Handle of the component, OR of the GameObject when 'type' is given. | +| `type` | no | `–` | Component type name on the target GameObject (omit when 'target' is a component handle). | + +**Returns:** `ComponentPropertiesResult` + +### `set_component_properties` +Set serialized properties on a component (one Undo step). 'properties' maps property name -> value; object references accept an ObjectRef handle. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `target` | yes | – | Handle of the component, OR of the GameObject when 'type' is given. | +| `properties` | yes | – | Map of serialized property name to value. Vectors/colors are arrays; object refs are handle objects. | +| `type` | no | `–` | Component type name on the target GameObject (omit when 'target' is a component handle). | + +**Returns:** `ComponentPropertiesResult` +**Notes:** Undo-able (one Undo step); blocked during Play mode. An unknown property name fails the whole batch (no partial apply). + +See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md). diff --git a/AIClient/Packages/com.unity.pipeline/Documentation~/commands/materials.md b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/materials.md new file mode 100644 index 0000000..7cb352d --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/materials.md @@ -0,0 +1,55 @@ +# Material & shader commands + +Read and edit material shader properties, and discover/introspect shaders so an agent can pick a valid shader name and property set. + +## Materials + +### `get_material_properties` +Read a material's shader, render queue, enabled keywords, and all shader properties with their current values (Color as [r,g,b,a], Vector as [x,y,z,w], Texture as an object reference). + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `material` | yes | `–` | Reference to the .mat asset (or a loaded material) to read (path / guid / globalId / instanceId). | + +**Returns:** `MaterialPropertiesResult` + +### `set_material_properties` +Set shader properties on a material (Float/Range/Int=number; Color=[r,g,b,a] or "#RRGGBBAA" hex; Vector=[x,y,z,w]; Texture=an object reference or null to clear), optionally reassign the shader, set the render queue, and toggle keywords. Unknown names / type mismatches are reported in `unknown[]`. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `material` | yes | `–` | Reference to the .mat asset (or a loaded material) to edit (path / guid / globalId / instanceId). | +| `shader` | no | `–` | Reassign the material's shader by name (e.g. "Standard", "Universal Render Pipeline/Lit", or a Shader Graph shader name). Applied before properties so new property names resolve against the new shader. | +| `properties` | no | `–` | JSON object of shader property name -> value. Names must include the leading underscore (e.g. _BaseColor). Float/Range/Int=number; Color=[r,g,b,a] or hex string; Vector=[x,y,z,w]; Texture=an object reference {guid/path} or null. | +| `renderQueue` | no | `–` | Explicit render queue, or -1 to inherit from the shader. Omit to leave unchanged. | +| `enableKeywords` | no | `–` | Shader keywords to enable (e.g. _NORMALMAP, _EMISSION). | +| `disableKeywords` | no | `–` | Shader keywords to disable. | +| `confirm` | no | `false` | Reserved for parity; editing an existing material is non-destructive and undoable, so it is not required. | +| `dry_run` | no | `false` | If true, validate the shader, resolve property names and texture refs, and report applied[]/unknown[] without writing anything. | + +**Returns:** `SetMaterialPropertiesResult` + +## Shaders + +### `list_shaders` +Discover available shaders so an agent can pick a valid name for set_material_properties / create_asset. Returns `[{ name, assetPath, isBuiltin, isSupported }]` — `assetPath` is omitted for built-in shaders in the default lean reply (pass `verbose: true` on the request for an explicit `assetPath: null`); use `isBuiltin` to classify. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `filter` | no | `–` | Case-insensitive substring matched against the shader name (e.g. "URP", "Lit"). | +| `includeBuiltin` | no | `true` | Include built-in/engine shaders (those with no project asset path). | +| `limit` | no | `200` | Maximum number of shaders to return. | + +**Returns:** `object` (list of `ShaderInfo`) + +### `get_shader_properties` +Introspect a shader's declared property list (name, description, type Color|Vector|Float|Range|TexEnv|Int, range, textureDimension, flags). Provide `shader` (by name) OR `material` (read the shader off that material). + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `shader` | no | `–` | Shader name (e.g. "Universal Render Pipeline/Lit"). Provide this OR 'material'. | +| `material` | no | `–` | Reference to a material to read the shader from instead of naming it. Provide this OR 'shader'. | + +**Returns:** `ShaderPropertiesResult` + +See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md). diff --git a/AIClient/Packages/com.unity.pipeline/Documentation~/commands/navigation.md b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/navigation.md new file mode 100644 index 0000000..fed671f --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/navigation.md @@ -0,0 +1,32 @@ +# Navigation & selection commands + +Commands to read and drive the Editor selection, and to run Unity Search queries. All commands are read-only or non-destructive and run on the main thread. + +### `get_selection` +Read the current Editor selection as structured object identities. + +No parameters. + +**Returns:** `SelectionResult` + +### `set_selection` +Set the Editor selection to the given assets/scene objects. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `instance_ids` | no | `–` | Scene/loaded object instance IDs to select. | +| `paths` | no | `–` | Asset paths to select (e.g. Assets/Foo.prefab). | + +**Returns:** `SelectionResult` + +### `search` +Run a Unity Search query and return structured results. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `query` | yes | `–` | Unity Search query string, e.g. 't:Material', 'p: my asset', 'h: Main Camera'. | +| `limit` | no | `50` | Max results to return (capped 200). | + +**Returns:** `SearchResult` + +See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md). diff --git a/AIClient/Packages/com.unity.pipeline/Documentation~/commands/package-manager.md b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/package-manager.md new file mode 100644 index 0000000..d84010e --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/package-manager.md @@ -0,0 +1,70 @@ +# Package Manager commands + +These commands query and modify the project's UPM package set (list, search, add, remove, resolve, status) over `UnityEditor.PackageManager`. Read-only queries block until the registry responds and return synchronously; mutating commands (`package_add`/`package_remove`) require `confirm=true`, support `dry_run` previews, and are async by default (poll `package_status`) with an optional `wait=true` to block until done. + +### `package_list` +List packages by scope: installed (default) | available (registry) | all (both). Returns the full result synchronously — available/all block until the registry query completes. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `scope` | no | `installed` | Which packages to list: installed (default) | available | all. | +| `include_indirect` | no | `true` | Include indirect (transitive) installed dependencies (applies to scope=installed/all). | +| `offline` | no | `false` | For available/all: query the local cache instead of the registry. | + +**Returns:** `object` +**Notes:** `MainThreadRequired = false`. Synchronous — `available`/`all` start a registry query and block until it completes (up to a 25s timeout); `installed` reads the resolved set inline on the main thread. + +### `package_search` +Search packages available in the registry. Provide a name (e.g. com.unity.foo) or omit to list all. Returns the full result synchronously (blocks until the registry query completes). + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `query` | no | `–` | Package name to search for. Omit/empty to list all available packages. | +| `offline` | no | `false` | Search the local cache only. | + +**Returns:** `object` +**Notes:** `MainThreadRequired = false`. Synchronous — blocks until the registry query completes (up to a 25s timeout). Each result is flagged with whether it is currently installed. + +### `package_add` +Add a UPM package by name@version, git URL, or 'file:' local path. Async by default (returns in_progress; poll package_status); pass wait=true to block until added. A recompile/domain reload follows — poll recompile_status. Requires confirm=true; use dry_run to preview. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `identifier` | yes | `–` | Package to add: 'com.unity.foo@1.2.3', a git URL, or 'file:../Path'. | +| `confirm` | no | `false` | Apply the change. Without it the call is refused. | +| `dry_run` | no | `false` | Preview the change without applying it. | +| `wait` | no | `false` | Block until the operation completes and return the result (synchronous). Default: return immediately and poll package_status. | + +**Returns:** `object` +**Notes:** `MainThreadRequired = false`. Mutating — requires `confirm=true`; `dry_run=true` returns a preview without applying. Async by default (returns `in_progress`; poll `package_status`); with `wait=true` it blocks until completion (up to a 25s timeout). A successful add triggers a recompile/domain reload — poll `recompile_status`. Returns `busy` if another package operation is already in progress. + +### `package_remove` +Remove a UPM package by name. Async by default (returns in_progress; poll package_status); pass wait=true to block until removed. A recompile/domain reload follows — poll recompile_status. Requires confirm=true; use dry_run to preview. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `name` | yes | `–` | Package name to remove (e.g. com.unity.foo). | +| `confirm` | no | `false` | Apply the change. Without it the call is refused. | +| `dry_run` | no | `false` | Preview the change without applying it. | +| `wait` | no | `false` | Block until the operation completes and return the result (synchronous). Default: return immediately and poll package_status. | + +**Returns:** `object` +**Notes:** `MainThreadRequired = false`. Mutating — requires `confirm=true`; `dry_run=true` returns a preview without applying. Async by default (returns `in_progress`; poll `package_status`); with `wait=true` it blocks until completion (up to a 25s timeout). A successful remove triggers a recompile/domain reload — poll `recompile_status`; the reload can drop a synchronous reply, so `package_status` confirms the outcome. Returns `busy` if another package operation is already in progress. + +### `package_resolve` +Resolve/refresh packages from the manifest (re-fetch and re-link). May trigger a recompile/domain reload — poll recompile_status. Its outcome is recorded for package_status. + +No parameters. + +**Returns:** `object` +**Notes:** `MainThreadRequired = true`. Fire-and-forget — `Client.Resolve()` schedules a resolve on a later tick, so the response returns before any reload. May trigger a recompile/domain reload — poll `recompile_status`. Its outcome is recorded in the status file, so `package_status` validates it. + +### `package_status` +Status of the last async package operation (add/remove/resolve): idle | in_progress | completed | failed, with the added package, manifest, and any error. + +No parameters. + +**Returns:** `string` +**Notes:** `MainThreadRequired = false`. Reads a Temp status file that survives the domain reload an add/remove/resolve triggers, so a lost synchronous reply or an interrupted async op is recoverable by polling. Returns `{"status":"idle"}` when no operation has run. + +See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md). diff --git a/AIClient/Packages/com.unity.pipeline/Documentation~/commands/prefabs.md b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/prefabs.md new file mode 100644 index 0000000..9f5c13a --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/prefabs.md @@ -0,0 +1,84 @@ +# Prefab commands + +Commands covering the prefab lifecycle an agent needs to build content procedurally: saving a configured GameObject as a prefab asset, instantiating it into a scene, deriving a variant, applying/reverting instance overrides, unpacking, and editing prefab contents through the prefab stage. Asset paths are sandboxed to the authoring root; scene-side mutations are Undo-able, but prefab asset writes are AssetDatabase operations and are not part of Unity's Undo system. + +### `create_prefab` +Save a GameObject as a prefab asset at a project path; the source becomes a connected instance. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `source` | yes | – | Reference to the source GameObject to save as a prefab (globalId/path/guid/instanceId/hierarchyPath). | +| `path` | yes | – | Prefab asset path relative to the authoring root (the Assets/ prefix is optional and the .prefab extension is added if missing). e.g. Prefabs/Enemy or Prefabs/Enemy.prefab | + +**Returns:** `AuthoringResult` +**Notes:** Scene-side effects are Undo-able; the prefab asset write is not undoable. + +### `instantiate_prefab` +Instantiate a prefab asset into a loaded scene and return the created instance. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `prefab` | yes | – | Reference to the prefab asset to instantiate (path/guid/globalId). | +| `scene_path` | no | `–` | Optional path of a loaded scene to instantiate into; defaults to the active scene. | +| `name` | no | `–` | Optional name for the created instance; defaults to the prefab name. | + +**Returns:** `AuthoringResult` +**Notes:** Undo-able. + +### `create_prefab_variant` +Create a prefab variant asset that inherits from a base prefab. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `base` | yes | – | Reference to the base prefab asset (path/guid/globalId). | +| `path` | yes | – | Variant prefab asset path relative to the authoring root (.prefab added if missing). | + +**Returns:** `AuthoringResult` +**Notes:** Prefab asset write is not undoable. + +### `apply_prefab_overrides` +Apply a prefab instance's overrides back to its source prefab asset. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `instance` | yes | – | Reference to a prefab instance GameObject in a scene (instanceId/hierarchyPath/globalId). | + +**Returns:** `AuthoringResult` +**Notes:** Scene-side effects are Undo-able; the asset write is not. The instance's source prefab asset must live under the authoring root. + +### `revert_prefab_overrides` +Revert a prefab instance's overrides so it matches its source prefab asset. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `instance` | yes | – | Reference to a prefab instance GameObject in a scene (instanceId/hierarchyPath/globalId). | + +**Returns:** `AuthoringResult` +**Notes:** Undo-able. + +### `unpack_prefab` +Unpack a prefab instance into plain GameObjects (outermost level or completely). + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `instance` | yes | – | Reference to a prefab instance GameObject in a scene (instanceId/hierarchyPath/globalId). | +| `completely` | no | `false` | If true, unpack all nested prefab levels (Completely); if false, only the outermost level (OutermostRoot). | + +**Returns:** `AuthoringResult` +**Notes:** Undo-able. + +### `save_prefab_contents` +Open a prefab asset in an isolated prefab stage, apply a declarative edit, and save it back (nested-prefab safe). + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `prefab` | yes | – | Reference to the prefab asset to edit (path/guid/globalId). | +| `rename_child` | no | `–` | Optional child name (relative path under the root, e.g. 'Body/Head') to rename. | +| `new_name` | no | `–` | New name for the child identified by rename_child. | +| `set_active_child` | no | `–` | Optional child name (relative path under the root) whose active state to set. | +| `active` | no | `true` | Active state to apply when set_active_child is provided. | + +**Returns:** `AuthoringResult` +**Notes:** Prefab asset write (prefab-stage save) is not part of Unity's Undo system. The prefab asset must live under the authoring root. + +See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md). diff --git a/AIClient/Packages/com.unity.pipeline/Documentation~/commands/project-settings.md b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/project-settings.md new file mode 100644 index 0000000..0c398a4 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/project-settings.md @@ -0,0 +1,270 @@ +# Project settings commands + +Read and change a representative slice of Unity's project-wide settings (Audio, Graphics, Input, Physics, Player, Quality, Runtime Pipeline, Tags & Layers, Time). `get_*` commands read a group's current values into a `ProjectSettingsResponse`; `set_*` commands mutate them through the shared `confirm`/`dry_run` convention, so `confirm=true` is required to apply and `dry_run=true` previews the change without applying it. Every command in this group is `MainThreadRequired = true`. On a `set_*`, omitted fields are left unchanged, and the group is re-read after the write so the response reflects the resulting state. Settings writes are not undoable via Ctrl+Z. + +### `get_audio_settings` +Read project Audio settings (volume, rolloff scale, doppler factor). + +No parameters. + +**Returns:** `ProjectSettingsResponse` +**Notes:** `MainThreadRequired = true`. + +### `set_audio_settings` +Change project Audio settings. Requires confirm=true; use dry_run to preview. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `settings` | no | `–` | Fields to change; omitted fields are left unchanged (fields below). | +| `confirm` | no | `false` | Apply the change. Without it the call is refused. | +| `dry_run` | no | `false` | Preview the change without applying it. | + +`settings` fields: + +| Field | Required | Default | Description | +|-------|----------|---------|-------------| +| `volume` | no | `–` | Global audio volume (0..1). | +| `rolloffScale` | no | `–` | Global rolloff scale. | +| `dopplerFactor` | no | `–` | Global doppler factor. | + +**Returns:** `ProjectSettingsResponse` +**Notes:** `MainThreadRequired = true`. `confirm=true` required to apply; supports `dry_run`. + +### `get_graphics_settings` +Read GraphicsSettings (default render pipeline). + +No parameters. + +**Returns:** `ProjectSettingsResponse` +**Notes:** `MainThreadRequired = true`. + +### `set_graphics_settings` +Set the default render pipeline asset. Requires confirm=true; use dry_run to preview. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `settings` | no | `–` | Fields to change; omitted fields are left unchanged (fields below). | +| `confirm` | no | `false` | Apply the change. Without it the call is refused. | +| `dry_run` | no | `false` | Preview the change without applying it. | + +`settings` fields: + +| Field | Required | Default | Description | +|-------|----------|---------|-------------| +| `renderPipelineAsset` | no | `–` | Reference (path / guid / globalId) to a RenderPipelineAsset to set as the default. Pass an empty reference (`{}`) to select the built-in pipeline; omit to leave unchanged. | + +**Returns:** `ProjectSettingsResponse` +**Notes:** `MainThreadRequired = true`. `confirm=true` required to apply; supports `dry_run`. + +### `get_input_settings` +Read the legacy Input Manager axes (names and count). + +No parameters. + +**Returns:** `ProjectSettingsResponse` +**Notes:** `MainThreadRequired = true`. + +### `set_input_settings` +Tune a legacy Input Manager axis (sensitivity/gravity/dead) by name. Requires confirm=true; use dry_run to preview. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `settings` | no | `–` | Axis change. 'axis' selects the axis by name; omitted numeric fields are left unchanged (fields below). | +| `confirm` | no | `false` | Apply the change. Without it the call is refused. | +| `dry_run` | no | `false` | Preview the change without applying it. | + +`settings` fields: + +| Field | Required | Default | Description | +|-------|----------|---------|-------------| +| `axis` | yes | – | Name of the axis to modify (e.g. 'Horizontal'). | +| `sensitivity` | no | `–` | New sensitivity. | +| `gravity` | no | `–` | New gravity. | +| `dead` | no | `–` | New dead-zone size. | + +**Returns:** `ProjectSettingsResponse` +**Notes:** `MainThreadRequired = true`. `confirm=true` required to apply; supports `dry_run`. + +### `get_physics_settings` +Read Physics settings (gravity, solver iterations, bounce threshold). + +No parameters. + +**Returns:** `ProjectSettingsResponse` +**Notes:** `MainThreadRequired = true`. + +### `set_physics_settings` +Change Physics settings. Requires confirm=true; use dry_run to preview. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `settings` | no | `–` | Fields to change; omitted fields are left unchanged (fields below). | +| `confirm` | no | `false` | Apply the change. Without it the call is refused. | +| `dry_run` | no | `false` | Preview the change without applying it. | + +`settings` fields: + +| Field | Required | Default | Description | +|-------|----------|---------|-------------| +| `gravityX` | no | `–` | Gravity X component. | +| `gravityY` | no | `–` | Gravity Y component (e.g. -9.81). | +| `gravityZ` | no | `–` | Gravity Z component. | +| `defaultSolverIterations` | no | `–` | Default solver iteration count. | +| `bounceThreshold` | no | `–` | Bounce threshold velocity. | + +**Returns:** `ProjectSettingsResponse` +**Notes:** `MainThreadRequired = true`. `confirm=true` required to apply; supports `dry_run`. + +### `get_player_settings` +Read PlayerSettings (company/product/version, scripting backend, API level). + +No parameters. + +**Returns:** `ProjectSettingsResponse` +**Notes:** `MainThreadRequired = true`. + +### `set_player_settings` +Change PlayerSettings. Requires confirm=true; use dry_run to preview. Scripting backend / API level changes trigger a domain reload. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `settings` | no | `–` | Fields to change; omitted fields are left unchanged (fields below). | +| `confirm` | no | `false` | Apply the change. Without it the call is refused. | +| `dry_run` | no | `false` | Preview the change without applying it. | + +`settings` fields: + +| Field | Required | Default | Description | +|-------|----------|---------|-------------| +| `companyName` | no | `–` | Company name. | +| `productName` | no | `–` | Product name. | +| `bundleVersion` | no | `–` | Bundle/application version string. | +| `scriptingBackend` | no | `–` | Scripting backend (e.g. Mono2x, IL2CPP). Triggers a domain reload. | +| `apiCompatibilityLevel` | no | `–` | API compatibility level (e.g. NET_Standard_2_0, NET_Unity_4_8). Triggers a domain reload. | + +**Returns:** `ProjectSettingsResponse` +**Notes:** `MainThreadRequired = true`. `confirm=true` required to apply; supports `dry_run`. Changing `scriptingBackend` or `apiCompatibilityLevel` triggers a domain reload (`requiresDomainReload`); scripting-backend / API-level changes are read and written against the active build target. + +### `get_quality_settings` +Read QualitySettings (current level, level names, vSync, anti-aliasing). + +No parameters. + +**Returns:** `ProjectSettingsResponse` +**Notes:** `MainThreadRequired = true`. + +### `set_quality_settings` +Change QualitySettings. Requires confirm=true; use dry_run to preview. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `settings` | no | `–` | Fields to change; omitted fields are left unchanged (fields below). | +| `confirm` | no | `false` | Apply the change. Without it the call is refused. | +| `dry_run` | no | `false` | Preview the change without applying it. | + +`settings` fields: + +| Field | Required | Default | Description | +|-------|----------|---------|-------------| +| `level` | no | `–` | Quality level index (see levelNames from get_quality_settings). | +| `vSyncCount` | no | `–` | VSync count (0 = off, 1, 2). | +| `antiAliasing` | no | `–` | MSAA sample count (0, 2, 4, 8). | + +**Returns:** `ProjectSettingsResponse` +**Notes:** `MainThreadRequired = true`. `confirm=true` required to apply; supports `dry_run`. + +### `get_runtime_pipeline_settings` +Read Pipeline Runtime settings (enableInBuilds, port, requestTimeoutMs, enableAuditLogging, autoStart, maxWorkItemsPerFrame). Reports the settings in effect, falling back to built-in defaults when none have been authored; never creates the settings file. + +No parameters. + +**Returns:** `ProjectSettingsResponse` +**Notes:** `MainThreadRequired = true`. + +### `set_runtime_pipeline_settings` +Change Pipeline Runtime settings. Requires confirm=true; use dry_run to preview. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `settings` | no | `–` | Fields to change; omitted fields are left unchanged (fields below). | +| `confirm` | no | `false` | Apply the change. Without it the call is refused. | +| `dry_run` | no | `false` | Preview the change without applying it. | + +`settings` fields: + +| Field | Required | Default | Description | +|-------|----------|---------|-------------| +| `enableInBuilds` | no | `–` | Enable the Pipeline HTTP server in Player builds. SECURITY WARNING: only enable in development/QA builds. | +| `port` | no | `–` | HTTP port for the Pipeline server. 0 = auto-assign from range 7900-7999. | +| `requestTimeoutMs` | no | `–` | Request timeout in milliseconds. | +| `enableAuditLogging` | no | `–` | Log every remote request for security auditing. | +| `autoStart` | no | `–` | Start the server automatically when the Player boots (or Play Mode is entered). | +| `maxWorkItemsPerFrame` | no | `–` | Maximum work items the dispatcher processes per frame. | + +**Returns:** `ProjectSettingsResponse` +**Notes:** `MainThreadRequired = true`. `confirm=true` required to apply; supports `dry_run`. Refused while in Play Mode — the running driver already loaded its own settings, so a change would silently not apply until the next Play session or build. `port` (0-65535), `requestTimeoutMs` (1000-60000), and `maxWorkItemsPerFrame` (1-50) are rejected outright with a `Fail` response if outside these bounds — the same ones the Project Settings page enforces — rather than being clamped or silently applied. + +### `get_tags_layers` +Read the project's tags and (named) layers. + +No parameters. + +**Returns:** `ProjectSettingsResponse` +**Notes:** `MainThreadRequired = true`. + +### `set_tags_layers` +Add/remove tags and assign user layer names (index 8-31). Requires confirm=true; use dry_run to preview. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `settings` | no | `–` | Tag/layer changes to make (fields below). | +| `confirm` | no | `false` | Apply the change. Without it the call is refused. | +| `dry_run` | no | `false` | Preview the change without applying it. | + +`settings` fields: + +| Field | Required | Default | Description | +|-------|----------|---------|-------------| +| `addTags` | no | `–` | Tag names to add. | +| `removeTags` | no | `–` | Tag names to remove. | +| `setLayers` | no | `–` | User layer assignments (index 8-31); array of layer-assignment objects (fields below). | + +`setLayers[]` (layer-assignment) fields: + +| Field | Required | Default | Description | +|-------|----------|---------|-------------| +| `index` | yes | – | Layer index (8-31 for user layers). | +| `name` | yes | – | Layer name (empty string clears the slot). | + +**Returns:** `ProjectSettingsResponse` +**Notes:** `MainThreadRequired = true`. `confirm=true` required to apply; supports `dry_run`. User layers are indices 8-31 (0-7 are reserved). + +### `get_time_settings` +Read Time settings (fixedDeltaTime, maximumDeltaTime, timeScale). + +No parameters. + +**Returns:** `ProjectSettingsResponse` +**Notes:** `MainThreadRequired = true`. + +### `set_time_settings` +Change Time settings. Requires confirm=true; use dry_run to preview. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `settings` | no | `–` | Fields to change; omitted fields are left unchanged (fields below). | +| `confirm` | no | `false` | Apply the change. Without it the call is refused. | +| `dry_run` | no | `false` | Preview the change without applying it. | + +`settings` fields: + +| Field | Required | Default | Description | +|-------|----------|---------|-------------| +| `fixedDeltaTime` | no | `–` | Fixed timestep in seconds (e.g. 0.02). | +| `maximumDeltaTime` | no | `–` | Maximum allowed timestep in seconds. | +| `timeScale` | no | `–` | Time scale (1 = real-time). | + +**Returns:** `ProjectSettingsResponse` +**Notes:** `MainThreadRequired = true`. `confirm=true` required to apply; supports `dry_run`. + +See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md). diff --git a/AIClient/Packages/com.unity.pipeline/Documentation~/commands/runtime.md b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/runtime.md new file mode 100644 index 0000000..0966019 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/runtime.md @@ -0,0 +1,213 @@ +# Runtime commands + +Commands served by the Player / dev-build server. Many require a Development build with the runtime Pipeline enabled — see [Runtime setup](../runtime-setup.md). Commands marked `RuntimeOnly` are only registered in a player build. + +### `runtime_status` +Get comprehensive runtime application status. + +No parameters. + +**Returns:** `RuntimeStatusResponse` +**Notes:** `MainThreadRequired = true`, `RuntimeOnly`. + +### `quit` +Gracefully quit the Unity application. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `exitCode` | no | `0` | Exit code for the application | + +**Returns:** `string` +**Notes:** `MainThreadRequired = true`, `RuntimeOnly`. + +### `set_target_framerate` +Set the target frame rate for the application. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `frameRate` | yes | `–` | Target frame rate (-1 for platform default, 0 for unlimited) | + +**Returns:** `string` +**Notes:** `MainThreadRequired = true`, `RuntimeOnly`. + +### `set_timescale` +Set the time scale for the application. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `scale` | yes | `–` | Time scale multiplier (0.0 to pause, 1.0 for normal speed) | + +**Returns:** `string` +**Notes:** `MainThreadRequired = true`, `RuntimeOnly`. + +### `simulate_key` +Simulate a keyboard key event (Input System). Drives the running app. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `key` | yes | `–` | Input System Key name, e.g. Space, W, Enter, LeftArrow. | +| `action` | no | `press` | down \| up \| press (down+up). | + +**Returns:** `InputSimulationResponse` +**Notes:** `MainThreadRequired = true`, `RuntimeOnly`. Requires the Input System package (`ENABLE_INPUT_SYSTEM`); reports unavailable otherwise. + +### `simulate_pointer` +Simulate a mouse/pointer event at screen coordinates (Input System). + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `x` | yes | `–` | Screen X in pixels (origin bottom-left). | +| `y` | yes | `–` | Screen Y in pixels (origin bottom-left). | +| `action` | no | `click` | move \| down \| up \| click (down+up). | +| `button` | no | `left` | left \| right \| middle. | + +**Returns:** `InputSimulationResponse` +**Notes:** `MainThreadRequired = true`, `RuntimeOnly`. Requires the Input System package (`ENABLE_INPUT_SYSTEM`); reports unavailable otherwise. + +### `log` +Write a message to Unity console. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `message` | yes | `–` | Message to log to console | +| `level` | no | `info` | Log level: info, warning, error | + +**Returns:** `string` +**Notes:** `MainThreadRequired = true`, `RuntimeOnly`. + +### `console` +Get captured Unity console output (Editor or Player; supports tail, level filtering, and follow via a cursor). + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `tail` | no | `100` | Maximum number of most-recent entries to return | +| `level` | no | `log` | Minimum severity to include: log | warn | error | +| `since` | no | `-1` | Cursor: only return entries newer than this seq. Use the 'cursor' from a previous response to follow. | +| `since_session` | no | `–` | Session the `since` cursor came from: pass the `session` from a previous response. A cursor from another session is refused and the tail returned with `reset=true`. | + +**Returns:** `ConsoleLogResponse` +**Notes:** `MainThreadRequired = false`. Available in both the Editor and player builds. + +A cursor is only meaningful paired with the `session` that issued it. Sequence numbers restart from +zero when the Editor restarts (the buffer is persisted under `Temp/`, which Unity deletes at every +launch), so a cursor from an earlier session names different entries. Always echo `session` back as +`since_session`; when the pair cannot be honored the response sets `reset=true`, returns the tail +instead of nothing, and gives you a fresh `cursor`/`session` to adopt. + +Beyond the entries, the response carries: + +- `counts` — errors/warnings/logs the buffer currently retains, before the level filter and `tail`. +- `groundTruth` — what the Editor itself reports: `compilationFailed`, `compiling`, the Editor + console's own `consoleErrors`/`consoleWarnings`/`consoleLogs`, whether the buffer has been + `seeded` from the console's store, and `ageMs` for how stale the sample is. Null in a player. + +`groundTruth.consoleErrors` exceeding `counts.error` means the Editor console is showing entries the +buffer does not hold. That is expected for output produced before the package was first imported; +otherwise it is the signal that something was missed. + +### `console_status` +Console ground truth and buffer counters without pulling entries: compile-failure flag, Editor +console counts, and the buffer's retained counts and cursor. + +No parameters. + +**Returns:** `ConsoleLogResponse` with an empty `entries` array. +**Notes:** `MainThreadRequired = false`. Cheap enough to poll in a loop while a compile runs; use +`console` when you want the entries themselves. + +### `clear_console` +Clear the captured log buffer and the Unity Editor console. + +No parameters. + +**Returns:** `object` +**Notes:** Available in both the Editor and player builds; in a player only the captured buffer is +cleared, since there is no Editor console. Editor compile errors are logged as sticky entries, which +Unity's own clear skips, so they remain in the Console window until the next compile completes. +Clearing keeps the cursor, so a client following `console` sees `dropped=true` on its next poll +rather than silently skipping the window that was cleared. + +### `eval` +Evaluate C# code dynamically using Roslyn compiler. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `code` | yes | `–` | C# code to evaluate | +| `timeout` | no | `5000` | Timeout in milliseconds | + +**Returns:** `EvalResponse` +**Notes:** `MainThreadRequired = true`. Available on both editor and runtime. + +### `eval_file` +Evaluate C# code read from a `.cs` file on disk. A convenience alternative to `eval` for code +too long to pass inline — edit the file, then evaluate it. The resolved source is run through the +same evaluation path as `eval`. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `file` | yes | `–` | Path to a `.cs` file to evaluate | +| `timeout` | no | `5000` | Timeout in milliseconds | + +The `file` is read on the Unity side (relative paths resolve against the Unity process working +directory) and must end in `.cs`. A missing file, a non-`.cs` extension, or an empty file returns +a `Bad Request`. + +**Returns:** `EvalResponse` +**Notes:** `MainThreadRequired = true`. Available on both editor and runtime. + +> For anything beyond an ad-hoc one-liner — bulk construction, builder scripts — prefer the +> Editor-side [`run_script`](scripts.md#run_script) command, which compiles a versioned project +> `.cs` file in memory and runs a named entry point instead of carrying code through the protocol. + +### `reload_file` +Compile and apply [CodeReload] edits from a source file. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `filename` | yes | `–` | Source file containing [CodeReload] methods (e.g. Assets/Scripts/Player.cs) | +| `timeout` | no | `30000` | Compilation timeout in milliseconds | +| `assemblyDir` | no | `–` | Directory to save compiled assemblies to disk (optional, default is in-memory only) | +| `pdb` | no | `false` | Emit debug symbols (portable PDB) mapped to the original source so breakpoints bind in your editor. Compiles unoptimized. | + +**Returns:** `CodeReloadResponse` +**Notes:** `MainThreadRequired = true`. See [Reloading code](../code-reload.md). + +### `reload_file_editor_interpreter` +Compile [CodeReload] edits and run them through the IlInterpreter VM in this process instead of `Assembly.Load` (IL2CPP-safe; only a minimal host API + the target type are available). + +Same parameters as [`reload_file`](#reload_file). + +**Returns:** `CodeReloadResponse` +**Notes:** `MainThreadRequired = true`. See [Reloading code](../code-reload.md). + +### `reload_file_player_interpreter` +Compile a file's (or folder's) [CodeReload] methods in the Editor and push the IL to connected development players over PlayerConnection (IL2CPP-safe). Folders are walked recursively; files that do not mention `CodeReload` are skipped. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `filename` | yes | `–` | Source `.cs` file or a folder containing [CodeReload] methods (e.g. Assets/pong.cs or Assets/Scripts) | +| `player` | no | `-1` | Target connected player id; `-1` broadcasts to all connected players | + +**Returns:** `{ success, message, diagnostics }` for a file; `{ success, message, pushed, failed }` for a folder. +**Notes:** `MainThreadRequired = true`. Served by the **Editor** server (it needs Roslyn and PlayerConnection), not the player; the player only needs the runtime Pipeline driver, not its HTTP server. See [Reloading code](../code-reload.md#reload_file_player_interpreter). + +### `codereload_status` +Show current code reload registry status and statistics. + +No parameters. + +**Returns:** `CodeReloadResponse` +**Notes:** `MainThreadRequired = true`, `RuntimeOnly`. + +### `cleanup_codereload` +Remove old code reload DLL versions and clear registry. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `assemblyDir` | yes | `–` | Directory containing assemblies to cleanup | +| `force_domain_reload` | no | `true` | Force Unity domain reload after cleanup | + +**Returns:** `CodeReloadResponse` +**Notes:** `MainThreadRequired = true`, `RuntimeOnly`. + +See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md). diff --git a/AIClient/Packages/com.unity.pipeline/Documentation~/commands/scenes.md b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/scenes.md new file mode 100644 index 0000000..5d5e5af --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/scenes.md @@ -0,0 +1,93 @@ +# Scene commands + +Commands for creating, opening, saving and inspecting scenes, controlling the active scene, snapshotting a scene's hierarchy, and managing the Build Settings scene list. Mutating scene operations are blocked while the editor is entering or in play mode (they fail with a recoverable error before touching any state); read-only commands are safe in play mode. + +### `create_scene` +Create a new scene and save it to the given path under the authoring root. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `path` | yes | – | Scene path relative to the authoring root (default Assets/); the Assets/ prefix and the .unity extension are optional. e.g. Scenes/Level1 | +| `additive` | no | `false` | Open the new scene additively alongside currently open scenes instead of replacing them. | +| `template` | no | `empty` | Initial contents: 'empty' (default) for a blank scene, or 'default' to seed a Main Camera + Directional Light matching Unity's built-in 3D template. | + +**Returns:** `AuthoringResult` +**Notes:** Blocked during Play mode. + +### `open_scene` +Open an existing scene from the given path. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `path` | yes | – | Scene path relative to the authoring root (default Assets/); the Assets/ prefix and the .unity extension are optional. | +| `additive` | no | `false` | Open additively alongside currently open scenes instead of replacing them. | + +**Returns:** `AuthoringResult` +**Notes:** Blocked during Play mode. + +### `save_scene` +Save an open scene. Saves the active scene when no path is given. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `path` | no | `–` | Path of the open scene to save (authoring-root relative; Assets/ prefix and .unity optional). Omit to save the active scene. | + +**Returns:** `AuthoringResult` +**Notes:** Blocked during Play mode. + +### `save_all` +Save all open scenes that have unsaved changes. + +No parameters. + +**Returns:** `object` +**Notes:** Blocked during Play mode. + +### `list_open_scenes` +List all currently open scenes with their load/active/dirty state. + +No parameters. + +**Returns:** `object` + +### `set_active_scene` +Set which open scene is the active scene (new objects are created in the active scene). + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `path` | yes | – | Path of an already-open scene to make active (authoring-root relative; Assets/ prefix and .unity optional). | + +**Returns:** `AuthoringResult` +**Notes:** Blocked during Play mode. + +### `get_scene_hierarchy` +Return the GameObject tree of an open scene (or the active scene). Each node carries instanceId + hierarchyPath usable by GameObject commands. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `path` | no | `–` | Path of the open scene to snapshot (authoring-root relative; Assets/ prefix and .unity optional). Omit for the active scene. | + +**Returns:** `SceneHierarchy` + +### `add_scene_to_build` +Add a scene to the Build Settings scene list (idempotent). Optionally enable it. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `path` | yes | – | Scene path to add (authoring-root relative; Assets/ prefix and .unity optional). | +| `enabled` | no | `true` | Whether the scene is enabled in the build list. | + +**Returns:** `object` +**Notes:** Blocked during Play mode. + +### `remove_scene_from_build` +Remove a scene from the Build Settings scene list (idempotent). + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `path` | yes | – | Scene path to remove (authoring-root relative; Assets/ prefix and .unity optional). | + +**Returns:** `object` +**Notes:** Blocked during Play mode. + +See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md). diff --git a/AIClient/Packages/com.unity.pipeline/Documentation~/commands/scripts.md b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/scripts.md new file mode 100644 index 0000000..9c7a85e --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/scripts.md @@ -0,0 +1,111 @@ +# Script commands + +Commands for creating C# script files, attaching MonoBehaviours to GameObjects, reading/writing serialized fields, and running compiled project entry points in memory. Writing a `.cs` file does not make its type available — Unity must import and compile it (a domain reload) first. The flow is: `create_script` → `recompile` → poll `recompile_status` (until completed/up_to_date) → `attach_script`. For bulk construction that does **not** need a new persistent project type, skip the recompile entirely: [`run_script`](#run_script) compiles a file in memory and runs it with no asset import and no domain reload. + +### `create_script` +Create a new C# script (default base class MonoBehaviour) from a template under the authoring root. NOTE: the type does not exist until a recompile completes — to attach it, call recompile, poll recompile_status, then attach_script. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `name` | yes | – | Class/file name without extension, e.g. PlayerController. Must be a valid C# identifier. | +| `path` | no | `–` | Folder (relative to the authoring root; the Assets/ prefix is optional) to write the .cs into. Defaults to the authoring root. | +| `namespace` | no | `–` | Optional namespace to wrap the class in. Omit for the global namespace. | +| `base_class` | no | `MonoBehaviour` | Base class to derive from. Defaults to MonoBehaviour. | +| `overwrite` | no | `false` | Overwrite the file if it already exists. Defaults to false (an existing file is an error). | + +**Returns:** `AuthoringResult` +**Notes:** Does not trigger a recompile; the created type is not usable until a recompile completes (poll `recompile_status`). + +### `attach_script` +Add a MonoBehaviour to a GameObject by its (compiled) type name OR by its script asset path. Provide exactly one of 'type' or 'script'. If the type isn't compiled yet, returns a recoverable error: recompile, poll recompile_status, then retry. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `target` | yes | – | Reference to the GameObject to add the component to (globalId/path/guid/instanceId/hierarchyPath). | +| `type` | no | `–` | Component type name to add, e.g. PlayerController or Game.Player.PlayerController. Must already be compiled. Mutually exclusive with 'script'. | +| `script` | no | `–` | Script asset path, e.g. 'Assets/Pool/Scripts/CueShooter.cs'. The backing class is resolved via MonoScript.GetClass(), so the class name may differ from the filename. Mutually exclusive with 'type'. | + +**Returns:** `AuthoringResult` +**Notes:** Undo-able. Provide exactly one of `type` or `script`. A not-yet-compiled type returns a recoverable error (recompile, poll `recompile_status`, then retry). + +### `set_serialized_field` +Set a serialized field on a component/asset. Supports primitives, enums, Vector/Color/Rect/Bounds, object references (value = an ObjectRef: asset by guid/fileId/path or scene object by instanceId/hierarchyPath), and array elements via 'name.Array.data[i]' (or 'name.Array.size' to resize). + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `target` | yes | – | Reference to the component or asset to modify (globalId/path/guid/instanceId/hierarchyPath). May be a GameObject when 'component' is given. | +| `field` | yes | – | SerializedProperty path, e.g. 'speed', 'settings.speed', or 'waypoints.Array.data[0]'. | +| `value` | yes | – | JSON value to assign. For object references pass an ObjectRef object (or null to clear). For enums pass the value name. | +| `component` | no | `–` | Component type name on the target GameObject (e.g. 'Rigidbody'). Use when 'target' is a GameObject; omit when 'target' is already a component handle. | + +**Returns:** `AuthoringResult` +**Notes:** Undo-able. + +### `get_serialized_fields` +Read serialized fields of a component/asset. Returns each top-level field's name, type and value (object references are returned as re-usable handles). Pass 'field' to read a single SerializedProperty path. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `target` | yes | – | Reference to the component or asset to read (globalId/path/guid/instanceId/hierarchyPath). May be a GameObject when 'component' is given. | +| `field` | no | `–` | Optional single SerializedProperty path to read (e.g. 'speed' or 'items.Array.data[0]'). Omit to read all top-level fields. | +| `component` | no | `–` | Component type name on the target GameObject (e.g. 'Rigidbody'). Use when 'target' is a GameObject; omit when 'target' is already a component handle. | + +**Returns:** `object` + +### `run_script` +Compile a single project `.cs` file in memory (no domain reload, no code carried through the +protocol) and execute a named `static` entry point. This is the **builder-pattern** path for bulk +construction — see the note below. Editor command; still arbitrary code execution, so it is grouped +under the same `scripts/eval` tag as `eval` and is disabled wherever the eval family is disabled. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `file` | yes | `–` | Path to a `.cs` file. Relative paths resolve against the **project root** (the parent of `Assets/`), not the process working directory. May live **outside `Assets/`** (e.g. `AgentScripts/`) so writing it never triggers an asset import or domain reload. | +| `entry` | no | `–` | Entry point as `Namespace.Type.Method` (or `Type.Method`, or a bare `Method`). Nested types may be written with dots (`Outer.Inner.Method`). Default: the single public static method if unambiguous, else a method named `Main`. Static, non-generic methods only in v1. Ephemeral mode only — rejected with `mode=hotpatch`. | +| `args` | no | `–` | JSON array of arguments, coerced to the entry's parameter types: primitives, enum names, `string[]`, and a string/object handle (`ObjectRef`) for `UnityEngine.Object` parameters. JSON `null` is only valid for reference-type and nullable parameters (never a silent `default(T)`). Ephemeral mode only — rejected with `mode=hotpatch`. | +| `mode` | no | `ephemeral` | `ephemeral`: compile to an in-memory assembly, run the entry, discard. `hotpatch`: apply in-place `[CodeReload]` method replacements to already-loaded types (delegates to `reload_file`). | +| `references` | no | `–` | Extra assembly name prefixes to reference. In the Editor all loaded assemblies are already referenced, so this is effectively a no-op there. Ephemeral mode only; **not applied** by hotpatch (the compile is `reload_file`'s). | +| `defines` | no | `–` | Extra scripting define symbols, **appended to the project's active editor defines** (`EditorUserBuildSettings.activeScriptCompilationDefines`) — so `UNITY_EDITOR`, version and platform symbols are already set and sources behave like project code; your defines extend that set rather than replace it. Ephemeral mode only; **not applied** by hotpatch. | +| `pdb` | no | `false` | Emit a portable PDB mapped to the source file so breakpoints bind. Ephemeral runs always emit source-mapped symbols so exception stack traces carry `file:line`. Compiles unoptimized. | +| `timeout_ms` | no | `30000` | Timeout in milliseconds (governs the main-thread wait budget end-to-end, like `eval`). | +| `dry_run` | no | `false` | Compile only: return diagnostics; the emitted assembly is **not loaded** into the domain and nothing executes (the response carries no `assemblyName`). Rejected with `mode=hotpatch` — a hotpatch "dry run" would still apply live method replacements. | + +**Returns:** `RunScriptResponse` — `{ result, diagnostics, compileMs, executeMs, assemblyName }` on top +of the standard envelope. The result carries no echo of the source (path + diagnostics only). Compile +errors return full Roslyn diagnostics (with line/column) and execute nothing; runtime exceptions +surface as structured errors with `file:line` mapped to the source file. +**Notes:** `MainThreadRequired = true`. Editor command. + +- Executing runs always compile **unoptimized (Debug codegen)** so the emitted symbols keep full + sequence points for `file:line` mapping — expect the generated code to run somewhat slower than + regular project assemblies. +- **Async entry points** (`async Task` / `Task`) are awaited to completion; `Task.Result` + becomes the command result and exceptions in the async work surface as runtime errors. The await + is **asynchronous** — the Editor main thread keeps pumping, so awaits that resume on Unity's + main-thread context (`Task.Yield()`, `Task.Delay()`, Awaitable, …) work naturally; no + `ConfigureAwait(false)` contortions are required. The wait is bounded by what remains of + `timeout_ms`; on expiry the command returns a `Timeout` error and the task keeps running + detached (its effects may still land), like an abandoned `eval`. +- **hotpatch specifics:** `entry`, `args` and `dry_run` are rejected (Bad Request); `references` and + `defines` are not applied. Path resolution follows `reload_file`, which probes under `Assets/` + for bare filenames (unlike ephemeral's project-root resolution). Timing: `executeMs` carries the + whole reload duration (compile + apply, not split by `reload_file`); `compileMs` is `0`. Advisory + reload diagnostics are surfaced as severity-`warning` entries on success. +- Under Unity's Mono runtime the in-memory assembly emitted by an executing `ephemeral` run is + **not** collectible/unloadable, so each run retains one small assembly (the same behavior as + `eval`); prefer a single builder entry over many tiny runs. `dry_run` loads nothing. + +#### The builder pattern (bulk construction) + +For bulk construction — creating many objects, wiring private fields, generating content — put the +logic in a **versioned project script** and invoke it with `run_script`. Write the file with +`write_text_file` (ideally under a non-`Assets/` folder such as `AgentScripts/` so the write triggers +no asset import), then call `run_script --file AgentScripts/Build.cs --entry Build.All`. Iterating the +script and re-running it costs an in-memory compile (< ~2s), **not** a 15–20s domain reload. + +The anti-patterns this replaces: carrying construction code as escaped C# strings through `eval` +(verbose, unreviewable, shell-escaping hazards), and editing a builder under `Assets/` in a loop +(each edit pays a full domain reload). Hold the line: code goes in files on disk via `run_script`; +`eval` stays for genuinely ad-hoc one-liners. + +See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md). diff --git a/AIClient/Packages/com.unity.pipeline/Documentation~/commands/wait.md b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/wait.md new file mode 100644 index 0000000..2586727 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Documentation~/commands/wait.md @@ -0,0 +1,169 @@ +# Wait commands + +Server-side condition waiting (AUTHAPI-25). `wait_for` waits until a runtime/editor member condition holds — evaluated on the Editor's per-frame loop — and can act in the **same frame** the condition first becomes true (e.g. screenshot the moment a match-end screen appears). It replaces the dominant agent anti-pattern of client-side polling loops: read a value via `eval`, sleep in the client, repeat. That loop is token-expensive and slow, and its client round-trips can miss short-lived states entirely (a 2-second screen is easy to miss at ~1–2 s per poll). A server-side condition is a cheap per-frame delegate that can act atomically the frame it fires. + +## Sync vs async: pick the right mode first + +`/api/exec` executes **one command at a time** — a synchronous `wait_for` holds that queue for its entire duration. The Editor itself never freezes (each poll is marshaled onto the main thread between sleeps), but **every other command queues behind the wait until it resolves**. That includes any command whose effect your condition is waiting for: if the condition needs a mutation you haven't issued yet, the mutation can never run, and the wait self-deadlocks until its timeout. + +Use a **synchronous** wait only when BOTH hold: + +- the wait is short — comfortably under your client's HTTP timeout (typically **< 30 s**), and +- the condition does **not** depend on any command you still need to issue (it will be satisfied by something already in motion: play-mode gameplay, a running bake, a timer, ...). + +For **everything else**, pass `async=true`: you get a `waitId` back immediately, other commands keep executing, and you poll `wait_status` (and cancel with `wait_cancel`). This is the default choice for long waits and for any "issue command, then wait for its effect" flow. + +A synchronous wait submitted as a detached job (`POST /api/exec` with `"job": true`) remains cancelable: `POST /api/job/cancel` interrupts the sleep loop and resolves the wait as `canceled`. + +> Member resolution, coercion, and the read-only security policy are intended to be shared with the invoke/query surface (AUTHAPI-16). Until that shared resolver lands, `wait_for` ships a self-contained resolver with the same rules that the two will converge on. Type and member-chain resolution is cached per wait — only the live target instance (an `ObjectRef` target or a `findType` instance) is re-resolved each poll. + +### `wait_for` +Wait until a member condition holds, then optionally act in the same frame. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `condition` | yes | `–` | The condition object (see below). | +| `timeout_s` | no | `30` | Maximum seconds to wait (clamped to 0–600; NaN/Infinity are rejected). | +| `poll_interval_ms` | no | `100` | How often to re-check (clamped to 16–5000 ms; NaN/Infinity are rejected). The sleep never exceeds the remaining budget, so a large interval cannot stretch a short timeout. | +| `on_met` | no | `–` | Follow-up run in the same frame the condition first holds: `{ capture: { view, source, save_path, width, height, include_image }, pause }`. `capture.source` (game view only): `camera` (default) renders a camera and **misses Screen Space - Overlay UI**; `screen` captures the composited game view including overlay canvases (HUDs), Play Mode only. | +| `return_history` | no | `false` | Include the observed `{ value, elapsedMs }` samples. A ring buffer keeps the **last 200** samples, so the tail near the transition is retained (the interesting part), not the first 200 identical observations. | +| `tolerate_missing` | no | `false` | Treat resolution failures (type/member/instance not found) as condition-not-met and retry until timeout, instead of failing fast. Enables "wait until X exists" — e.g. waiting for a spawned object via `findType`. On timeout the last resolution error is included. | +| `async` | no | `false` | Return a `waitId` immediately and evaluate in the background; poll `wait_status`, cancel with `wait_cancel`. **Use for long waits and whenever the condition depends on a command you still need to issue.** | + +**The `condition` object** + +| Field | Required | Description | +|-------|----------|-------------| +| `member` | yes | Dotted member path. With no `target`/`findType` it is a fully-qualified **static** path (e.g. `UnityEditor.EditorApplication.isPlaying`); with `target`/`findType` it walks **instance** members (e.g. `State`, `Health.CurrentHealth`). Read-only fields/properties only — write-only members and methods are rejected. | +| `target` | no | Object handle (`instanceId` / `hierarchyPath` / `guid` / `path` / `globalId`) to read instance members from. Re-resolved every poll, so the referenced object may appear mid-wait (combine with `tolerate_missing`). | +| `findType` | no | Fully-qualified `UnityEngine.Object` type name; the member walks from a **live** instance. Persistent objects (prefab/asset files on disk) and hidden editor internals (`hideFlags != None`) are excluded, so the wait never silently binds to a prefab asset instead of the scene instance. Scene instances are preferred; if several candidates remain, the lowest instance id is chosen deterministically and a `note` on the result reports the ambiguity — pass `target` to select one explicitly. | +| `op` | no | `equals` (default) \| `notEquals` \| `greaterThan` \| `lessThan` \| `contains` (strings) \| `changed` (met on the first change from the initially observed value; needs no `value`). | +| `value` | conditional | Comparison operand, coerced to the member's type (primitive, enum name, or string). Required for every op except `changed`. When either side is a `float`, `equals`/`notEquals` compare at **float precision** (widening a float to double manufactures noise digits — `0.9f` would otherwise never equal `0.9`). | + +**`op: changed` is for value-like members** — primitives, enums, and strings. It compares the member's current value against the first observed value, so content mutations *inside* a reference-typed member (a list gaining an element, a field on a referenced object changing) are **not** detected: the reference itself must change. Likewise, `value`/`initialValue`/`history` snapshots of mutable reference types reflect the object's state at serialization time, not at observation time. + +**Returns:** `WaitResult` + +``` +{ + "state": "met", // pending | met | timedOut | interrupted | canceled | failed | not_found + "met": true, + "timedOut": false, + "member": "MatchManager.Instance.State", + "op": "equals", + "value": "Ended", // most recently observed value + "initialValue": "Playing", // first observed value (baseline for op=changed) + "elapsedMs": 512, // frozen at the terminal transition + "framesObserved": 6, + "note": "…", // present only for non-fatal resolution notes (e.g. ambiguous findType) + "capture": { "savedPath": "Screenshots/victory.png" }, // present only with on_met.capture + "waitId": "…" // present only for async submissions / status snapshots +} +``` + +- A **timeout** returns `met:false, timedOut:true` with the last observed `value` — distinct from a resolution/evaluation error, which returns `state:"failed"` with an `error` message (unless `tolerate_missing` turns resolution errors into retries; the wait then times out with the last resolution error attached). +- If the main thread stalls past the per-poll marshal budget (~60 s: a huge import, a modal bake), the poll is counted as **missed** and the wait keeps going until its own budget expires — a stall does not turn the wait into a generic error. +- The sync result is well under 2 KB without `history`. + +### `wait_status` +Get the status/result of an async wait (`wait_for` with `async=true`). + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `wait_id` | yes | `–` | The id returned by `wait_for` when `async=true`. | + +**Returns:** `WaitResult` (`state:"not_found"` if the id is unknown — async waits do not survive a domain reload; completed waits are retained up to a bounded count and pruned oldest-first the next time a `wait_for` is submitted, so a session that never submits another wait keeps its last results queryable). + +### `wait_cancel` +Cancel an async wait. + +| Parameter | Required | Default | Description | +|-----------|----------|---------|-------------| +| `wait_id` | yes | `–` | The id to cancel. | + +**Returns:** `WaitResult`. If the wait was still active, it resolves to `state:"canceled"`. If it had already reached a terminal state (`met`/`timedOut`/`failed`/`interrupted`) before the cancel request arrived, that actual state is returned unchanged — the cancel had no effect, and reporting a fake `canceled` here would misreport whether an `on_met` follow-up (capture/pause) actually ran. + +## Migration: replace a client polling loop with one call + +Before — an agent screenshots a match-end screen by polling with `eval` (dozens of round-trips, and the 2-second screen is easy to miss): + +``` +# ~60 client round-trips, each ~1–2s: +loop: + state = eval "MatchManager.Instance.State" # read + if state == "Ended": break + sleep 1 # client-side sleep +capture_game_view --source screen --save_path Screenshots/victory.png +``` + +After — one **async** wait that captures atomically in the frame the condition first holds, while other commands stay available (the match may take minutes, and you may still need to issue commands that drive it): + +``` +# 1. Arm the wait; returns { waitId } immediately: +wait_for --condition '{"member":"MatchManager.Instance.State","op":"equals","value":"Ended"}' \ + --timeout_s 300 \ + --on_met '{"capture":{"view":"game","source":"screen","save_path":"Screenshots/victory.png"}}' \ + --async true + +# 2. Keep working: start the match, drive gameplay, run other commands... + +# 3. Collect the result (poll until state != "pending"): +wait_status --wait_id +``` + +Only use the synchronous form when the wait is short and self-contained — e.g. play mode is already running and the state flips within a few seconds: + +``` +wait_for --condition '{"member":"MatchManager.Instance.State","op":"equals","value":"Ended"}' --timeout_s 10 +``` + +## Waiting for something to exist (spawn waits) + +By default the first failed resolution fails the wait (`state:"failed"`) — that catches typos fast. To wait for an object or member that does not exist *yet*, pass `tolerate_missing:true`: + +``` +wait_for --condition '{"findType":"MyGame.BossController","member":"IsActivated","op":"equals","value":true}' \ + --tolerate_missing true --timeout_s 120 --async true +``` + +Resolution failures are then treated as condition-not-met and retried every poll until the object appears (or the wait times out, with the last resolution error attached). + +## Interruption and lifecycle + +- Concurrent waits are capped (8); a further submission is rejected with a structured error telling you to `wait_cancel` one or let one finish. +- A **domain reload** (`beforeAssemblyReload`) or **exiting play mode** resolves every active wait to `state:"interrupted"` rather than hanging or leaking. **Entering play mode does not interrupt**: with domain reload disabled ("Enter Play Mode Options"), a wait armed in edit mode survives into play mode — the natural way to arm a capture before pressing play. (With domain reload enabled, the reload interrupts it anyway.) +- `on_met.pause` pauses play mode on the frame the condition holds (no-op outside play mode). +- If the server is stopping while a synchronous wait is pending, the wait resolves as `interrupted` ("server stopping") instead of evaluating against a shutting-down editor. + +## Result contract details + +- `error` is set only when the wait itself ends abnormally (`failed`, `interrupted`, `canceled`, + or the surfaced last resolution error on a tolerated timeout). A failed `on_met` follow-up + (capture/pause) is reported separately as **`onMetError`** while `state` stays `met` — the + condition did hold; check `onMetError` before trusting `capture`. +- `condition.target` and `condition.findType` are **mutually exclusive** (rejected up front). +- Member paths resolve **public** readable fields/properties only. +- A **destroyed** Unity object mid-path fails structurally; as the **leaf** value it is observed + as `null` (Unity's own `==` semantics), so "wait until destroyed" is + `{ "op": "equals", "value": null }` — the `value` key must be present and explicitly `null`; + omitting it is rejected for every op except `changed`. +- `tolerate_missing` retries the evaluator's STRUCTURED failures: resolution failures + (type/member/instance not found, unless permanently malformed) and evaluation errors + ("cannot compare yet" — e.g. an ordering op while the member is still null); the last error is + surfaced if the wait times out. A member getter that THROWS fails the wait immediately, + tolerated or not. +- A bare type name matching several loaded types binds deterministically (lowest full name) and + surfaces a `note` — use the fully-qualified name to disambiguate. + +## Interaction with `batch` + +`wait_for` is rejected inside a `batch` (`not_batchable`): the batch holds the main thread for its +whole turn, so the editor state a condition watches cannot change while the wait polls — it would +just burn its timeout. Run an async `wait_for` before or after the batch and poll `wait_status` +(both `wait_status` and `wait_cancel` are quick reads and stay batchable). + +## Interaction with the startup settle gate + +`wait_for` is a background command (`MainThreadRequired=false`), so it is **exempt from the settling busy-gate** (AUTHAPI-35): it is accepted even while the Editor is still importing/compiling after a cold start. A wait polling during that window observes a half-ready editor — types may not be loaded and objects may not exist yet. Combine with `tolerate_missing:true` for a deliberate wait-until-ready pattern, or gate on `/api/status` reporting `ready` first if you want fully settled reads. + +See [Creating commands](../creating-commands.md) and [Connectivity](../connectivity.md). diff --git a/AIClient/Packages/com.unity.pipeline/Documentation~/connectivity.md b/AIClient/Packages/com.unity.pipeline/Documentation~/connectivity.md new file mode 100644 index 0000000..55caf12 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Documentation~/connectivity.md @@ -0,0 +1,541 @@ +# Connectivity + +How a client reaches a running Unity instance: the loopback-only HTTP servers, their port ranges, the port descriptor file used for discovery, and the bearer-token authentication every request must carry. + +The rest of this page covers the implementation. If you just want to connect, start with the two sections below. + +## Connecting to a running Editor + +Connections go through the `unity` CLI. Run `unity command` with no command name to connect to a Unity instance and list its available commands: + +```bash +# Auto-discover a Unity instance from the current directory +unity command + +# Connect to a specific project +unity command --project-path /path/to/your/unity/project +``` + +Once connected, run any command by name, e.g. `unity command editor_status`. + +## Connecting to a running Player (game) + +To target a running development Player instead of the Editor, use `--runtime` (by process name) or `--runtime-path` (by the location of the runtime port file). These options go **after** `command` and **before** the command name: + +```bash +# By Player process/executable name +unity command --runtime MyGame.exe runtime_status + +# By the folder/bundle where the runtime port file lives +unity command --runtime-path "C:\Builds\MyGame" runtime_status # Windows: next to the .exe +unity command --runtime-path "/Users/me/Builds/MyGame.app" runtime_status # macOS: the .app bundle +``` + +> The Runtime server only runs in a **development Player build** with the runtime manager enabled — see [Runtime connection & setup](runtime-setup.md). + +## Finding the port in the Unity logs + +The [port descriptor file](#port-descriptor-file) is the primary discovery channel, but the server also reports itself to the Unity log when it starts and stops — useful when you can't read the descriptor file directly. Look for `Pipeline`-prefixed lines. + +- **Runtime (Player)** — logs its port **and** the descriptor file location on start, and a line on stop: + + ``` + Pipeline: Runtime server started successfully on port 7901 + Pipeline: Runtime descriptor written to /path/to/MyGame/.unity-pipeline-runtime-port + Pipeline: Runtime server stopped + ``` + +- **Editor** — logs its port when the server is (re)started from the **Pipeline ▸ Start Server** menu or re-opened by its watchdog (`Pipeline Server started on port 7801`). Its descriptor always lives at the fixed `Library/Pipeline/.unity-pipeline-port` path. + +### Where the logs live + +**Editor log** (`Editor.log`): + +| OS | Path | +|----|------| +| Windows | `C:\Users\\AppData\Local\Unity\Editor\Editor.log` | +| macOS | `~/Library/Logs/Unity/Editor.log` | + +**Player log** (`Player.log`): + +| OS | Path | +|----|------| +| Windows | `C:\Users\\AppData\LocalLow\\\Player.log` | +| macOS | `~/Library/Logs///Player.log` | + +(`` and `` are the project's **Company Name** and **Product Name** from Player Settings.) + +## Loopback-only binding + +Both the Editor and Runtime servers bind to the **IPv4 loopback** (`127.0.0.1`) — plus the `localhost` hostname for compatibility: + +```csharp +if (Socket.OSSupportsIPv4) + m_HttpListener.Prefixes.Add($"http://127.0.0.1:{m_Port}/"); +m_HttpListener.Prefixes.Add($"http://localhost:{m_Port}/"); +``` + +The server is never exposed on a routable interface — it is reachable only from the same machine. + +Clients should connect to **`127.0.0.1`** explicitly rather than `localhost`. Unity's Mono `HttpListener` only reliably serves the IPv4 loopback: a request arriving over the IPv6 loopback (`::1`) is answered with `400` because Mono mis-parses the bracketed `[::1]` host. Since `localhost` resolves to `::1` or `127.0.0.1` non-deterministically (notably on Windows with Node's default DNS order), dialing `localhost` caused intermittent connection failures — dialing `127.0.0.1` avoids the IPv6 path entirely. + +In addition, the server refuses any request that carries an `Origin` header (legitimate CLI/CI clients never send one), which blocks a browser page from reaching the local server and short-circuits CORS preflights. The Editor server can opt into the single exception: enabling **Allow Browser Clients** in the pipeline settings asset (`Window/Pipeline/Settings...`, applies on next start) admits `Origin: null`, the opaque origin a sandboxed browser frame reports, and answers that client's CORS preflight. An ordinary page sends its real origin and is still refused, and a sandboxed one still needs the bearer token. + +## Port ranges + +Each server type picks the first free port in its range (or you can pin one explicitly): + +| Server | Production range | Test range | +|--------|------------------|------------| +| **Editor** | `7800`–`7849` | `7850`–`7899` | +| **Runtime** (Player) | `7900`–`7949` | `7950`–`7999` | + +If no port in the range is free, startup throws (`No available ports in range …`). + +## Port Descriptor File + +When a server starts, it writes a small JSON **instance descriptor** so clients can discover it. This is the only discovery channel — there is no broadcast or registry. + +| Server | Descriptor path | +|--------|-----------------| +| **Editor** | `/Library/Pipeline/.unity-pipeline-port` | +| **Runtime** | `/.unity-pipeline-runtime-port` | + +The Editor descriptor lives under the git-ignored `Library/` folder. The file is created with permissions restricted to the current user (it carries the auth token). The server rewrites it on every heartbeat to refresh `lastHeartbeat`, and deletes it on shutdown. + +The Runtime descriptor is written next to the Player, at `{Application.dataPath}/..`: + +- **Windows / Linux** — beside the executable, e.g. `C:\Builds\MyGame\.unity-pipeline-runtime-port`. +- **macOS** — `Application.dataPath` is `.app/Contents`, so the descriptor lands at the **`.app` bundle root**: `MyGame.app/.unity-pipeline-runtime-port`. (The file is inside the `.app` bundle.) This is why `unity command --runtime-path` takes the `.app` bundle path on macOS — see [Runtime connection & setup](runtime-setup.md). +- **Android** — `Application.dataPath` points inside the read-only APK install directory, so the descriptor is written to `Application.persistentDataPath` instead: `/.unity-pipeline-runtime-port`. + +> Test servers do **not** write a descriptor (they override `WritesDescriptor => false`) — the test already knows its port, so it never clobbers the live server's file. See [Tests architecture](testing.md). + +### Editor descriptor fields + +```json +{ + "pid": 12345, + "port": 7800, + "projectPath": "/path/to/Project", + "projectName": "Project", + "unityVersion": "6000.x.y", + "mode": "editor", + "startedAt": "2026-06-25T10:00:00Z", + "lastHeartbeat": "2026-06-25T10:05:00Z", + "evalToken": "", + "capabilities": ["exec.argv", "exec.commandLine"], + "info": "This editor has not been opened in automated mode and therefore could get stuck on modal dialogs. Human intervention may be required." +} +``` + +| Field | Meaning | +|-------|---------| +| `pid` | Process id of the Unity Editor. | +| `port` | Port the server is listening on. | +| `projectPath` | Absolute path to the Unity project. | +| `projectName` | Project folder name. | +| `unityVersion` | Editor version string. | +| `mode` | `"editor"` or `"batchmode"`. | +| `startedAt` | When the instance started (UTC). | +| `lastHeartbeat` | Last heartbeat (UTC), refreshed on status calls. | +| `evalToken` | Bearer token for authenticating requests. | +| `capabilities` | Optional wire features this server understands (see [Capability negotiation](#capability-negotiation)). **An absent key means the server predates the field** — treat it as supporting none of them. | +| `info` | Corrective guidance for the client, omitted when there is nothing to say. Currently only set when the Editor is interactive and wasn't launched with `-automated`: a blocking modal dialog can stall the Editor's main-thread update loop (and therefore all pipeline command processing) until a human dismisses it. Read this before issuing commands — it's the one field every client sees, since reading the descriptor is a mandatory first step just to connect. | + +### Runtime descriptor fields + +The runtime descriptor shares `pid`, `port`, `unityVersion`, `startedAt`, `lastHeartbeat`, and `evalToken`, and adds: + +| Field | Meaning | +|-------|---------| +| `platform` | Unity runtime platform (e.g. `WindowsPlayer`). | +| `buildGuid` | Unique build identifier (`Application.buildGUID`). | +| `workingDirectory` | Directory the Player is running from. | + +The runtime descriptor also carries `capabilities`, with the same meaning and the same absent-key rule. + +(The runtime descriptor carries `platform`/`buildGuid`/`workingDirectory` in place of the editor's `projectPath`/`projectName`/`mode`.) + +## Authentication + +Every request must authenticate with a bearer token: + +``` +Authorization: Bearer +``` + +- The server **generates the token at startup** (`SecurityTokenManager.GetOrCreateToken()` — 256 bits of CSPRNG output, base64-encoded). In the Editor the token is persisted in `SessionState`, so it **survives domain reloads** within an editor session (recompiles, entering play mode) — long-lived clients (MCP sessions, IDE integrations) keep working instead of getting `401` after every reload. It is regenerated only when the Editor **restarts**, or on an explicit rotation (`SecurityTokenManager.ClearCache()` / `RotateToken()`). Player builds use a per-process token. +- The token is published in the descriptor's `evalToken` field. The descriptor is **re-advertised with the live token on every heartbeat**, so the port file never advertises a token the server would reject (e.g. after a reload or rotation). +- The server validates the bearer token on **every** request (before routing) using a constant-time comparison. A missing or wrong token returns `401 Unauthorized`. + +## Discovering and calling an instance + +A client connects by: + +1. Reading the descriptor file (editor: `Library/Pipeline/.unity-pipeline-port`). +2. Taking the `port` and `evalToken` from it. +3. Sending requests to `http://127.0.0.1:/...` with `Authorization: Bearer `. + +Endpoints exposed by the server include `/api/status`, `/api/editor_status`, `/api/dialog`, `/api/commands` (lists available commands), `/api/exec` (POST — runs a command), `/api/test-status`, and `/api/progress`. + +### Command progress (`GET /api/progress`) + +While a command is executing over `/api/exec`, clients can poll `GET /api/progress` for the +task's live progress — the `unity` CLI uses this to render terminal progress bars, mirroring +`EditorUtility.DisplayProgressBar`. The endpoint is served off the Editor main thread, so it +answers even while a long synchronous command has the Editor blocked. Response +(`pct` is 0–1; all `progress` fields optional; `progress` is omitted when nothing is reported): + +```json +{ + "active": true, + "progress": { + "title": "Generating World", + "info": "Processing 42/100", + "current": 42, + "total": 100, + "pct": 0.42 + } +} +``` + +Progress sources, in order of precedence: + +1. `CliProgress.Report(title, info, current, total, progress)` — explicit reporting from + command code; thread-safe and works from a blocked main thread. +2. Running `UnityEditor.Progress` items, mirrored automatically. + +### Detached jobs (`/api/exec` with `"job": true`, `/api/job`, `/api/job/cancel`) + +A long command can outlive the client's HTTP timeout. Submitting it as a **detached job** +returns a job id immediately; the command runs in the background (still one at a time, in +arrival order) and the client polls for the result — reattaching at any point: + +1. `POST /api/exec` with body `{"command": "…", "parameters": {…}, "job": true}` → the + standard exec envelope, with the job handle as its `result`: + `{"success": true, "result": {"jobId": "…", "state": "queued"}}` (lean by default — + add `"verbose": true` to get the `command`/`executedAt` metadata back, see AUTHAPI-21). +2. `GET /api/job?id=` → `{"jobId", "command", "state": + "queued|running|completed|failed|canceled", "progress": {…}, "result", "error", …}`. + `progress` mirrors `/api/progress` while the job runs; `result` is retained after + completion (last 100 terminal jobs, 1 hour) so it can be fetched repeatedly. +3. `POST /api/job/cancel` with body `{"id": ""}` — a queued job is canceled before it + starts; a running job gets a cooperative cancellation flag that command or `eval` code can + observe via `Unity.Pipeline.PipelineCancellation.ThrowIfCancellationRequested()` (arbitrary + synchronous code cannot be aborted from outside). + +At most 100 jobs may be queued or running at once (jobs execute strictly serially, so a deeper +backlog is pure queued work with no benefit) — submitting one beyond that returns `429`. + +Jobs live in Editor memory: they do not survive domain reloads (script recompilation). + +Editor code that already calls `EditorUtility.DisplayProgressBar` can switch to the drop-in +`CliEditorProgress.DisplayProgressBar` / `ClearProgressBar` wrappers to keep the Editor dialog +and gain CLI visibility. See [Creating commands](creating-commands.md). + +### Readiness and the settle window + +On a **cold project import** the editor server comes up (and its descriptor is written) while the Editor is still importing assets and compiling scripts, so the Editor is not yet able to service commands. Until the Editor is first seen idle after server start: + +- `/api/status` reports `"status": "settling"` instead of `"ready"`. Wait for `ready` before issuing commands. +- `/api/exec` rejects **main-thread** commands with **HTTP 503** and a structured, retryable envelope — distinguishable from a genuine command failure. The gate applies before execution *and* before a detached job (`"job": true`) is created, so a job can't run into the half-ready Editor in the background either. The busy reply is a standard exec envelope and follows the request's reply-shape flags: lean (the default, shown here) drops the envelope metadata; `"verbose": true` restores the `command` echo and `executedAt`: + + ```json + { + "success": false, + "error": "Server Busy", + "errorDetails": "The Editor is still settling after startup (importing assets / compiling scripts), so main-thread commands are not serviceable yet. Retry shortly, or poll /api/status until it reports 'ready'.", + "status": "busy", + "busyReason": "settling", + "retryable": true + } + ``` + + `busyReason` is the specific cause, matching `/api/status`'s own `status` values for the same conditions (`"settling"`, `"blocked_by_dialog"`) — branch on it directly rather than inferring the cause from whether `dialogs` happens to be populated. + +- Background commands (`recompile_status`, `package_status`, `console`, ...) and `editor_status` stay servable throughout, so progress remains observable. + +The settle gate is one-way and scoped to the **editor session**: once the Editor has been idle once after startup, the server reports `ready` and the gate never arms again for that session — including for server instances recreated by domain reloads and for servers started while a mid-session compile/import happens to be in flight. Warm starts settle immediately; only the cold-import window gates. + +### Modal dialogs and the dialog-busy gate + +A native modal dialog (e.g. "Save changes before quitting?") or an `EditorWindow` modal blocks the Editor's main thread inside a nested OS message loop, so no main-thread command can run until it's dismissed. The server mirrors these dialogs from `UnityEditor.EditorDialogEvents`: + +- `GET /api/dialog` reports the currently open dialog(s): `{"active": bool, "dialogs": [...]}`, each entry shaped `{id, source, title, message, level, buttons, openedAt, dismissedAt}`. +- `/api/status` reports `"status": "blocked_by_dialog"` (instead of `"ready"`) with a `"dialog"` key carrying that same shape for the first open dialog — so the cheapest, most commonly polled probe doesn't claim readiness while every main-thread command is actually gated. +- `/api/exec` rejects any **main-thread** command with **HTTP 503**, the same busy envelope shape as the settle gate's but with `"busyReason": "blocked_by_dialog"` and a `"dialogs"` array attached. + + **Exception: `editor_status`.** Unlike every other main-thread command, `editor_status` still returns a normal **200** while a dialog is open, served from a snapshot taken the instant before the dialog blocked the thread — nothing it reports (compiling, domain reload, play mode) can change while the thread that would update it is stuck. The response carries `"status": "blocked_by_dialog"` and the same `"dialog"` payload as `/api/status`, so a caller can still tell it apart from a genuinely idle Editor. + +- A successful `/api/exec` response may carry `"dialogsDuringExecution"`: dialog(s) that opened and/or closed while the command was actually *executing* (not while it sat queued behind another command), so a caller learns about them without polling `/api/dialog` concurrently. + +Coverage is mechanism-based: native message boxes and `EditorWindow` modals are covered; OS file/folder pickers and other dialog mechanisms are not — a caller still needs a fallback signal (e.g. a command timeout) for uncovered cases. + +`/api/commands` accepts optional query parameters for discovery: + +- `detail` — `full` (the **default**) returns the complete command metadata including `parameters` and the generated `schema`; `compact` returns a lightweight index per command (`name`, `description`, `tags`, `package`). The recommended discovery flow is to browse the compact index first, then request full detail only for the few commands you intend to invoke. +- `query` — case-insensitive substring match on a command's name, description, or any tag. +- `tag` — scope results to a tag subtree via segment-aware prefix match (`tag=assets` matches `assets` and `assets/import`, not `assetsx`). +- `group_by` — `flat` (the default) returns a `commands` array; `package` or `tag` return a `groups` array instead (`tag` is a nested tree mirroring the tag/subtag hierarchy; untagged commands land in a node with an empty tag). +- `sort` — `name` (the default) or `package` (originating package, with name as tiebreak). +- `order` — `asc` (the default) or `desc`. Applies to the chosen `sort`; sorting happens on the flat list before pagination and grouping. +- `offset` / `limit` — paginate the filtered, sorted list. Both apply to the flat list *before* grouping, so pages stay deterministic. `offset` skips that many matches (default `0`); `limit` caps how many are returned (default: no cap). A client has seen everything once `offset + count` reaches `total`. + +Filters combine with AND; a filter that matches nothing returns an empty result, not an error. An invalid `detail`, `group_by`, `sort`, `order`, `offset`, or `limit` value is rejected with `400` naming the accepted values. + +### `/api/commands` response shape + +Every response carries the pagination counters plus a `server` block. The command payload is either a flat `commands` array or — under `group_by` — a `groups` array in its place: + +| Field | Meaning | +|---|---| +| `commands` | The page of commands. Present only when `group_by=flat` (the default). | +| `groups` | Present *instead of* `commands` when `group_by=package` or `group_by=tag`. | +| `count` | How many commands this page actually returned. | +| `total` | How many commands matched the filters, **before** `offset`/`limit` were applied. | +| `offset` | Echo of the requested `offset` (`0` when not supplied). | +| `limit` | Echo of the requested `limit` (`null` when not supplied — no cap). | +| `server` | The responding server's `version`, `port`, and `startTime`. | + +`GET /api/commands?detail=compact&tag=baking/lighting&limit=2` — `count` is the 2 returned here, while `total` is all 6 commands under `baking/lighting`, so the next page is `offset=2`: + +```json +{ + "commands": [ + { + "name": "bake_lighting", + "description": "Trigger an async lightmap bake of the open scene(s) via Lightmapping.BakeAsync(). Returns immediately; poll lighting_bake_status until completed.", + "tags": ["baking/lighting"], + "package": "Unity.Pipeline.Editor" + }, + { + "name": "cancel_lighting_bake", + "description": "Cancel an in-progress lighting bake (Lightmapping.Cancel()).", + "tags": ["baking/lighting"], + "package": "Unity.Pipeline.Editor" + } + ], + "count": 2, + "total": 6, + "offset": 0, + "limit": 2, + "server": { + "version": "0.0.1", + "port": 54321, + "startTime": "2026-07-29T09:14:22.113Z" + } +} +``` + +Under `group_by=tag` the same envelope carries a nested `groups` tree instead. Two things to note. A node's `commands` holds only the commands tagged *exactly* at that node — so `baking`, whose commands all live in subtags, reports an empty array — while its `count` covers the node's whole **subtree**. And because pagination happens before grouping, group counts describe the returned page rather than every match: `GET /api/commands?detail=compact&tag=baking&group_by=tag&limit=2` groups only the 2 commands on this page, while `total` still reports all 17 matches under `baking`: + +```json +{ + "groups": [ + { + "tag": "baking", + "count": 2, + "commands": [], + "children": [ + { + "tag": "baking/lighting", + "count": 1, + "commands": [ + { + "name": "bake_lighting", + "description": "Trigger an async lightmap bake of the open scene(s) via Lightmapping.BakeAsync(). Returns immediately; poll lighting_bake_status until completed.", + "tags": ["baking/lighting"], + "package": "Unity.Pipeline.Editor" + } + ], + "children": [] + }, + { + "tag": "baking/navmesh", + "count": 1, + "commands": [ + { + "name": "bake_navmesh", + "description": "Trigger an async legacy NavMesh bake of the open scene(s) via UnityEditor.AI.NavMeshBuilder. Returns immediately; poll navmesh_bake_status until completed.", + "tags": ["baking/navmesh"], + "package": "Unity.Pipeline.Editor" + } + ], + "children": [] + } + ] + } + ], + "count": 2, + "total": 17, + "offset": 0, + "limit": 2, + "server": { + "version": "0.0.1", + "port": 54321, + "startTime": "2026-07-29T09:14:22.113Z" + } +} +``` + +`group_by=package` uses the same envelope with flatter nodes — `{ "package": "Unity.Pipeline.Editor", "count": 2, "commands": [ ... ] }`, with no `children`. + +## Executing a command (`POST /api/exec`) + +A request carries the command in **exactly one** of three forms: + +```jsonc +{"command": "reload_file", "parameters": {"path": "Assets/A.cs"}} // structured +{"commandLine": "reload_file Assets/A.cs"} // server tokenizes, then binds +{"argv": ["eval", "return 2+2;"]} // server binds directly +``` + +For the two raw forms the **first token is the command name**, and the server binds the rest +against the command's declared parameters. This is what lets a client execute a command in a +single request without knowing its schema — the structured form needs `GET /api/commands` first, +the raw forms need nothing. + +**Prefer `argv` whenever you already have split tokens.** On POSIX a CLI never holds the original +command *string* — the shell already split and unquoted argv — so re-quoting those tokens for the +server to re-split is a lossy round-trip across two independently-versioned quoting dialects. Use +`commandLine` only when you genuinely hold raw text (a chat message, an MCP argument, a pasted +line). + +Supplying more than one form is an error, and so is sending `parameters` alongside `commandLine` +or `argv`. The latter is **rejected rather than ignored**: silently dropping a payload makes "you +sent it and we discarded it" indistinguishable from "you never sent it". + +`argv` and `commandLine` are exec-only. `batch` operations keep `command` + `params`. + +### Tokenizer dialect (`commandLine` only) + +This is a **versioned contract**, not an implementation detail. It is the pipeline's own dialect — +identical on every OS, and deliberately *not* the caller's shell — so the same string tokenizes +the same way from cmd.exe, bash, an MCP client, or a chat box. + +| Rule | Example | Tokens | +|---|---|---| +| Whitespace separates tokens; runs collapse | `a b` | `a`, `b` | +| `"…"` groups, `\` escapes the next character | `"a b"`, `"a\"b"` | `a b`, `a"b` | +| `'…'` groups, with **no** escapes at all | `'a\b'` | `a\b` | +| `\` escapes outside quotes | `a\ b` | `a b` | +| Adjacent spans concatenate | `a"b c"d` | `ab cd` | +| `""` yields one **empty** token | `--message ""` | `--message`, *(empty)* | +| Unbalanced quote or dangling `\` | `"oops` | **error** | + +There is **no expansion of any kind** — no `$VAR`, globbing, `~`, comments, or operators. `&&`, +`|` and `>` are ordinary characters. + +Two consequences worth stating explicitly: + +- **Single quotes are load-bearing.** They pass double quotes through untouched, which is the only + practical way to send `eval 'obj.name = "x";'` or `batch --operations '[{…}]'`. +- **Windows `CommandLineToArgvW` rules do not apply.** `"a""b"` is `ab` here, not `a"b`. The usual + argument for Windows rules — that `\` is the path separator — does not hold, because every path + this API accepts is a forward-slashed Unity asset path. + +### Argument grammar (both raw forms) + +- `--key value`, `--key=value`, or a bare `--key` (which means `true`, and is an error on a + non-boolean parameter). +- A follower is consumed as the value **unless it starts with `--`**, so `--path -foo` works. +- `--` ends flag parsing; everything after it is a positional value, exempt from the `-foo` and + `key=value` checks. +- Positionals fill **required parameters in declaration order, then optional parameters in + declaration order**. A slot already filled by an explicit flag is skipped, not overwritten. +- Not supported, by design: short flags, `-abc` bundling, `--no-x`, repeated-flag-as-array, + flag-name abbreviation, and `@argfile`. + +> **Declaration order is wire API for raw clients.** Reordering a command's parameters — or +> flipping one between required and optional — silently changes what a positional binds to. Append +> new optional parameters at the end. See [Creating commands](creating-commands.md). + +### Successful replies echo the bound parameters + +```json +{"success": true, "result": "pong", "parameters": {"message": "hi"}} +``` + +`parameters` is present **only** for `argv`/`commandLine` requests, so structured replies are +unchanged. It reports exactly what the binder stored, so a client that no longer binds locally can +still show the user what the server understood. + +### Argument errors + +```json +{ + "success": false, + "error": "Invalid Command Arguments", + "errorCode": "INVALID_COMMAND_ARGS", + "errorDetails": "log_editor has no parameter --mesage. Did you mean --message?", + "argProblems": [{"kind": "unknownName", "name": "mesage", "suggestion": "message"}], + "commandSchema": {"name": "log_editor", "parameters": [{"name": "message", "type": "String", "required": true}]} +} +``` + +**`errorCode` is the discriminator, not the HTTP status.** Every `/api/exec` failure is already +`400`, so status alone cannot separate "your arguments are wrong" from "the command threw". + +| `errorCode` | Meaning | +|---|---| +| `INVALID_COMMAND_ARGS` | The command resolved, but its arguments could not be bound. Nothing executed. | +| *(absent)* | Any other failure — an unknown command, a validation error, or the command itself throwing. | + +A malformed *request shape* — two command forms at once, `parameters` beside `argv`, an empty +`argv`, a `commandLine` that does not tokenize (unbalanced quote, dangling backslash), or a body +using none of the three forms — is a `400` with `error: "Invalid Request"` and **no** `errorCode`, +because no command was ever resolved. Such a reply carries neither `argProblems` nor +`commandSchema`: there is no command to describe. + +`argProblems` is machine-readable and **accumulated**: every defect is reported, not just the +first, so a user fixing a command line sees all of its problems at once. It is deliberately not +pre-rendered English — the `unity` CLI renders *and localizes* these itself. Use `errorDetails` as +the English fallback, and for any `kind` your client does not recognize. + +| `kind` | Meaning | +|---|---| +| `emptyName` | A flag with no name: `--=` or `--=value`. A bare `--` is the end-of-flags separator, never this. | +| `emptyValue` | `--key=` with nothing after it, or a bare `--key` on a non-boolean parameter. | +| `singleDash` | A `-x` token in positional position. | +| `duplicate` | The same `--key` supplied more than once. | +| `unknownName` | No such parameter. Carries `suggestion` when a close match exists. | +| `bareAssignment` | A `key=value` positional whose left side names *the parameter that positional fills* — a misremembered `--key value`. A left side naming some other parameter is a value: `eval "timeout=5;"` binds as `code`. | +| `excessPositional` | More positionals than there are slots left for them. `capacity` is the slots still free after the flags took theirs and `given` is the positionals supplied; `token` is the first one with no slot. | +| `positionalConflict` | A positional whose own slot a flag already filled. Carries `name` (that parameter) and `token`. | +| `typeMismatch` | The declared type cannot accept the token; carries `expectedType`. | + +`commandSchema` is the command's catalog entry, shaped like a `/api/commands` `commands[]` +element (without the generated `schema`). It lets a client print usage without a separate schema +fetch. + +### Capability negotiation + +Servers advertise optional wire features in `capabilities`, both on `GET /api/status` and in the +**port descriptor**: + +```json +"capabilities": ["exec.argv", "exec.commandLine"] +``` + +The descriptor is the carrier that matters: clients already read it locally to obtain `evalToken`, +so negotiation costs **zero extra requests**. + +The rule for clients: + +- Token present → send that form. +- Descriptor present but **no `capabilities` key at all** → the server predates this feature. Do + not send raw forms; tell the user to update the package. +- Never sniff first. An older server receiving `{"argv":[…]}` fails deserialization (its `command` + field is required) and answers `400 {"error":"Invalid JSON"}` — which a client would otherwise + surface as a generic internal failure, making version skew look like a client bug. + +Because the descriptor file is writable by anything running as the user, treat a capability claim +as a hint rather than a guarantee: a `400` carrying `error: "Invalid JSON"` or `"Invalid Request"` +with **no** `errorCode`, in response to a request that used `argv`, means the same thing as an +absent key. Degrade, don't crash. + +## See also + +- [Runtime connection & setup](runtime-setup.md) — enabling the server in a Player build. +- [Creating commands](creating-commands.md) — authoring the commands clients call. diff --git a/AIClient/Packages/com.unity.pipeline/Documentation~/creating-commands.md b/AIClient/Packages/com.unity.pipeline/Documentation~/creating-commands.md new file mode 100644 index 0000000..b91c6ea --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Documentation~/creating-commands.md @@ -0,0 +1,347 @@ +# Creating commands + +A *command* is a `static` method that the Pipeline server can invoke over HTTP. The method's accessibility does not matter — `public`, `internal`, and `private` static methods can all be registered. This page covers the command-authoring API: how to declare a command, describe its parameters, return a result, and have it discovered automatically. + +## The handler + response pattern + +Authoring a command has two halves: + +1. **The handler** — your `static` method, tagged `[CliCommand]`. It does the work and returns a value. +2. **The response** — the server wraps whatever your handler returns in a [`CommandExecutionResponse`](#the-commandexecutionresponse-envelope) and serializes it to JSON for the client. + +You never build the HTTP response yourself. Return a `string`, a number, an anonymous object, a typed model, or `null`; the server takes care of the envelope, timing, and error reporting. + +## Declaring a command + +Tag a `static` method with `[CliCommand]` (the examples below use `public`, but any accessibility works): + +```csharp +[CliCommand("name", "description", MainThreadRequired = true, RuntimeOnly = false)] +public static Handler(...); +``` + +| Argument | Meaning | +|----------|---------| +| `name` | Unique command name used by the client (`unity command `). | +| `description` | Human-readable text shown in help and the `/api/commands` listing. | +| `MainThreadRequired` | Whether the handler must run on Unity's main thread. **Default `true`.** | +| `RuntimeOnly` | Whether the command is hidden from an Editor server's command listing. **Default `false`.** | +| `Tags` | Optional hierarchical tags for grouping/browsing commands. Path-style: a `/` separates tag from subtag (e.g. `"assets"`, `"assets/import"`). **Default: empty.** | + +Every discovered command also carries the **package** it originates from (derived from the declaring assembly, e.g. `Unity.Pipeline.Editor`). Tags and package appear in both the compact and full `/api/commands` listings — `detail=full` (the default) includes the parameters and generated JSON schema, while `detail=compact` returns just the lightweight index (`name`, `description`, `tags`, `package`). Tags also drive the endpoint's `tag` filter and its `group_by=tag` tree (see [Connectivity](connectivity.md)). + +The method **must be `static`**, but its accessibility does not matter: `public`, `internal`, and `private` static methods can all be registered. `CommandRegistry` invokes handlers through reflection, so a `private` handler runs exactly like a `public` one. Only a non-static (instance) method fails to register — `CommandRegistry` skips it and logs a warning. To expose an instance method as a command, register it dynamically instead (see [Registering a command dynamically](#registering-a-command-dynamically)). + +### Tag taxonomy + +Every shipped command carries at least one tag (enforced by `CommandRegistrationTests.CommandRegistry_DiscoverCommands_AllShippedCommandsCarryTags`). Tags are lowercase `/`-separated paths. Pick from the established top-level tags before inventing a new one, and add a subtag when a family is large enough to browse on its own: + +| Top-level tag | Covers | Subtags in use | +|---------------|--------|----------------| +| `animation` | Animation authoring | `animator`, `clip`, `timeline` | +| `assets` | Asset CRUD and search | `import`, `text` | +| `authoring` | Authoring-root configuration | — | +| `batch` | Transactional multi-command execution (`batch`) | — | +| `baking` | Bake pipelines | `lighting`, `navmesh`, `occlusion` | +| `build` | Player builds | `settings`, `targets` | +| `capture` | Screenshots and view/element capture | — | +| `editor` | Editor application control | `playmode` | +| `gameobjects` | Scene GameObject manipulation | `components` | +| `materials` | Materials | `shaders` | +| `navigation` | Selection and search | — | +| `observability` | Logs and diagnostics | `console`, `performance` | +| `packages` | UPM package management | — | +| `prefabs` | Prefab workflows | — | +| `runtime` | Player-only application control | `application`, `input` | +| `scenes` | Scene lifecycle and hierarchy | — | +| `scripts` | C# source workflows | `compile`, `eval`, `codereload` | +| `settings` | Project settings | `audio`, `graphics`, `input`, `physics`, `player`, `quality`, `tags_layers`, `time` | +| `tests` | Test runner | — | +| `ui` | UI element workflows | — | +| `wait` | Server-side condition waiting | — | + +A command may carry multiple tags when it genuinely belongs to two families (e.g. `add_scene_to_build` is tagged `scenes` and `build/settings`). + +### Describing parameters + +Tag each parameter with `[CliArg]`: + +```csharp +[CliArg("name", "description", Required = false, DefaultValue = null)] +``` + +| Property | Meaning | +|----------|---------| +| `name` | Parameter name as it appears in client arguments (`--name value`). | +| `description` | Human-readable description for help text. | +| `Required` | Whether the parameter must be supplied. Defaults to `false` — but if the parameter has no C# default value it is treated as required. | +| `DefaultValue` | Value used when the client omits the parameter (a C# default value takes precedence). | + +`[CliArg]` is optional metadata. A parameter without it still works: its name defaults to the C# parameter name and `Required` defaults to "does this parameter lack a C# default value?". + +#### Declaration order and `Required` are wire API + +Clients may send an unparsed command line (`argv`/`commandLine` on `/api/exec`), and the server +binds positionals into **required parameters in declaration order, then optional parameters in +declaration order**. Three consequences for command authors: + +- **Reordering parameters, or flipping one between required and optional, is a breaking change** + for those clients even though the C# signature still compiles. Append new optional parameters at + the end. +- **Enum parameters are validated by name** (case-insensitively), and an invalid value is rejected + with the legal set echoed back — you get that for free, no attribute needed. A `[Flags]` enum + also takes a comma-separated combination (`--channels Info,Warning`), and a numeric value is + accepted, because validation defers to the same converter the executor uses. +- **Structured (`IStructuredCommandInput` / `JObject`) parameters are reachable from a command + line only as a JSON-valued flag**, e.g. `--payload '{"name":"x"}'`. Single quotes are the + practical form; see the tokenizer dialect in [Connectivity](connectivity.md). + +A token the declared type cannot accept is now a hard `400` on the raw path, rather than the +parameter silently dropping out and the command running with a default. + +## Worked example 1 — returning a string + +A command can return a plain `string`. The server places it in the response `result` field. + +```csharp +using Unity.Pipeline.Commands; +using UnityEditor; +using UnityEngine; + +public static class PlayModeCommands +{ + [CliCommand("editor_play", "Enter Unity Editor play mode")] + public static string EnterPlayMode() + { + if (EditorApplication.isPlaying) + return "Already in play mode"; + + EditorApplication.isPlaying = true; + return "Entered play mode"; + } +} +``` + +Calling `editor_play` yields a `CommandExecutionResponse` whose `result` is `"Entered play mode"`. + +## Worked example 2 — returning a response model + +For richer results, return a model. Extending `CommandExecutionResponse` lets you populate response fields directly; you can also return any plain serializable model (like `AuthoringResult`) and let the server wrap it. + +```csharp +using System; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Models; + +public class WordCountResponse : CommandExecutionResponse +{ + public int WordCount { get; set; } + + public static WordCountResponse Counted(int wordCount) => new WordCountResponse + { + Success = true, + WordCount = wordCount + }; + + public static WordCountResponse Failed(string error) => new WordCountResponse + { + Success = false, + Error = error + }; +} + +public static class TextCommands +{ + [CliCommand("word_count", "Count the words in a string")] + public static WordCountResponse CountWords( + [CliArg("text", "Text to count words in", Required = true)] string text) + { + if (string.IsNullOrWhiteSpace(text)) + return WordCountResponse.Failed("text parameter is required and cannot be empty"); + + return WordCountResponse.Counted(text.Split((char[])null, StringSplitOptions.RemoveEmptyEntries).Length); + } +} +``` + +`WordCountResponse` adds `wordCount` on top of the standard envelope. Another common shape is a domain model such as `AuthoringResult` — the canonical identity (asset path, GUID, instance id, hierarchy path) of an object a command created, returned so the client can reference it in a follow-up call. + +## Structured (multi-field) parameters + +When a command needs a structured argument with several fields, don't spread them across many `[CliArg]` parameters — declare a small DTO that implements `IStructuredCommandInput` and take it as a single parameter. The type is advertised to clients as a nested JSON **object** schema in `GET /api/commands` (instead of collapsing to `string`), and the value is deserialized automatically via Newtonsoft — no extra wiring. + +```csharp +[CliCommand("set_time_settings", "Change Time settings. Requires confirm=true; use dry_run to preview.")] +public static CommandExecutionResponse Set( + [CliArg("settings", "Fields to change; omitted fields are left unchanged.")] TimeSettingsArgs settings = null, + [CliArg("confirm", "Apply the change. Without it the call is refused.")] bool confirm = false, + [CliArg("dry_run", "Preview the change without applying it.")] bool dryRun = false) +{ /* ... */ } + +public class TimeSettingsArgs : IStructuredCommandInput +{ + [CliArg("fixedDeltaTime", "Fixed timestep in seconds (e.g. 0.02).")] + public float? FixedDeltaTime { get; set; } + + [CliArg("timeScale", "Time scale (1 = real-time).")] + public float? TimeScale { get; set; } +} +``` + +`JsonSchemaGenerator` reflects over the type's public, writable fields and properties to emit `{ "type": "object", "properties": { ... } }`, recursing into nested `IStructuredCommandInput` members and arrays/lists of them. Member metadata mirrors command parameters: + +- `[CliArg(name, description, Required = ...)]` controls the property name, description, and whether it appears in the schema's `required` array. +- Without a `[CliArg]`, the member (or its Newtonsoft `[JsonProperty]`) name is used and it is optional. Use nullable types (`float?`) for "omitted = leave unchanged" semantics. +- `[JsonIgnore]` members are omitted from the schema. + +`[CliArg]` is valid on parameters, fields, and properties, so the same attribute annotates DTO members. Most commands that take an `IStructuredCommandInput` are mutations — pair the DTO with `confirm`/`dry_run` and follow the [safety conventions](safety-and-mutations.md) (inline gate + `AuthoringUndoScope`). + +## The `CommandExecutionResponse` envelope + +Whatever your handler returns, the client receives a `CommandExecutionResponse`: + +| Field | Type | Meaning | In lean reply? | +|-------|------|---------|----------------| +| `success` | `bool` | Whether the command ran without throwing. | always | +| `result` | `object` | Your handler's return value (a string, model, anonymous object, or `null`). | always on success, explicitly `null` when null; omitted on failure | +| `error` | `string` | Error summary when `success` is `false`. | when non-null | +| `errorDetails` | `string` | Extra error context. | when non-null | +| `warnings` | `string[]` | Corrective guidance the server wants the caller to see (e.g. an unrecognized option value). | when non-null (omitted when there is nothing to say, in every mode) | +| `command` | `string` | The command name. | verbose only | +| `executedAt` | `DateTime` | When the reply was produced. | verbose only | +| `executionTimeMs` | `long?` | How long the command took. | verbose only | + +The envelope is **lean by default** (AUTHAPI-21): serialized compact (no indentation), with the +envelope's own null keys omitted and the always-on metadata (`command`, `executedAt`, +`executionTimeMs`) dropped. A minimal success is just `{"success":true,"result":...}`. Agents +consume the JSON directly; a client can pretty-print for a human if needed. + +The boundaries of the lean contract, worth knowing: + +- **Only the envelope's nulls are omitted; your `result` payload keeps explicit nulls.** The + envelope's null keys are redundant (`success` already disambiguates: `error` is null on success), + so they are dropped. Inside `result` the opposite holds — a scene object's `AuthoringResult` + still carries `"assetPath": null` — because an absent payload key would be indistinguishable + from a nonexistent or misspelled one. +- **A successful reply always carries `result`, even when its value is null — in every mode.** A + null result on success is the command's actual value (e.g. a `format="value"` read of an + unassigned object-reference field), never a droppable envelope null. Only a *failure* omits the + `result` key. +- **The metadata gating applies to the whole graph.** A command whose result is itself a response + model (e.g. `eval` returns an `EvalResponse` nested under `result`) has its nested + `executedAt`/`executionTimeMs` stripped in lean mode too — and restored by verbose along with + everything else. + +Two independent request flags adjust the shape: + +- `"verbose": true` — full fidelity back: every envelope field, explicit nulls, and nested response + metadata, for debugging or correlation. Honored on request-validation failures too. +- `"omitNulls": true` — drop null keys from the whole reply **inside `result`** (the success + `result` key itself always survives, see above). Opt in only when the result schema is already + known and the nulls are pure bytes — the payoff case is bulk list reads (e.g. `list_shaders` + over hundreds of built-ins repeating `"assetPath": null` per item). + +The `GET`-style endpoints (`/api/job`, `/api/progress`) have no envelope/payload split — every field +is payload — so they include null keys explicitly by default and accept `omit_nulls=true` as a query +parameter instead. An unrecognized value (e.g. `omit_nulls=1`) is not silently coerced: the reply +keeps its nulls and carries a `warnings` array naming the accepted values, so an agent can correct +itself instead of guessing. + +If your handler throws, the server catches it and returns a failure envelope with `success = false` and the exception message in `error` — you do not need to catch-and-wrap yourself unless you want a tailored message. + +## `MainThreadRequired` + +- **Default: `true`.** Most Unity APIs (scene, GameObject, asset, play-mode access) must run on the main thread. The server marshals these handlers onto the main thread via its dispatcher. +- **Set `false` only** for handlers that are thread-safe and read-only / pollable (e.g. a status or buffer-read command). These run on a background thread so they never block the main thread or deadlock against a busy editor. + +When in doubt, leave it `true`. + +## `RuntimeOnly` + +- **Default: `false`** — the command is advertised in an Editor server's `/api/commands` listing. +- **Set `true`** to hide a command from the Editor command listing. It remains **executable**; it is simply not advertised when a client is connected to an Editor (Runtime/Player servers still list it). Use this for commands that only make sense against a running Player. + +## Discovery + +Commands are discovered by `CommandRegistry`, which scans for `[CliCommand]`-tagged methods through a pluggable `ICommandDiscovery`: + +- In the **Editor**, `TypeCacheCommandDiscovery` provides fast `TypeCache`-based discovery. +- In a **Player**, the registry falls back to reflection over loaded assemblies. + +Results are cached until the next domain reload. **A newly added command becomes available after the next recompile** — no registration call is needed; just declare it and recompile. + +## Registering a command dynamically + +`[CliCommand]` covers commands you know about at compile time. When the set of commands depends on runtime state — a tool that exposes one command per loaded document, a plugin host, a test that needs a throwaway command — register them directly instead: + +```csharp +CommandRegistry.RegisterCommand( + "my_dynamic_command", + "What this command does", + new Func(MyHandler), + mainThreadRequired: true, + runtimeOnly: false, + tags: new[] { "mytool" }); +``` + +The result is an ordinary command: it appears in `/api/commands`, carries the same metadata, and executes through `/api/exec` exactly like an attribute-declared one. + +**Parameters still come from `[CliArg]`.** The registry reads the handler's own parameters, so a handler method annotates them exactly as an attribute-declared command does: + +```csharp +private static object MyHandler( + [CliArg("text", "Some input", Required = true)] string text, + [CliArg("count", "How many times")] int count = 1) +{ + return new { echoed = text, count }; +} +``` + +A lambda cannot carry `[CliArg]` on its parameters, so registering one yields default metadata (the C# parameter name, required only when there is no default value). Register a named method when you want full metadata. + +**Instance methods are allowed.** Unlike the attribute path, the handler is a delegate, so it may be bound to an instance — the command then runs against that instance: + +```csharp +var session = new MySession(documentId); +CommandRegistry.RegisterCommand("read_document", "Read the open document", + new Func(session.Read), tags: new[] { "mytool" }); +``` + +**Removing a command:** + +```csharp +bool removed = CommandRegistry.UnregisterCommand("my_dynamic_command"); +``` + +`UnregisterCommand` returns `false` when nothing was registered under that name. Attribute-declared commands are part of the code and are never removable, so passing one of their names also returns `false`. + +**Lifetime and collisions.** Registrations live until they are unregistered or the domain reloads — statics reset on reload, so re-register from wherever your code initializes (e.g. `[InitializeOnLoadMethod]`). + +A registration made **while in Play Mode** is also dropped when Play Mode exits, so a script registering from `Awake` or `OnEnable` starts each Play session with a clean registry. This matters when Enter Play Mode has domain reload disabled: without it, the second entry would throw (the name would still be taken by the first entry) and a surviving registration would hold a delegate bound to the previous session's destroyed object. A registration made in **Edit Mode** survives a Play session — an `[InitializeOnLoadMethod]` runs once per domain, so nothing would restore it. + +All registrations survive a discovery-mechanism swap. Registering a name that is already taken, by an attribute-declared command or an earlier dynamic one, throws `InvalidOperationException` rather than shadowing it; unregister first if you mean to replace it. + +## Minimal custom command template + +```csharp +using Unity.Pipeline.Commands; + +public static class MyCommands +{ + [CliCommand("my_command", "What this command does")] + public static object MyCommand( + [CliArg("text", "Some input", Required = true)] string text, + [CliArg("count", "How many times")] int count = 1) + { + // Do work on the main thread (MainThreadRequired defaults to true). + return new { echoed = text, count }; // anonymous object → response.result + } +} +``` + +Recompile, then invoke it from your client (`unity command my_command --text hello --count 3`). + +## See also + +- [Command reference](commands/runtime.md) +- [Connectivity](connectivity.md) — how clients reach the server and authenticate. diff --git a/AIClient/Packages/com.unity.pipeline/Documentation~/filter.yml b/AIClient/Packages/com.unity.pipeline/Documentation~/filter.yml new file mode 100644 index 0000000..ab48510 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Documentation~/filter.yml @@ -0,0 +1,20 @@ +apiRules: + # Everything under Unity.Pipeline.Tests.* (Tests/Editor, Tests/Runtime, and their + # sub-namespaces) is test-only. Some of it is forced `public` for a compiler reason, not + # because it's consumable package API: e.g. code-reload/IL-interpreter probe classes are named + # literally by SourceCodeTransformer in a freshly-generated override that Roslyn compiles into + # a separate, uniquely named in-memory assembly (no InternalsVisibleTo exists for those + # ephemeral assemblies), so `internal` fails the compile with CS0122. Exempting the whole test + # namespace tree means a future probe/fixture that needs the same `public` workaround doesn't + # need a new filter.yml entry. This does not affect PVP-150/151 for the shipped Runtime/Editor + # assemblies — only Unity.Pipeline.Tests.* is excluded. + - exclude: + uidRegex: ^Unity\.Pipeline\.Tests\..+$ + type: Type + + # Decoy attribute (CodeReloadInPlaceTests.cs) that only exists to prove the IL weaver matches + # by full name, not simple name — not consumable API, test-only despite living outside the + # Unity.Pipeline.Tests namespace. + - exclude: + uidRegex: ^FakeReload\.CodeReloadAttribute$ + type: Type diff --git a/AIClient/Packages/com.unity.pipeline/Documentation~/images/codereload-watcher-panel.png b/AIClient/Packages/com.unity.pipeline/Documentation~/images/codereload-watcher-panel.png new file mode 100644 index 0000000000000000000000000000000000000000..9980fbc0afb97344fb7b914a1594b2311911acc9 GIT binary patch literal 45951 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 lQTj9Wv3*I/`, plus the `localhost` hostname), so it is reachable only from the same machine and never exposed on a routable interface. Clients should connect to `127.0.0.1` explicitly — see [Loopback-only binding](connectivity.md#loopback-only-binding) for why `localhost` can resolve to the IPv6 loopback (`::1`), which Unity's Mono `HttpListener` cannot serve. +- Every request must present `Authorization: Bearer `; the token is generated at startup and published in the runtime descriptor. + +Because the server exposes code evaluation and code reload, only enable it in development/QA builds — never in a production build without additional safeguards. + +## See also + +- [Connectivity](connectivity.md) — ports, descriptor file, and auth in detail. +- [Code reload](code-reload.md) — applying live code changes to a running Player. diff --git a/AIClient/Packages/com.unity.pipeline/Documentation~/safety-and-mutations.md b/AIClient/Packages/com.unity.pipeline/Documentation~/safety-and-mutations.md new file mode 100644 index 0000000..8acfd21 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Documentation~/safety-and-mutations.md @@ -0,0 +1,90 @@ +# Safety & mutations + +Mutating commands — asset writes, project-settings changes, package/build changes — +share two conventions so command authors and clients know what to expect: a `confirm`/`dry_run` gate +on destructive or overwriting operations, and Undo grouping via `AuthoringUndoScope`. Commands that +resolve caller-supplied asset paths confine them with `ProjectPaths` (see +[Creating authoring commands](authoring-commands.md)). The helpers live in `Editor/Authoring/`. + +### The confirm / dry_run convention + +Destructive or overwriting commands expose two boolean `[CliArg]`s — `confirm` and `dry_run` — and +gate their own mutation on them. There is no central dispatcher; each command applies the same simple +rules inline: + +- **`dry_run == true`** → validate and describe the intended change, mutate nothing, return a preview. + This wins even if `confirm` is also true. +- **`confirm == false`** (and not a dry run) → refuse without mutating. Return the failure the way the + command reports its other errors — `throw new ArgumentException(...)` for the throwing style (e.g. + `delete_asset`, `clear_baked_lighting`), or a structured error object for commands that return + structured results (e.g. `build`, which returns `{ success = false, status = "error", message = "…" }`). +- **otherwise** (`confirm == true`, not a dry run) → perform the mutation. Group *scene/object* + mutations in an `AuthoringUndoScope` (see below). Asset/settings/package writes are **not** part of + Unity's Undo, so they run directly — say so in the command description ("Not undoable via Ctrl+Z."). + +```csharp +[CliCommand("clear_baked_lighting", "Clear baked lightmap data for the open scene(s). Destructive: requires confirm=true (use dry_run to preview). Not undoable via Ctrl+Z.")] +public static object ClearBakedLighting( + [CliArg("confirm", "Apply the clear. Without it the call is refused.")] bool confirm = false, + [CliArg("dry_run", "Preview what would be cleared without clearing it.")] bool dryRun = false) +{ + // …resolve the open scene(s)… + if (dryRun) + return new { status = "dry_run", wouldClear = true }; + if (!confirm) + throw new ArgumentException("Refusing to clear baked lighting. Pass confirm=true to apply, or dry_run=true to preview."); + + // Clearing baked GI is not part of Unity's Undo — no AuthoringUndoScope. + Lightmapping.Clear(); + + return new { cleared = true }; +} +``` + +Purely additive, non-destructive commands (e.g. `create_folder`, `add_animator_parameter`) +do not take `confirm`/`dry_run`; they just perform the mutation directly. + +### Undo grouping + +Scene/object mutations are grouped with `AuthoringUndoScope` so a multi-step command reverts as a +single Ctrl+Z step. It increments Unity's current Undo group on construction and calls +`Undo.CollapseUndoOperations` on dispose, collapsing everything the body registers — via +`Undo.RecordObject`, `Undo.RegisterCreatedObjectUndo`, and similar — into one named step. The command +opts into Undo by calling those APIs inside the scope. See +[Creating authoring commands](authoring-commands.md) for the full pattern and the per-mutation `Undo` +API table. + +> **Caveat.** Some operations are not part of Unity's Undo system. `AssetDatabase` operations, UPM +> package changes, and settings backed by native assets may not be undoable; for those the collapse is +> simply a no-op and Ctrl+Z will not revert the change. Don't rely on Undo to clean up such writes — +> validate up front and fail before writing. + +### Path confinement + +Commands that accept a caller-supplied asset path resolve it through `ProjectPaths.Resolve`, which +normalizes the path, rejects `..` traversal, and confines it to the configurable authoring root +(default `Assets`) so agent-supplied paths cannot escape the project. It returns a project-relative +path, or `null` with an `error` string when the path escapes the root. + +```csharp +var normalized = ProjectPaths.Resolve(path, out var error); +if (normalized == null) + throw new ArgumentException(error); +// normalized is project-relative and guaranteed to live under the authoring root. +``` + +See [Creating authoring commands](authoring-commands.md) for the full path-handling rules and the +`set_authoring_root` / `get_authoring_root` commands that adjust the root. + +### For command authors + +To make a mutating command safe: + +1. If the operation is destructive or overwrites existing content, add `confirm` and `dry_run` boolean + `[CliArg]`s and gate on them inline (preview on `dry_run`, refuse on `!confirm`). +2. Group scene/object mutations in `using (new AuthoringUndoScope(""))` and register Undo + operations inside it where the mutation is undoable. +3. Resolve any caller-supplied asset path through `ProjectPaths.Resolve` before touching the filesystem + — ideally during validation, so a bad path fails before anything is applied. + +See [Creating commands](creating-commands.md) and [Creating authoring commands](authoring-commands.md). diff --git a/AIClient/Packages/com.unity.pipeline/Documentation~/testing.md b/AIClient/Packages/com.unity.pipeline/Documentation~/testing.md new file mode 100644 index 0000000..5825b2f --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Documentation~/testing.md @@ -0,0 +1,95 @@ +# Tests architecture + +How the package's tests exercise commands. There are two complementary styles — **ViaClient** (over real HTTP, end-to-end) and **CommandDirect** (calling the static command method straight) — backed by a small set of shared test helpers. + +## Two test styles + +### ViaClient — exercise the full HTTP path + +Spin up an isolated `PipelineTestServer` and call `server.Execute(command, params)`. This goes over HTTP through the same routing, parameter coercion, and threading the real server uses — it tests the command *as a client sees it*. + +```csharp +[Test] +public void SetTransform_ViaClient_ArrayParams_Apply() +{ + var go = Track(new GameObject("Xform219_Arrays")); + + using (var server = new PipelineTestServer()) + { + var response = server.Execute("set_transform", new + { + target = new { instanceId = PipelineUtils.GetObjectId(go) }, + position = new[] { 1f, 2f, 3f }, + rotation = new[] { 0f, 90f, 0f }, + scale = new[] { 2f, 2f, 2f } + }); + + Assert.IsTrue(response.IsSuccess, $"set_transform should succeed: {response.Error}"); + Assert.AreEqual(new Vector3(1, 2, 3), go.transform.localPosition); + } +} +``` + +The test server is isolated: it uses the **test editor port range `7850`–`7899`** and **writes no descriptor**, so it never disturbs the live editor server (which uses `7800`–`7849`). `Execute` pumps the server's own dispatcher while the HTTP call is in flight, so `MainThreadRequired` commands complete even from a plain `[Test]` that blocks the main thread — no deadlock. + +### CommandDirect — call the static method directly + +Call the command's static method with typed arguments. This is synchronous, with **no server, HTTP, or dispatcher** involved — fast and ideal for unit-testing command logic and parameter handling. + +```csharp +[Test] +public void SetTransform_Direct_TypedArrays_Apply() +{ + var go = Track(new GameObject("Xform219_Direct")); + + GameObjectCommands.SetTransform(RefTo(go), + position: new[] { 1f, 2f, 3f }, + rotation: new[] { 0f, 90f, 0f }, + scale: new[] { 2f, 2f, 2f }); + + Assert.AreEqual(new Vector3(1, 2, 3), go.transform.localPosition); + Assert.AreEqual(new Vector3(2, 2, 2), go.transform.localScale); +} +``` + +Use **CommandDirect** to verify a command's behavior with strongly-typed inputs; use **ViaClient** to additionally verify wire-level concerns (JSON coercion, required-parameter validation, threading). + +## Shared helpers + +| Helper | Role | +|--------|------| +| `PipelineTestServer` | Disposable wrapper that starts an isolated `TestEditorPipelineServer`, wires up a `PipelineClient`, and exposes `Execute(command, parameters, timeoutMs = 30000)`. Pumps the server dispatcher during each call to avoid main-thread deadlock. | +| `TestEditorPipelineServer` | `EditorPipelineServer` subclass for tests. Overrides `WritesDescriptor => false`, `GetPortRange() => (7850, 7899)`, and `GetToken()` (from `SecurityTokenManager`) so it is fully isolated from the live server. | +| `PipelineClient` | Test-side HTTP client. Constructed from a URL+token or a server/manager instance. Key methods: `ExecuteCommandAsync` (`/api/exec`), `GetStatusAsync` (`/api/status`), `PostJsonAsync`. Returns a `PipelineResponse` (`IsSuccess`, `StatusCode`, `Error`, `JsonResponse`, `IsCommandSuccess`). | +| `EditorTestUtilities` | Async helpers for editor state, e.g. `WaitFor(Func condition, timeoutMs)` to poll a condition without busy-waiting. | +| `LiveServerGuard` | Assembly-level `ITestAction` that asserts the **live editor server survives the test run**. | + +### `PipelineTestServer` setup + +```csharp +public PipelineTestServer() +{ + m_Server = new TestEditorPipelineServer(); + m_Server.Start(); // auto-assigns a port in 7850-7899; writes no descriptor + m_Client = new PipelineClient($"http://localhost:{m_Server.Port}", SecurityTokenManager.GetOrCreateToken()); +} +``` + +Wrap it in a `using` (it is disposable) so the isolated server is stopped at the end of the test. + +### `LiveServerGuard` + +Applied once at assembly scope (`[assembly: LiveServerGuard]`), it runs before and after **every** test in the editor suite. If a live editor server was advertising its descriptor before a test, the guard asserts afterwards that the test did not disturb it — the descriptor still exists, the port is unchanged, and the server is still listening: + +```csharp +Assert.IsNotNull(after, $"'{test.Name}' deleted the live pipeline server descriptor"); +Assert.AreEqual(m_Before.Port, after.Port, $"'{test.Name}' changed the port"); +Assert.IsTrue(IsListening(after.Port, after.EvalToken), $"'{test.Name}' left the server not responding"); +``` + +This is what makes it safe to "dogfood" — run the test suite against the very editor you are driving — without a test clobbering the live server. Tests that intentionally start/stop the live server are marked `[Explicit]` and must hand it back intact. + +## See also + +- [Creating commands](creating-commands.md) — the command API these tests exercise. +- [Connectivity](connectivity.md) — ports, descriptor, and auth (the test server deliberately skips the descriptor). diff --git a/AIClient/Packages/com.unity.pipeline/Editor.meta b/AIClient/Packages/com.unity.pipeline/Editor.meta new file mode 100644 index 0000000..ac21aa2 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5144d7ecd5530424ab66f205802d8c9e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Authoring.meta b/AIClient/Packages/com.unity.pipeline/Editor/Authoring.meta new file mode 100644 index 0000000..266f586 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Authoring.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 113bc2bcfe487eb469aa654e6718f78b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Authoring/AuthoringUndoScope.cs b/AIClient/Packages/com.unity.pipeline/Editor/Authoring/AuthoringUndoScope.cs new file mode 100644 index 0000000..68480a7 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Authoring/AuthoringUndoScope.cs @@ -0,0 +1,58 @@ +using System; +using UnityEditor; + +namespace Unity.Pipeline.Editor.Authoring +{ + ///

+ /// + /// Groups all Undo operations registered during its lifetime into a single, collapsible Editor + /// Undo step, so a multi-step agent action reverts as one. Register mutations inside the scope + /// with Undo.RegisterCreatedObjectUndo / RegisterCompleteObjectUndo / etc. + /// + /// + /// + /// using (new AuthoringUndoScope("Create Enemy")) + /// { + /// var go = new GameObject("Enemy"); + /// Undo.RegisterCreatedObjectUndo(go, "Create Enemy"); + /// // ... further registered mutations collapse into the same step + /// } + /// + /// + /// + /// NOTE: minimal seed for the shared safety policy (CAT-2509). AssetDatabase operations + /// (folder/asset creation, import) are NOT part of Unity's Undo system, so this scope only + /// affects scene/object mutations. + /// + /// + public sealed class AuthoringUndoScope : IDisposable + { + private readonly int m_Group; + private bool m_Canceled; + + /// Start a new collapsible Undo group. + /// Name shown for the collapsed Undo step. + public AuthoringUndoScope(string name) + { + Undo.IncrementCurrentGroup(); + m_Group = Undo.GetCurrentGroup(); + if (!string.IsNullOrEmpty(name)) + Undo.SetCurrentGroupName(name); + } + + /// + /// Skip the collapse on dispose. Call after the scope's registered operations have been + /// reverted wholesale (e.g. Undo.RevertAllDownToGroup(group) on a transactional batch + /// abort): the group id no longer refers to this scope's operations on the Undo stack, and + /// collapsing a discarded id could fold whatever now sits at that index into a stray group. + /// + public void Cancel() => m_Canceled = true; + + /// Collapse all Undo operations registered during this scope into one step, unless was called. + public void Dispose() + { + if (!m_Canceled) + Undo.CollapseUndoOperations(m_Group); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Authoring/AuthoringUndoScope.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Authoring/AuthoringUndoScope.cs.meta new file mode 100644 index 0000000..a0ef9b1 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Authoring/AuthoringUndoScope.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6ef72626627670a4eadfccdab20cd9ba +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Authoring/ObjectResolver.cs b/AIClient/Packages/com.unity.pipeline/Editor/Authoring/ObjectResolver.cs new file mode 100644 index 0000000..eddac8f --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Authoring/ObjectResolver.cs @@ -0,0 +1,256 @@ +using Unity.Pipeline.Models; +using UnityEditor; +using UnityEngine; +using UnityEngine.SceneManagement; +using Object = UnityEngine.Object; + +namespace Unity.Pipeline.Editor.Authoring +{ + /// + /// Resolves an agent-supplied handle to a live UnityEngine.Object, and + /// describes any object back into a canonical identity. + /// Backed by GlobalObjectId, which addresses both assets (GUID + fileId) and scene objects. + /// + public static class ObjectResolver + { + /// + /// Try to resolve a handle to a loaded object. Returns false with an + /// when the handle is empty or does not resolve. + /// + /// The agent-supplied object reference. + /// The resolved object, or null on failure. + /// A human-readable reason on failure, or null on success. + /// True if the handle resolved. + public static bool TryResolve(ObjectRef handle, out Object obj, out string error) + { + obj = null; + error = null; + + if (handle == null || handle.IsEmpty) + { + error = "Empty object reference."; + return false; + } + + // 1. Canonical GlobalObjectId. + if (!string.IsNullOrEmpty(handle.GlobalId)) + { + if (!GlobalObjectId.TryParse(handle.GlobalId, out var gid)) + { + error = $"Invalid globalId '{handle.GlobalId}'."; + return false; + } + + obj = GlobalObjectId.GlobalObjectIdentifierToObjectSlow(gid); + if (obj != null) + return true; + + error = $"globalId '{handle.GlobalId}' did not resolve to a loaded object."; + return false; + } + + // 2. Asset path. Explicit "Assets/"/"Packages/"-rooted paths load as-is; a bare relative + // path (e.g. "Materials/Floor.mat") is normalized under the authoring root first. If it + // does not resolve to an asset, fall back to a hierarchy lookup so dotted GameObject names + // (e.g. "Cube.001") still resolve, and report every strategy that was tried. + if (!string.IsNullOrEmpty(handle.Path)) + { + var raw = handle.Path; + var explicitlyRooted = IsExplicitlyRooted(raw); + var assetPath = raw; + if (!explicitlyRooted) + { + var resolved = ProjectPaths.Resolve(raw, out _); + if (!string.IsNullOrEmpty(resolved)) + assetPath = resolved; + } + + obj = AssetDatabase.LoadMainAssetAtPath(assetPath); + if (obj != null) + return true; + + if (explicitlyRooted) + { + error = $"No asset at path '{raw}'."; + return false; + } + + // A bare relative string may actually be a scene hierarchy path with a dotted name. + var go = FindByHierarchyPath(raw); + if (go != null) + { + obj = go; + return true; + } + + error = $"Could not resolve '{raw}': no asset at '{assetPath}', no GameObject at hierarchy path '{raw}'."; + return false; + } + + // 3. GUID (+ optional fileId for sub-assets). + if (!string.IsNullOrEmpty(handle.Guid)) + { + var path = AssetDatabase.GUIDToAssetPath(handle.Guid); + if (string.IsNullOrEmpty(path)) + { + error = $"Unknown GUID '{handle.Guid}'."; + return false; + } + + if (handle.FileId.HasValue) + { + foreach (var candidate in AssetDatabase.LoadAllAssetsAtPath(path)) + { + if (candidate != null && + AssetDatabase.TryGetGUIDAndLocalFileIdentifier(candidate, out _, out long localId) && + localId == handle.FileId.Value) + { + obj = candidate; + return true; + } + } + + error = $"No sub-asset with fileId {handle.FileId} in '{path}'."; + return false; + } + + obj = AssetDatabase.LoadMainAssetAtPath(path); + if (obj != null) + return true; + + error = $"Could not load asset '{path}'."; + return false; + } + + // 4. Instance id (loaded/scene object). + if (handle.InstanceId.HasValue) + { + obj = PipelineUtils.IdToObject(handle.InstanceId.Value); + if (obj != null) + return true; + + error = $"No loaded object with instanceId {handle.InstanceId}."; + return false; + } + + // 5. Scene hierarchy path. + if (!string.IsNullOrEmpty(handle.HierarchyPath)) + { + var go = FindByHierarchyPath(handle.HierarchyPath); + if (go != null) + { + obj = go; + return true; + } + + error = $"No GameObject at hierarchy path '{handle.HierarchyPath}'."; + return false; + } + + error = "Empty object reference."; + return false; + } + + /// + /// Produce the canonical identity for an object (assets get path/guid/fileId; loaded objects + /// get instanceId/hierarchyPath). Returns null for a null object. + /// + /// The object to describe. + /// The object's canonical identity, or null if is null. + public static AuthoringResult Describe(Object obj) + { + if (obj == null) + return null; + + var result = new AuthoringResult { Type = obj.GetType().Name }; + + var assetPath = AssetDatabase.GetAssetPath(obj); + if (!string.IsNullOrEmpty(assetPath)) + { + result.AssetPath = assetPath; + if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(obj, out var guid, out long localId)) + { + result.Guid = guid; + result.FileId = localId; + } + } + else + { + result.InstanceId = PipelineUtils.GetObjectId(obj); + var go = obj as GameObject ?? (obj as Component)?.gameObject; + if (go != null) + result.HierarchyPath = GetHierarchyPath(go); + } + + // Not every object has a global id (e.g. transient objects); ignore failures. + try + { + result.GlobalId = GlobalObjectId.GetGlobalObjectIdSlow(obj).ToString(); + } + catch + { + // leave GlobalId null + } + + return result; + } + + /// True when a path is explicitly rooted at "Assets/" or "Packages/" (or is exactly one of those). + private static bool IsExplicitlyRooted(string path) => + path == "Assets" || path == "Packages" + || path.StartsWith("Assets/", System.StringComparison.Ordinal) + || path.StartsWith("Packages/", System.StringComparison.Ordinal); + + private static GameObject FindByHierarchyPath(string path) + { + var parts = path.Trim('/').Split('/'); + if (parts.Length == 0 || string.IsNullOrEmpty(parts[0])) + return null; + + for (int s = 0; s < SceneManager.sceneCount; s++) + { + var scene = SceneManager.GetSceneAt(s); + if (!scene.isLoaded) + continue; + + foreach (var root in scene.GetRootGameObjects()) + { + if (root.name != parts[0]) + continue; + + var current = root.transform; + var matched = true; + for (int i = 1; i < parts.Length; i++) + { + var child = current.Find(parts[i]); + if (child == null) + { + matched = false; + break; + } + + current = child; + } + + if (matched) + return current.gameObject; + } + } + + return null; + } + + private static string GetHierarchyPath(GameObject go) + { + var sb = new System.Text.StringBuilder(go.name); + var parent = go.transform.parent; + while (parent != null) + { + sb.Insert(0, parent.name + "/"); + parent = parent.parent; + } + + return "/" + sb; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Authoring/ObjectResolver.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Authoring/ObjectResolver.cs.meta new file mode 100644 index 0000000..a33169d --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Authoring/ObjectResolver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 26becd8c305c973488fa15b9ea058a00 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Authoring/ProjectPaths.cs b/AIClient/Packages/com.unity.pipeline/Editor/Authoring/ProjectPaths.cs new file mode 100644 index 0000000..f5bf5e8 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Authoring/ProjectPaths.cs @@ -0,0 +1,148 @@ +using System; +using System.IO; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace Unity.Pipeline.Editor.Authoring +{ + /// + /// Project-path handling for authoring commands. + /// + /// - Paths resolve relative to the configurable (default "Assets"), + /// so callers can pass bare paths ("Gameplay/Enemies") without repeating the "Assets/" prefix. + /// - Explicit "Assets/..." (or "Packages/...") paths are treated as project-relative as-is. + /// - Every resolved path is confined to (the sandbox). With the + /// default root ("Assets") that means full Assets access; set a sub-folder to confine an agent. + /// - "../" traversal and writes outside the project root are always rejected. + /// + /// NOTE: minimal seed for the shared safety policy (CAT-2509). + /// + public static class ProjectPaths + { + private const string DefaultRoot = "Assets"; + + // Per-project EditorPrefs key so the root doesn't leak across projects on the same machine. + private static string PrefKey => $"Unity.Pipeline.AuthoringRoot:{Application.dataPath}"; + + /// Absolute path to the project root (the folder that contains Assets/). + public static string ProjectRoot => Path.GetDirectoryName(Application.dataPath); + + /// + /// Base folder (project-relative, under Assets/) that bare paths resolve against and that all + /// authoring writes are confined to. Defaults to "Assets". Persisted per project via EditorPrefs. + /// Setting an invalid value (outside Assets/ or containing "..") throws. + /// + public static string AuthoringRoot + { + get + { + var root = EditorPrefs.GetString(PrefKey, DefaultRoot); + return string.IsNullOrEmpty(root) ? DefaultRoot : root; + } + set + { + var normalized = NormalizeRoot(value, out var error); + if (normalized == null) + throw new ArgumentException(error); + EditorPrefs.SetString(PrefKey, normalized); + } + } + + /// Reset the authoring root to the default ("Assets"). + public static void ResetAuthoringRoot() => EditorPrefs.DeleteKey(PrefKey); + + /// + /// Resolve an agent-supplied path to a normalized, project-relative path confined to + /// . Bare paths are taken relative to the root; explicit + /// "Assets/..." paths and absolute paths under the project are honored. Returns null with an + /// when the path escapes the root or the project. + /// + /// The agent-supplied path to resolve. + /// A human-readable reason on failure, or null on success. + /// The normalized, project-relative path, or null on failure. + public static string Resolve(string path, out string error) + { + error = null; + if (string.IsNullOrWhiteSpace(path)) + { + error = "Path is required."; + return null; + } + + var root = AuthoringRoot; + var normalized = path.Replace('\\', '/').Trim(); + + // Absolute path: must live under the project root; convert to project-relative. + if (Path.IsPathRooted(normalized)) + { + var full = Path.GetFullPath(normalized).Replace('\\', '/'); + var projectRoot = ProjectRoot.Replace('\\', '/').TrimEnd('/'); + if (!full.Equals(projectRoot, StringComparison.OrdinalIgnoreCase) && + !full.StartsWith(projectRoot + "/", StringComparison.OrdinalIgnoreCase)) + { + error = $"Path '{path}' is outside the project root '{projectRoot}'."; + return null; + } + + normalized = full.Length > projectRoot.Length ? full.Substring(projectRoot.Length + 1) : string.Empty; + } + + normalized = normalized.TrimStart('/'); + + if (normalized.Split('/').Contains("..")) + { + error = $"Path '{path}' must not contain '..'."; + return null; + } + + // Explicit project-relative paths ("Assets/..." / "Packages/...") are used as-is; anything + // else is a bare path taken relative to the authoring root. + var isProjectRelative = + normalized == "Assets" || normalized.StartsWith("Assets/", StringComparison.Ordinal) || + normalized == "Packages" || normalized.StartsWith("Packages/", StringComparison.Ordinal); + + var resolved = (isProjectRelative ? normalized : CombineUnder(root, normalized)).TrimEnd('/'); + + // Confine to the authoring root (default "Assets" => full Assets access). + if (!(resolved == root || resolved.StartsWith(root + "/", StringComparison.Ordinal))) + { + error = $"Path '{path}' resolves to '{resolved}', which is outside the authoring root '{root}'."; + return null; + } + + return resolved; + } + + private static string CombineUnder(string root, string relative) + { + relative = relative.TrimStart('/'); + return string.IsNullOrEmpty(relative) ? root : $"{root}/{relative}"; + } + + private static string NormalizeRoot(string value, out string error) + { + error = null; + if (string.IsNullOrWhiteSpace(value)) + { + error = "Authoring root is required."; + return null; + } + + var normalized = value.Replace('\\', '/').Trim().TrimStart('/').TrimEnd('/'); + if (normalized.Split('/').Contains("..")) + { + error = $"Authoring root '{value}' must not contain '..'."; + return null; + } + + if (!(normalized == "Assets" || normalized.StartsWith("Assets/", StringComparison.Ordinal))) + { + error = $"Authoring root '{value}' must be under the project's Assets/ folder."; + return null; + } + + return normalized; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Authoring/ProjectPaths.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Authoring/ProjectPaths.cs.meta new file mode 100644 index 0000000..528dcdf --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Authoring/ProjectPaths.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 462c39b6cec1060408ca75a32bf31d89 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/BuildProcessors.meta b/AIClient/Packages/com.unity.pipeline/Editor/BuildProcessors.meta new file mode 100644 index 0000000..b17ac39 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/BuildProcessors.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6a4d02bf29da41d499ea151c638ee920 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/BuildProcessors/CodeReloadLinkXmlGenerator.cs b/AIClient/Packages/com.unity.pipeline/Editor/BuildProcessors/CodeReloadLinkXmlGenerator.cs new file mode 100644 index 0000000..faa7fb3 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/BuildProcessors/CodeReloadLinkXmlGenerator.cs @@ -0,0 +1,355 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Text; +using UnityEditor; +using UnityEditor.Build; +using UnityEditor.Build.Reporting; +using UnityEditor.Compilation; +using UnityEditor.UnityLinker; +using UnityEngine; +using Unity.Pipeline.Compilation; +using Unity.Pipeline.CodeReload; +using IlInterpreter.Interpreter; +using Assembly = System.Reflection.Assembly; + +namespace Unity.Pipeline.Editor.BuildProcessors +{ + /// + /// Contributes an auto-generated link.xml that preserves the host-binding surface the + /// interpreter exposes to reloaded / eval'd code, so IL2CPP managed stripping cannot remove + /// members the built game never referenced (symptom: "Host method '…' is not registered in the + /// binding", on device only). + /// + /// Unity's own generated link.xml can't cover this: it preserves what the build *references*, + /// and the whole point of code reload is to call members the build never referenced. So preserve + /// (a) every type in with preserve="all", and + /// (b) — because demand-time auto-bind () lets reloaded + /// code reach ANY user or UnityEngine type — the build's user assemblies and UnityEngine modules + /// wholesale. + /// + /// Development builds only: the interpreter reload/eval sinks compile out of release players. + /// Also preserves the interpreter engine itself (IlInterpreter + its reflection/metadata + /// dependencies) — kept here, rather than in a static Runtime/link.xml, precisely so + /// release players don't pay the size cost for machinery they compile out. + /// + class CodeReloadLinkXmlGenerator : IUnityLinkerProcessor + { + public int callbackOrder => 0; + + public string GenerateAdditionalLinkXmlFile(BuildReport report, UnityLinkerBuildPipelineData data) + { + // Only development builds carry the interpreter; release builds need no extra preservation. + if (report == null || !report.summary.options.HasFlag(BuildOptions.Development)) + return string.Empty; + + // The managed assemblies staged for this player build — the universe for the wholesale + // preservation pass. See CollectPlayerAssemblyNames: it unions the linker input directory + // with the editor's own player-assembly view, because on some build backends the input + // directory is empty at IUnityLinkerProcessor time and relying on it alone silently + // collapsed preservation to the explicit per-type surface — stripping everything + // demand-time auto-bind reaches (e.g. a live-added `new Slider()`, whose UITK ctors the + // built game never referenced) on device only. + // inputDirectory is obsolete on the incremental build pipeline (it comes back empty there), + // which is exactly the gap the union above closes; on the classic pipeline it is still the + // exact staged set, so keep reading it. +#pragma warning disable CS0618 + var playerAssemblies = CollectPlayerAssemblyNames(data.inputDirectory); +#pragma warning restore CS0618 + + var path = Path.GetFullPath(FileUtil.GetUniqueTempPathInProject() + "-hostbindings.link.xml"); + File.WriteAllText(path, GenerateLinkXml(playerAssemblies, out var stats)); + // The stats line is the diagnostic: if a game assembly with [CodeReload] types is missing + // from the reloadable-target list (e.g. its name matches the engine-assembly skip + // prefixes), its private state can be stripped and binding fails on device only. + Debug.Log($"Pipeline: generated code-reload host-binding link.xml at {path} — {stats}"); + return path; + } + + /// + /// The simple names of the managed assemblies that end up in this player build — the universe + /// the wholesale-preservation pass draws from. Unions two sources so a gap in either can't + /// silently collapse preservation: + /// + /// the linker input directory (the exact staged set, incl. test assemblies for a test + /// player) — recursively, since some backends nest the managed DLLs in a subfolder; + /// the editor's own view — player assemblies (user + /// code) plus every loaded UnityEngine* module (the precompiled engine modules + /// demand-time auto-bind can construct from) — which stays populated even when the input + /// directory is empty at time. + /// + /// A union only adds; it never drops an assembly the input scan found, so a test player keeps + /// its test assemblies. Returns null only if every source came up empty (preserve per-type only). + /// + internal static string[] CollectPlayerAssemblyNames(string inputDirectory) + { + var names = new HashSet(StringComparer.Ordinal); + + try + { + if (!string.IsNullOrEmpty(inputDirectory) && Directory.Exists(inputDirectory)) + foreach (var dll in Directory.GetFiles(inputDirectory, "*.dll", SearchOption.AllDirectories)) + names.Add(Path.GetFileNameWithoutExtension(dll)); + } + catch (Exception ex) + { + Debug.LogWarning($"Pipeline: could not enumerate linker input assemblies " + + $"('{inputDirectory}'): {ex.Message} — falling back to the editor's " + + "player-assembly view for wholesale preservation."); + } + + try + { + foreach (var a in CompilationPipeline.GetAssemblies(AssembliesType.Player)) + if (!string.IsNullOrEmpty(a.name)) + names.Add(a.name); + } + catch { /* editor API unavailable in this context — the UnityEngine sweep still runs */ } + + foreach (var a in PipelineUtils.GetLoadedAssemblies()) + { + var n = a.GetName().Name; + if (!string.IsNullOrEmpty(n) && n.StartsWith("UnityEngine", StringComparison.Ordinal)) + names.Add(n); + } + + return names.Count > 0 ? new List(names).ToArray() : null; + } + + /// + /// Build the interpreter's default host binding and emit a link.xml preserving every + /// registered type, grouped by owning assembly. Pure and deterministic — directly unit-testable. + /// Derives from — the builder the code-reload + /// executor runs — so the preservation set cannot drift from the runtime surface. The per-reload + /// AllowType(targetType) overlay is excluded: the target is the user's own component, + /// which the built player references and IL2CPP won't strip. + /// + public static string GenerateLinkXml() => GenerateLinkXml(null, out _); + + public static string GenerateLinkXml(out string stats) => GenerateLinkXml(null, out stats); + + /// : one-line summary of what was preserved, logged at build + /// time so a missing game assembly is visible in the build log. + /// : simple names of the managed assemblies staged for + /// the player build; when provided, user assemblies and UnityEngine modules from that set are + /// preserved wholesale (including engine-named assemblies carrying [CodeReload] members — the + /// attribute marks them as user code), and reload-target entries are limited to assemblies in + /// the set (editor-only and test assemblies drop out of game builds); when null, only per-type + /// preservation is emitted, unfiltered. + public static string GenerateLinkXml(IEnumerable playerAssemblyNames, out string stats) + { + var binding = IlInterpreterHostBindings.CreateStandard(); + + // SortedSet/SortedDictionary give a stable, diffable ordering and dedupe (closed generics + // collapsing onto their definition can produce repeats). + var byAssembly = new SortedDictionary>(StringComparer.Ordinal); + foreach (var t in binding.RegisteredTypes) + { + // Preserve the open definition for constructed generics (a closed-generic fullname is + // assembly-qualified and won't match in link.xml). + var def = t.IsGenericType && !t.IsGenericTypeDefinition ? t.GetGenericTypeDefinition() : t; + + var asm = def.Assembly.GetName().Name; + var full = def.FullName; + if (string.IsNullOrEmpty(asm) || string.IsNullOrEmpty(full)) + continue; + + full = full.Replace('+', '/'); // link.xml uses '/' as the nested-type separator + + if (!byAssembly.TryGetValue(asm, out var types)) + byAssembly[asm] = types = new SortedSet(StringComparer.Ordinal); + types.Add(full); + } + + // Also preserve the reloadable target components. The target type IS referenced by the + // built player, but a PRIVATE field only the interpreter touches can still be stripped, + // breaking the reflection walk; preserve="all" keeps every member so + // AllowNonPublicInstanceMembers(targetType) can resolve private state on device. + int hostTypeCount = 0; + foreach (var kv in byAssembly) + hostTypeCount += kv.Value.Count; + + // The AppDomain scan below also sees editor-only and test assemblies that are not part + // of the player build; when the staged set is known, reload targets outside it are + // dropped as noise. A test-player build stages its test assemblies, so fixtures keep + // their entries exactly where they matter. + HashSet staged = null; + if (playerAssemblyNames != null) + { + staged = new HashSet(StringComparer.Ordinal); + foreach (var name in playerAssemblyNames) + if (!string.IsNullOrEmpty(name)) + staged.Add(name); + } + + int targetTypeCount = 0; + var targetAssemblies = new SortedSet(StringComparer.Ordinal); + var engineNamedTargetAssemblies = new SortedSet(StringComparer.Ordinal); + foreach (var t in CollectReloadableTargetTypes()) + { + var asm = t.Assembly.GetName().Name; + var full = t.FullName; + if (string.IsNullOrEmpty(asm) || string.IsNullOrEmpty(full)) + continue; + if (staged != null && !staged.Contains(asm)) + continue; + full = full.Replace('+', '/'); + if (!byAssembly.TryGetValue(asm, out var types)) + byAssembly[asm] = types = new SortedSet(StringComparer.Ordinal); + types.Add(full); + targetTypeCount++; + targetAssemblies.Add(asm); + if (IsNonUserAssembly(asm)) + engineNamedTargetAssemblies.Add(asm); + } + + // Dev-build widening: demand-time auto-bind (HostBinding.AutoBindResolver) lets a reloaded + // or eval'd body call into ANY user or UnityEngine type, so RegisteredTypes is not the full + // callable set — preserve the build's user assemblies and UnityEngine modules wholesale. + // Unity.* packages (Burst, Collections, …) stay per-type: AOT-heavy and rarely touched from + // reload bodies. (The project-extension seam that could promote a specific type was + // deferred to a future release, so on-device reload bodies can only reach package types + // the stripper kept.) + var wholesale = new SortedSet(StringComparer.Ordinal); + // The interpreter engine itself: it parses pushed override IL via + // System.Reflection.Metadata and resolves host members by name, so those paths look + // unused to the stripper. Emitted here (dev builds only) rather than in a static + // Runtime/link.xml, which would bloat release players that compile the interpreter out. + foreach (var name in InterpreterEngineAssemblies) + wholesale.Add(name); + if (staged != null) + { + foreach (var name in staged) + { + if (name.StartsWith("UnityEngine", StringComparison.Ordinal)) wholesale.Add(name); + else if (!IsNonUserAssembly(name)) wholesale.Add(name); + } + + // A staged, engine-named assembly carrying [CodeReload] members has identified itself + // as user code participating in code reload — a package-like name (e.g. "Unity.MyGame") + // must not demote it. Preserving only its [CodeReload] types would leave the rest of + // it strippable (demand-time auto-bind would hit stripped members on device only), + // so promote it into the wholesale set like any other user assembly. + foreach (var asm in engineNamedTargetAssemblies) + wholesale.Add(asm); + } + + stats = $"{hostTypeCount} host-binding type(s) and {targetTypeCount} reloadable target type(s) " + + $"across {byAssembly.Count} assembly(ies); target assemblies: " + + (targetAssemblies.Count > 0 ? string.Join(", ", targetAssemblies) : "none") + + $"; {wholesale.Count} assembly(ies) preserved wholesale for demand-time auto-bind"; + + var sb = new StringBuilder(); + sb.AppendLine(""); + sb.AppendLine(" "); + // Wholesale assemblies first (their per-type entries are subsumed), then per-type blocks. + foreach (var name in wholesale) + sb.AppendLine($" "); + foreach (var kv in byAssembly) + { + if (wholesale.Contains(kv.Key)) continue; + sb.AppendLine($" "); + foreach (var type in kv.Value) + sb.AppendLine($" "); + sb.AppendLine(" "); + } + sb.AppendLine(""); + return sb.ToString(); + } + + // The IlInterpreter engine and its reflection/metadata dependencies — always preserved + // wholesale so pushed code reload keeps working on device. + static readonly string[] InterpreterEngineAssemblies = + { + "Unity.Pipeline.IlInterpreter", + "UnityPipeline.System.Reflection.Metadata", + "UnityPipeline.System.Collections.Immutable", + }; + + // Engine/BCL/tooling assembly names — NOT user code. Decides which staged assemblies are + // preserved wholesale, and which reload-target assemblies get the engine-named warning. + // Matching is deliberately precise (exact "Unity"/"System" or a dotted prefix, never the + // bare word) so a game assembly that merely starts with the word — "UnityChanDemo", + // "SystemsRuntime" — is still preserved wholesale. + static bool IsNonUserAssembly(string name) => + name == "Unity" || + name.StartsWith("Unity.", StringComparison.Ordinal) || + name.StartsWith("UnityEngine", StringComparison.Ordinal) || + name.StartsWith("UnityEditor", StringComparison.Ordinal) || + name == "System" || + name.StartsWith("System.", StringComparison.Ordinal) || + name.StartsWith("Microsoft.", StringComparison.Ordinal) || + name.StartsWith("Mono.", StringComparison.Ordinal) || + name == "mscorlib" || + name == "netstandard" || + name.StartsWith("nunit.", StringComparison.Ordinal); + + /// + /// User-code types that carry a class-level [CodeReload] or any [CodeReload] + /// method — i.e. every type whose members can be reloaded through + /// the interpreter and therefore needs its (possibly private) fields kept under stripping. + /// The attributes live in Unity.Pipeline, so only assemblies referencing it can carry + /// them — a cheap, metadata-only check that gates the expensive type scan. Assembly *names* + /// play no part here, so game assemblies named like packages ("Unity.MyGame") are covered. + /// + static IEnumerable CollectReloadableTargetTypes() + { + var results = new List(); + foreach (var asm in PipelineUtils.GetLoadedAssemblies()) + { + if (!ReferencesPipelineRuntime(asm)) + continue; + + Type[] types; + try { types = asm.GetTypes(); } + catch (ReflectionTypeLoadException ex) { types = ex.Types; } + catch { continue; } + + foreach (var t in types) + { + if (t == null) continue; + try + { + if (t.IsDefined(typeof(CodeReloadAttribute), inherit: false) || HasReloadableMethod(t)) + results.Add(t); + } + catch { /* type that can't be inspected — skip */ } + } + } + return results; + } + + static bool ReferencesPipelineRuntime(Assembly asm) + { + var pipeline = typeof(CodeReloadAttribute).Assembly.GetName().Name; + try + { + foreach (var reference in asm.GetReferencedAssemblies()) + if (string.Equals(reference.Name, pipeline, StringComparison.Ordinal)) + return true; + } + catch { /* dynamic/unloadable assembly — treat as not referencing */ } + return false; + } + + static bool HasReloadableMethod(Type t) + { + const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic + | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly; + foreach (var m in t.GetMethods(flags)) + { + if (m.IsDefined(typeof(CodeReloadAttribute), inherit: false)) + return true; + } + return false; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/BuildProcessors/CodeReloadLinkXmlGenerator.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/BuildProcessors/CodeReloadLinkXmlGenerator.cs.meta new file mode 100644 index 0000000..613526c --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/BuildProcessors/CodeReloadLinkXmlGenerator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b802ce727e209d74bbbda4467462840a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/BuildProcessors/PipelineRuntimeBuildProcessor.cs b/AIClient/Packages/com.unity.pipeline/Editor/BuildProcessors/PipelineRuntimeBuildProcessor.cs new file mode 100644 index 0000000..50d28a3 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/BuildProcessors/PipelineRuntimeBuildProcessor.cs @@ -0,0 +1,375 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using Unity.Pipeline.Config; +using UnityEngine; +using UnityEditor; +using UnityEditor.Build; +using UnityEditor.Build.Reporting; + +namespace Unity.Pipeline.Editor.BuildProcessors +{ + /// + /// Build processor for runtime Pipeline support. Three responsibilities: + /// - Validates the RuntimePipelineConfig settings (JSON-authored, read via + /// RuntimePipelineConfig.Load()) before allowing builds with runtime Pipeline enabled. + /// - Bakes the current settings into a transient RuntimePipelineConfig Resources asset so a + /// Player build can find them (the authored copy stays in ProjectSettings/, never here). + /// - Bakes the project's code reload scope (Assets + loaded package locations) into a + /// generated RuntimePipelineBuildInfo asset. A running Player cannot resolve the project + /// layout, so the absolute roots it is allowed to code reload from must be captured at build + /// time. + /// Both generated assets are purged at the very start of every build (before either is + /// possibly rewritten) and deleted again after a successful build, so machine-specific/ + /// duplicated data never lingers in the project — including a stale, possibly-enabled asset + /// left behind by a build that was interrupted before OnPostprocessBuild could run (Unity + /// never invokes it for a failed or cancelled build). + /// +#if UNITY_6000_3_OR_NEWER + class PipelineRuntimeBuildProcessor : IPreprocessBuildWithContext, IPostprocessBuildWithReport +#else + class PipelineRuntimeBuildProcessor : IPreprocessBuildWithReport, IPostprocessBuildWithReport +#endif + { + /// Callback ordering relative to other build processors (0 = default). + public int callbackOrder => 0; + + private const string ConfigAssetPath = "Assets/Settings/Pipeline/Resources/RuntimePipelineConfig.asset"; + private const string BuildInfoAssetPath = "Assets/Settings/Pipeline/Resources/RuntimePipelineBuildInfo.asset"; + + // Opt-in symbol that puts the Pipeline into a build that is not a Development Build. Kept in + // step with the defineConstraints on Unity.Pipeline / Unity.Pipeline.IlInterpreter and on the + // bundled DLLs under Runtime/Plugins/CodeAnalysis: if this file and those disagree, a player + // gets settings assets no code can read, or Pipeline code with no settings to start from. + private const string EnableSymbol = "ENABLE_RUNTIME_PIPELINE"; + + /// Verify bundled DLL integrity and validate runtime pipeline configuration before a build. +#if UNITY_6000_3_OR_NEWER + /// The build callback context. + public void OnPreprocessBuild(BuildCallbackContext ctx) +#else + /// The build report. + public void OnPreprocessBuild(BuildReport report) +#endif + { + // Purge any leftovers from a previous, interrupted build before anything else in this + // method — every exit path below (no config, disabled, not a development build, + // validation failure) must start from a clean slate. OnPostprocessBuild is not invoked + // for a failed/cancelled build, so it can never be relied on for this; + // this purge is the only mechanism that actually guarantees it. Without it, a stale + // *enabled* asset left by an earlier interrupted build would still get packaged into a + // build that is supposed to have Pipeline disabled. + DeleteGeneratedAssetsIfPresent(); + + // Integrity gate: fail the build if a bundled Roslyn DLL was swapped or modified. + VerifyBundledChecksums(); + + var config = RuntimePipelineConfig.Load(); + if (config == null) + { + Debug.LogWarning("Pipeline: No RuntimePipelineConfig asset found (Project Settings > Pipeline > Runtime). Pipeline will be disabled in Player builds."); + return; + } + + try + { + if (!config.enableInBuilds) + { + Debug.LogWarning("Pipeline: RuntimePipelineConfig found, but enableInBuilds = false. Pipeline will be disabled in Player builds."); + return; + } + + // A build that will not contain the Pipeline assemblies cannot read the generated + // Resources assets, so baking them would ship dead, machine-specific data. + if (!PipelineIsInBuild()) + { + Debug.Log("Pipeline: enableInBuilds is on, but this build is neither a Development " + + $"Build nor defines {EnableSymbol}, so the Pipeline assemblies and settings are " + + "excluded from it."); + return; + } + + var validationResult = config.Validate(); + if (!validationResult.IsValid) + { + throw new BuildFailedException($"Pipeline: Runtime configuration validation failed: {validationResult.Message}"); + } + + if (validationResult.Level == "warning") + { + Debug.LogWarning($"Pipeline: Runtime configuration warning: {validationResult.Message}"); + } + + // Push signing: ensure the project key exists and bake its public half into the + // build info, so the player rejects any code-reload push not signed by the matching + // private key. Log the fingerprint so a later key mismatch is diagnosable from the + // build log alone. + var privateKey = PushSigningKey.LoadOrCreate(PushSigningKey.DefaultDirectory, out var keyCreated); + var pushPublicKey = Unity.Pipeline.CodeReload.PushEnvelope.DerivePublicKey(privateKey); + Debug.Log($"Pipeline: push-signing key {(keyCreated ? "GENERATED" : "loaded")} " + + $"(fingerprint {Unity.Pipeline.CodeReload.PushEnvelope.Fingerprint(pushPublicKey)}, " + + $"Library/Pipeline/{PushSigningKey.KeyFileName}). This build only accepts pushes signed with it."); + + WriteConfigAsset(config); + WriteBuildInfoAsset(pushPublicKey); + + Debug.Log("Pipeline: Runtime server ENABLED in build."); + } + finally + { + UnityEngine.Object.DestroyImmediate(config); + } + } + + /// + /// Whether this build will contain the Pipeline runtime assemblies, i.e. whether it satisfies + /// their UNITY_EDITOR || DEVELOPMENT_BUILD || ENABLE_RUNTIME_PIPELINE define + /// constraint. A scripted build (the build command, which calls BuildPlayer with + /// ) is a development build even when the Build + /// Settings toggle is off, so the command's active options count too. + /// + private static bool PipelineIsInBuild() + { + if (EditorUserBuildSettings.development) + return true; + + if (Commands.Build.BuildCommand.ActiveScriptedBuildOptions is { } scriptedOptions + && (scriptedOptions & BuildOptions.Development) != 0) + return true; + + var group = BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget); + var defines = PlayerSettings.GetScriptingDefineSymbols(NamedBuildTarget.FromBuildTargetGroup(group)); + return defines != null && defines.Split(';').Any(d => d.Trim() == EnableSymbol); + } + + public void OnPostprocessBuild(BuildReport report) + { + DeleteGeneratedAssetsIfPresent(); + } + + /// + /// Absolute roots considered in-scope for runtime code reload: the project's Assets folder + /// plus the resolved location of every package loaded into the project (a local package may + /// live anywhere on disk, not only under Packages). + /// + /// Absolute paths of the project's Assets folder and every loaded package. + public static List CollectProjectRoots() + { + var roots = new List { Path.GetFullPath(Application.dataPath) }; + + foreach (var package in UnityEditor.PackageManager.PackageInfo.GetAllRegisteredPackages()) + { + if (!string.IsNullOrEmpty(package.resolvedPath)) + { + roots.Add(Path.GetFullPath(package.resolvedPath)); + } + } + + return roots; + } + + private static void WriteConfigAsset(RuntimePipelineConfig sourceConfig) + { + var folder = Path.GetDirectoryName(ConfigAssetPath).Replace('\\', '/'); + CreateFolderRecursive(folder); + + // No DeleteGeneratedAssetIfPresent() call here: OnPreprocessBuild already purged both + // paths before any of this method's caller ran, so this path is guaranteed clear. + + var baked = ScriptableObject.CreateInstance(); + baked.enableInBuilds = sourceConfig.enableInBuilds; + baked.port = sourceConfig.port; + baked.requestTimeoutMs = sourceConfig.requestTimeoutMs; + baked.enableAuditLogging = sourceConfig.enableAuditLogging; + baked.autoStart = sourceConfig.autoStart; + baked.maxWorkItemsPerFrame = sourceConfig.maxWorkItemsPerFrame; + AssetDatabase.CreateAsset(baked, ConfigAssetPath); + AssetDatabase.SaveAssets(); + } + + private static void WriteBuildInfoAsset(string pushPublicKey) + { + var folder = Path.GetDirectoryName(BuildInfoAssetPath).Replace('\\', '/'); + CreateFolderRecursive(folder); + + // No DeleteGeneratedAssetIfPresent() call here: OnPreprocessBuild already purged both + // paths before any of this method's caller ran, so this path is guaranteed clear. + + var buildInfo = ScriptableObject.CreateInstance(); + buildInfo.allowedReloadRoots = CollectProjectRoots(); + buildInfo.pushPublicKey = pushPublicKey ?? ""; + AssetDatabase.CreateAsset(buildInfo, BuildInfoAssetPath); + AssetDatabase.SaveAssets(); + } + + /// + /// Delete both transient build-only assets if either is present, however they got there — + /// baked by a previous build (normal cleanup) or left behind by one that never reached + /// OnPostprocessBuild (crash, force-quit, cancelled build). + /// + private static void DeleteGeneratedAssetsIfPresent() + { + DeleteGeneratedAssetIfPresent(ConfigAssetPath); + DeleteGeneratedAssetIfPresent(BuildInfoAssetPath); + } + + /// + /// Untyped load + a raw file-existence fallback, deliberately not a typed + /// AssetDatabase.LoadAssetAtPath<T>: a typed load returns null — leaving a stale file + /// untouched on disk, inside Resources, where a Player build would still package it — for + /// any asset whose script reference broke after a package upgrade, or that was only + /// partially written by the very crash that left it behind. Both are exactly the kind of + /// leftover this cleanup exists to catch. + /// + private static void DeleteGeneratedAssetIfPresent(string assetPath) + { + if (AssetDatabase.LoadAssetAtPath(assetPath) != null || File.Exists(assetPath)) + AssetDatabase.DeleteAsset(assetPath); + } + + private static void CreateFolderRecursive(string folder) + { + var parts = folder.Split('/'); + var current = parts[0]; + for (var i = 1; i < parts.Length; i++) + { + var next = current + "/" + parts[i]; + if (!AssetDatabase.IsValidFolder(next)) + AssetDatabase.CreateFolder(current, parts[i]); + current = next; + } + } + + // Relative location of the bundled Roslyn DLLs + their integrity manifest within the package. + private const string CodeAnalysisRelDir = "Runtime/Plugins/CodeAnalysis"; + private const string ChecksumsFileName = "CHECKSUMS"; + + /// + /// Verify the bundled Roslyn DLLs against the committed CHECKSUMS manifest, locating them + /// relative to this package on disk. Throws on any + /// mismatch so a tampered/swapped DLL cannot be built into a player. + /// + public static void VerifyBundledChecksums() + { + if (!TryGetBundledCodeAnalysisPaths(out var codeAnalysisDir, out var checksumsPath)) + { + throw new BuildFailedException( + "Pipeline: could not locate the com.unity.pipeline package on disk to verify " + + "bundled Roslyn DLL integrity. Aborting build."); + } + + var error = VerifyChecksums(codeAnalysisDir, checksumsPath); + if (error != null) + { + throw new BuildFailedException($"Pipeline: bundled Roslyn DLL integrity check failed. {error}"); + } + } + + /// + /// Resolve the bundled Roslyn DLL folder and its CHECKSUMS manifest from this package's + /// location on disk. Returns false when the package cannot be located, in which case both + /// out parameters are null. + /// + /// Directory holding the bundled Roslyn DLLs. + /// Path to the CHECKSUMS manifest inside that directory. + /// True when the package was located and both paths were resolved. + public static bool TryGetBundledCodeAnalysisPaths(out string codeAnalysisDir, out string checksumsPath) + { + codeAnalysisDir = null; + checksumsPath = null; + + var packageInfo = UnityEditor.PackageManager.PackageInfo.FindForAssembly( + typeof(PipelineRuntimeBuildProcessor).Assembly); + + if (packageInfo == null || string.IsNullOrEmpty(packageInfo.resolvedPath)) + return false; + + codeAnalysisDir = Path.Combine(packageInfo.resolvedPath, CodeAnalysisRelDir); + checksumsPath = Path.Combine(codeAnalysisDir, ChecksumsFileName); + return true; + } + + /// + /// Core, side-effect-free integrity check (so it is directly unit-testable). Returns null + /// when every DLL listed in exists under + /// with a matching SHA-256 and no unlisted DLL is present; + /// otherwise returns a human-readable error describing the first problem found. + /// + /// Directory containing the bundled Roslyn DLLs. + /// Path to the CHECKSUMS manifest. + /// Null if every DLL matches; otherwise a human-readable description of the first problem found. + public static string VerifyChecksums(string codeAnalysisDir, string checksumsPath) + { + if (!Directory.Exists(codeAnalysisDir)) + return $"DLL directory not found: {codeAnalysisDir}"; + if (!File.Exists(checksumsPath)) + return $"CHECKSUMS manifest not found: {checksumsPath}"; + + var expected = ParseChecksums(checksumsPath); + if (expected.Count == 0) + return $"CHECKSUMS manifest has no entries: {checksumsPath}"; + + // Every listed DLL must exist and match. + foreach (var entry in expected) + { + var dllPath = Path.Combine(codeAnalysisDir, entry.Key); + if (!File.Exists(dllPath)) + return $"listed DLL is missing: {entry.Key}"; + + var actual = ComputeSha256(dllPath); + if (!string.Equals(actual, entry.Value, StringComparison.OrdinalIgnoreCase)) + return $"hash mismatch for {entry.Key} (expected {entry.Value}, got {actual})"; + } + + // No unlisted DLL may sit alongside them (guards against an injected extra assembly). + foreach (var dllPath in Directory.GetFiles(codeAnalysisDir, "*.dll")) + { + var name = Path.GetFileName(dllPath); + if (!expected.ContainsKey(name)) + return $"unexpected DLL not listed in CHECKSUMS: {name}"; + } + + return null; + } + + /// SHA-256 of a file as a lowercase hex string. + /// The file to hash. + /// The lowercase hex-encoded SHA-256 hash. + public static string ComputeSha256(string filePath) + { + using (var sha = SHA256.Create()) + using (var stream = File.OpenRead(filePath)) + { + var hash = sha.ComputeHash(stream); + var sb = new StringBuilder(hash.Length * 2); + foreach (var b in hash) + sb.Append(b.ToString("x2")); + return sb.ToString(); + } + } + + // Parse " # comment" lines, skipping blanks and '#' comment lines. + private static Dictionary ParseChecksums(string checksumsPath) + { + var result = new Dictionary(StringComparer.OrdinalIgnoreCase); + + foreach (var raw in File.ReadAllLines(checksumsPath)) + { + var line = raw.Trim(); + if (line.Length == 0 || line.StartsWith("#")) + continue; + + var tokens = line.Split(new[] { ' ', '\t' }, StringSplitOptions.RemoveEmptyEntries); + if (tokens.Length < 2) + continue; + + result[tokens[1]] = tokens[0]; + } + + return result; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/BuildProcessors/PipelineRuntimeBuildProcessor.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/BuildProcessors/PipelineRuntimeBuildProcessor.cs.meta new file mode 100644 index 0000000..acd0329 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/BuildProcessors/PipelineRuntimeBuildProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 50df0b5c45692fb4a81122ca6eec4709 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/CliEditorProgress.cs b/AIClient/Packages/com.unity.pipeline/Editor/CliEditorProgress.cs new file mode 100644 index 0000000..c5c5b57 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/CliEditorProgress.cs @@ -0,0 +1,51 @@ +using UnityEditor; + +namespace Unity.Pipeline.Editor +{ + /// + /// Drop-in replacements for 's progress-bar calls that ALSO make + /// the progress visible to a connected CLI over GET /api/progress (CLI-488). + /// EditorUtility.DisplayProgressBar has no public getter and cannot be observed from + /// the pipeline server, so existing code keeps its Editor progress dialog but stays invisible + /// to the terminal. Swapping the call site to this class keeps the exact same Editor behavior + /// and adds the CLI reporting — including while the main thread is blocked inside the task, + /// which is when the dialog (and the terminal bar) matter most: + /// + /// CliEditorProgress.DisplayProgressBar("Generating World", $"Processing {i}/{n}", (float)i / n); + /// // … + /// CliEditorProgress.ClearProgressBar(); + /// + /// Code that can take a package dependency but runs headless (batchmode) can call + /// directly instead. + /// + public static class CliEditorProgress + { + /// Same as , plus CLI reporting. + /// Short title for the operation. + /// Detail text (e.g. current step). + /// Progress in [0, 1]. + public static void DisplayProgressBar(string title, string info, float progress) + { + CliProgress.Report(title, info, progress: progress); + EditorUtility.DisplayProgressBar(title, info, progress); + } + + /// Same as , plus CLI reporting. + /// Short title for the operation. + /// Detail text (e.g. current step). + /// Progress in [0, 1]. + /// True if the user clicked Cancel. + public static bool DisplayCancelableProgressBar(string title, string info, float progress) + { + CliProgress.Report(title, info, progress: progress); + return EditorUtility.DisplayCancelableProgressBar(title, info, progress); + } + + /// Same as , plus clearing the CLI report. + public static void ClearProgressBar() + { + CliProgress.Clear(); + EditorUtility.ClearProgressBar(); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/CliEditorProgress.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/CliEditorProgress.cs.meta new file mode 100644 index 0000000..46cf3e6 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/CliEditorProgress.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: bc6ed9f7b4ea400f8ed4508d6e2b761b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetVersion: 1 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands.meta new file mode 100644 index 0000000..0316bec --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e52bfc361c2ed7846a3c4c69b24828c5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation.meta new file mode 100644 index 0000000..e98352a --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 881bcacc155b44229761a2e2b2917fae +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/AnimationClipCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/AnimationClipCommands.cs new file mode 100644 index 0000000..32ede45 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/AnimationClipCommands.cs @@ -0,0 +1,427 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Editor.Commands.GameObjects; +using Unity.Pipeline.Models; +using UnityEditor; +using UnityEngine; + +namespace Unity.Pipeline.Editor.Commands.Animation +{ + /// + /// Group A of CLI-214: author assets and their float curves. + /// + /// These sit on the CLI-190 authoring foundation, so: + /// - every agent-supplied asset path is funnelled through + /// (sandboxed to the authoring root), + /// - an existing clip is addressed with an resolved by + /// and re-confined to the authoring root, + /// - destructive/overwriting operations require an explicit confirm argument and every + /// command supports dry_run. + /// + /// NOTE: AnimationClip sub-object edits (curves, clip settings) are NOT covered by Unity's Undo, + /// so changes are persisted with + + /// rather than wrapped in an . Only float curves are supported in + /// v1 (object-reference / PPtr curves are out of scope). + /// + static class AnimationClipCommands + { + [CliCommand("create_animation_clip", + "Create an empty .anim AnimationClip asset under the authoring root, with an optional frame rate and loop flag.", + MainThreadRequired = true, + Tags = new[] { "animation/clip" })] + public static AuthoringResult CreateAnimationClip( + [CliArg("path", "Asset path ending in .anim, relative to the authoring root. The Assets/ prefix is optional.", Required = true)] string path, + [CliArg("frameRate", "Sampling frame rate of the clip (default 60).")] float frameRate = 60f, + [CliArg("loop", "If true, set the clip's loop-time flag in its AnimationClipSettings (default false).")] bool loop = false, + [CliArg("confirm", "Required (true) only when overwriting an existing asset at the path.")] bool confirm = false, + [CliArg("dry_run", "If true, validate inputs and report what would be created without writing anything.")] bool dryRun = false) + { + var normalized = ProjectPaths.Resolve(path, out var error); + if (normalized == null) + throw new ArgumentException(error); + + if (!string.Equals(Path.GetExtension(normalized), ".anim", StringComparison.OrdinalIgnoreCase)) + throw new ArgumentException($"Animation clip path '{normalized}' must end in .anim."); + + if (frameRate <= 0f) + throw new ArgumentException($"frameRate must be positive (got {frameRate})."); + + var exists = AssetDatabase.LoadMainAssetAtPath(normalized) != null; + if (exists && !confirm) + throw new ArgumentException($"An asset already exists at '{normalized}'. Pass confirm=true to overwrite it."); + + if (dryRun) + return new AuthoringResult { AssetPath = normalized, Type = nameof(AnimationClip) }; + + EnsureParentFolder(normalized); + + var clip = new AnimationClip { frameRate = frameRate }; + + var settings = AnimationUtility.GetAnimationClipSettings(clip); + settings.loopTime = loop; + AnimationUtility.SetAnimationClipSettings(clip, settings); + + // CreateAsset does not reliably overwrite, so remove an existing asset first (the confirm + // guard above gates that one already exists). + if (exists) + AssetDatabase.DeleteAsset(normalized); + + AssetDatabase.CreateAsset(clip, normalized); + EditorUtility.SetDirty(clip); + AssetDatabase.SaveAssets(); + AssetDatabase.ImportAsset(normalized); + + var loaded = AssetDatabase.LoadMainAssetAtPath(normalized); + var result = ObjectResolver.Describe(loaded) ?? new AuthoringResult { Type = nameof(AnimationClip) }; + result.AssetPath = normalized; + return result; + } + + [CliCommand("set_animation_curve", + "Add or replace a single float curve binding on an AnimationClip (via AnimationUtility.SetEditorCurve). " + + "Replacing an existing binding overwrites it rather than duplicating.", + MainThreadRequired = true, + Tags = new[] { "animation/clip" })] + public static SetAnimationCurveResult SetAnimationCurve( + [CliArg("clip", "Reference to the AnimationClip to edit (path / guid / globalId).", Required = true)] ObjectRef clip, + [CliArg("path", "GameObject path relative to the animated root the property lives on. Empty string (default) targets the root.")] string path = "", + [CliArg("type", "Component type the property lives on, e.g. \"Transform\", \"UnityEngine.Light\". Resolved via the component TypeResolver.", Required = true)] string type = null, + [CliArg("property", "Curve property name, e.g. \"m_LocalPosition.x\", \"m_LocalScale.y\", \"localEulerAnglesRaw.z\".", Required = true)] string property = null, + [CliArg("keys", "Keyframes: [{ time, value, inTangent?, outTangent?, weightedMode?: \"None\"|\"In\"|\"Out\"|\"Both\" }]. Omitted tangents default to 0 (flat); this is NOT Unity's Auto tangent mode.", Required = true)] JArray keys = null, + [CliArg("dry_run", "If true, validate type/property/keys without writing the curve.")] bool dryRun = false) + { + var (clipAsset, clipPath) = ResolveClip(clip); + var componentType = ResolveCurveType(type); + if (string.IsNullOrWhiteSpace(property)) + throw new ArgumentException("property is required."); + + var bindingPath = path ?? string.Empty; + var curve = BuildCurve(keys, out var keyCount); + + var result = new SetAnimationCurveResult + { + AssetPath = clipPath, + Type = nameof(AnimationClip), + Binding = new CurveBinding { Path = bindingPath, Type = componentType.Name, Property = property }, + KeyCount = keyCount + }; + + if (dryRun) + return result; + + var binding = EditorCurveBinding.FloatCurve(bindingPath, componentType, property); + AnimationUtility.SetEditorCurve(clipAsset, binding, curve); + + EditorUtility.SetDirty(clipAsset); + AssetDatabase.SaveAssets(); + + var described = ObjectResolver.Describe(clipAsset); + if (described != null) + { + result.Guid = described.Guid; + result.FileId = described.FileId; + result.GlobalId = described.GlobalId; + } + + return result; + } + + [CliCommand("get_animation_clip", + "Read an AnimationClip's metadata and all float curve bindings (optionally with keyframes).", + MainThreadRequired = true, + Tags = new[] { "animation/clip" })] + public static AnimationClipInfo GetAnimationClip( + [CliArg("clip", "Reference to the AnimationClip to read (path / guid / globalId).", Required = true)] ObjectRef clip, + [CliArg("includeKeys", "If true, include each binding's keyframes (default false).")] bool includeKeys = false) + { + var (clipAsset, clipPath) = ResolveClip(clip); + + var settings = AnimationUtility.GetAnimationClipSettings(clipAsset); + var info = new AnimationClipInfo + { + AssetPath = clipPath, + FrameRate = clipAsset.frameRate, + Length = clipAsset.length, + Loop = settings.loopTime + }; + + foreach (var binding in AnimationUtility.GetCurveBindings(clipAsset)) + { + var curve = AnimationUtility.GetEditorCurve(clipAsset, binding); + var keyCount = curve?.length ?? 0; + + var entry = new CurveBindingInfo + { + Path = binding.path, + Type = binding.type != null ? binding.type.Name : null, + Property = binding.propertyName, + KeyCount = keyCount + }; + + if (includeKeys && curve != null) + { + entry.Keys = new List(keyCount); + foreach (var key in curve.keys) + { + entry.Keys.Add(new KeyframeInfo + { + Time = key.time, + Value = key.value, + InTangent = key.inTangent, + OutTangent = key.outTangent + }); + } + } + + info.Bindings.Add(entry); + } + + return info; + } + + [CliCommand("remove_animation_curve", + "Remove a float curve binding from an AnimationClip (SetEditorCurve(clip, binding, null)). Destructive: requires confirm=true.", + MainThreadRequired = true, + Tags = new[] { "animation/clip" })] + public static SetAnimationCurveResult RemoveAnimationCurve( + [CliArg("clip", "Reference to the AnimationClip to edit (path / guid / globalId).", Required = true)] ObjectRef clip, + [CliArg("path", "GameObject path relative to the animated root the binding lives on. Empty string (default) targets the root.")] string path = "", + [CliArg("type", "Component type of the binding to remove, e.g. \"Transform\". Resolved via the component TypeResolver.", Required = true)] string type = null, + [CliArg("property", "Curve property name to remove, e.g. \"m_LocalPosition.x\".", Required = true)] string property = null, + [CliArg("confirm", "Must be true to actually remove the binding (destructive guard).")] bool confirm = false, + [CliArg("dry_run", "If true, report the binding that would be removed without removing it.")] bool dryRun = false) + { + var (clipAsset, clipPath) = ResolveClip(clip); + var componentType = ResolveCurveType(type); + if (string.IsNullOrWhiteSpace(property)) + throw new ArgumentException("property is required."); + + var bindingPath = path ?? string.Empty; + var binding = EditorCurveBinding.FloatCurve(bindingPath, componentType, property); + var existing = AnimationUtility.GetEditorCurve(clipAsset, binding); + if (existing == null) + throw new ArgumentException( + $"No curve binding for path='{bindingPath}', type='{componentType.Name}', property='{property}' on '{clipPath}'."); + + var keyCount = existing.length; + var result = new SetAnimationCurveResult + { + AssetPath = clipPath, + Type = nameof(AnimationClip), + Binding = new CurveBinding { Path = bindingPath, Type = componentType.Name, Property = property }, + KeyCount = keyCount + }; + + if (dryRun) + return result; + + if (!confirm) + throw new ArgumentException( + $"Refusing to remove curve '{property}' from '{clipPath}'. Pass confirm=true (destructive, not undoable via Unity's Undo)."); + + AnimationUtility.SetEditorCurve(clipAsset, binding, null); + EditorUtility.SetDirty(clipAsset); + AssetDatabase.SaveAssets(); + + return result; + } + + /// + /// Resolve a clip handle to a loaded and its sandbox-confined asset + /// path, rejecting handles that don't point at an on-disk AnimationClip or that escape the root. + /// + private static (AnimationClip clip, string path) ResolveClip(ObjectRef clip) + { + if (clip == null || clip.IsEmpty) + throw new ArgumentException("clip is required."); + + if (!ObjectResolver.TryResolve(clip, out var obj, out var error)) + throw new ArgumentException(error); + + if (!(obj is AnimationClip clipAsset)) + throw new ArgumentException($"Reference '{clip}' resolved to a {obj.GetType().Name}, not an AnimationClip."); + + var assetPath = AssetDatabase.GetAssetPath(clipAsset); + if (string.IsNullOrEmpty(assetPath)) + throw new ArgumentException($"Reference '{clip}' does not point at an on-disk AnimationClip."); + + var confined = ProjectPaths.Resolve(assetPath, out var confineError); + if (confined == null) + throw new ArgumentException( + $"Clip '{assetPath}' is outside the authoring root '{ProjectPaths.AuthoringRoot}': {confineError}"); + + return (clipAsset, confined); + } + + /// + /// Resolve a curve-binding component type. Reuses the component , + /// which only accepts subclasses (curves bind to component properties). + /// + private static Type ResolveCurveType(string type) + { + if (string.IsNullOrWhiteSpace(type)) + throw new ArgumentException("type is required."); + + var resolved = TypeResolver.ResolveComponentType(type); + if (resolved == null) + throw new ArgumentException( + $"Could not resolve component type '{type}'. Use a short name (e.g. Transform) or a fully-qualified name (e.g. UnityEngine.Light)."); + + return resolved; + } + + /// Build an from the agent-supplied keyframe array. + private static AnimationCurve BuildCurve(JArray keys, out int keyCount) + { + if (keys == null || keys.Count == 0) + throw new ArgumentException("keys must be a non-empty array of { time, value, ... }."); + + var keyframes = new List(keys.Count); + foreach (var token in keys) + { + if (!(token is JObject keyObj)) + throw new ArgumentException("Each key must be an object: { time, value, inTangent?, outTangent?, weightedMode? }."); + + if (keyObj["time"] == null || keyObj["value"] == null) + throw new ArgumentException("Each key requires a 'time' and a 'value'."); + + var time = keyObj["time"].ToObject(); + var value = keyObj["value"].ToObject(); + var inTangent = keyObj["inTangent"]?.ToObject() ?? 0f; + var outTangent = keyObj["outTangent"]?.ToObject() ?? 0f; + + var keyframe = new Keyframe(time, value, inTangent, outTangent); + + var weightedToken = keyObj["weightedMode"]; + if (weightedToken != null && weightedToken.Type != JTokenType.Null) + { + var name = weightedToken.ToObject(); + if (!Enum.TryParse(name, ignoreCase: true, out var weightedMode)) + throw new ArgumentException($"Unknown weightedMode '{name}'. Use None | In | Out | Both."); + keyframe.weightedMode = weightedMode; + } + + keyframes.Add(keyframe); + } + + keyCount = keyframes.Count; + return new AnimationCurve(keyframes.ToArray()); + } + + /// Create the asset's parent folder chain if it does not yet exist. + private static void EnsureParentFolder(string assetPath) + { + var parent = Path.GetDirectoryName(assetPath)?.Replace('\\', '/'); + if (string.IsNullOrEmpty(parent) || AssetDatabase.IsValidFolder(parent)) + return; + + CreateFolderRecursive(parent); + } + + private static void CreateFolderRecursive(string assetsPath) + { + if (AssetDatabase.IsValidFolder(assetsPath)) + return; + + var parent = Path.GetDirectoryName(assetsPath)?.Replace('\\', '/'); + var name = Path.GetFileName(assetsPath); + if (string.IsNullOrEmpty(parent) || string.IsNullOrEmpty(name)) + throw new ArgumentException($"Invalid folder path '{assetsPath}'."); + + if (!AssetDatabase.IsValidFolder(parent)) + CreateFolderRecursive(parent); + + AssetDatabase.CreateFolder(parent, name); + } + } + + /// + /// Result of set_animation_curve / remove_animation_curve: the clip identity extended + /// with the affected binding and its key count. + /// + [Serializable] + class SetAnimationCurveResult : AuthoringResult + { + [JsonProperty("binding")] + public CurveBinding Binding { get; set; } + + [JsonProperty("keyCount")] + public int KeyCount { get; set; } + } + + /// A curve binding's address: GameObject path, component type, and property name. + [Serializable] + class CurveBinding + { + [JsonProperty("path")] + public string Path { get; set; } + + [JsonProperty("type")] + public string Type { get; set; } + + [JsonProperty("property")] + public string Property { get; set; } + } + + /// Result of get_animation_clip: clip metadata and its curve bindings. + [Serializable] + class AnimationClipInfo + { + [JsonProperty("assetPath")] + public string AssetPath { get; set; } + + [JsonProperty("frameRate")] + public float FrameRate { get; set; } + + [JsonProperty("length")] + public float Length { get; set; } + + [JsonProperty("loop")] + public bool Loop { get; set; } + + [JsonProperty("bindings")] + public List Bindings { get; set; } = new List(); + } + + /// A single curve binding in , optionally with its keys. + [Serializable] + class CurveBindingInfo + { + [JsonProperty("path")] + public string Path { get; set; } + + [JsonProperty("type")] + public string Type { get; set; } + + [JsonProperty("property")] + public string Property { get; set; } + + [JsonProperty("keyCount")] + public int KeyCount { get; set; } + + [JsonProperty("keys", NullValueHandling = NullValueHandling.Ignore)] + public List Keys { get; set; } + } + + /// A single keyframe in a curve binding. + [Serializable] + class KeyframeInfo + { + [JsonProperty("time")] + public float Time { get; set; } + + [JsonProperty("value")] + public float Value { get; set; } + + [JsonProperty("inTangent")] + public float InTangent { get; set; } + + [JsonProperty("outTangent")] + public float OutTangent { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/AnimationClipCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/AnimationClipCommands.cs.meta new file mode 100644 index 0000000..c5d610e --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/AnimationClipCommands.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 764503eaf79a41668748014af111eaf2 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/AnimatorControllerCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/AnimatorControllerCommands.cs new file mode 100644 index 0000000..b5c1a35 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/AnimatorControllerCommands.cs @@ -0,0 +1,891 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Models; +using UnityEditor; +using UnityEditor.Animations; +using UnityEngine; + +namespace Unity.Pipeline.Editor.Commands.Animation +{ + /// + /// Group B of CLI-214: author assets — layers, parameters, states + /// and transitions. Built on UnityEditor.Animations, which is part of the Editor (no extra + /// package), so the types are referenced directly. + /// + /// Like the animation-clip commands, paths/handles are sandbox-confined via + /// / , and every command supports + /// dry_run. Some AnimatorController API calls register Undo internally, but sub-object edits + /// are not reliably undoable, so changes are persisted with + + /// . + /// + /// Out of scope (v1): BlendTree authoring (assigning an EXISTING BlendTree as a state motion is + /// allowed), StateMachineBehaviours, sub-state machines, and humanoid/avatar configuration. + /// + static class AnimatorControllerCommands + { + [CliCommand("create_animator_controller", + "Create an .controller AnimatorController asset (with a default Base Layer) under the authoring root.", + MainThreadRequired = true, + Tags = new[] { "animation/animator" })] + public static AuthoringResult CreateAnimatorController( + [CliArg("path", "Asset path ending in .controller, relative to the authoring root. The Assets/ prefix is optional.", Required = true)] string path, + [CliArg("confirm", "Required (true) only when overwriting an existing asset at the path.")] bool confirm = false, + [CliArg("dry_run", "If true, validate inputs and report what would be created without writing anything.")] bool dryRun = false) + { + var normalized = ProjectPaths.Resolve(path, out var error); + if (normalized == null) + throw new ArgumentException(error); + + if (!string.Equals(Path.GetExtension(normalized), ".controller", StringComparison.OrdinalIgnoreCase)) + throw new ArgumentException($"Animator controller path '{normalized}' must end in .controller."); + + var exists = AssetDatabase.LoadMainAssetAtPath(normalized) != null; + if (exists && !confirm) + throw new ArgumentException($"An asset already exists at '{normalized}'. Pass confirm=true to overwrite it."); + + if (dryRun) + return new AuthoringResult { AssetPath = normalized, Type = nameof(AnimatorController) }; + + EnsureParentFolder(normalized); + + if (exists) + AssetDatabase.DeleteAsset(normalized); + + // CreateAnimatorControllerAtPath creates the asset on disk WITH a default "Base Layer". + var controller = AnimatorController.CreateAnimatorControllerAtPath(normalized); + EditorUtility.SetDirty(controller); + AssetDatabase.SaveAssets(); + + var loaded = AssetDatabase.LoadMainAssetAtPath(normalized); + var result = ObjectResolver.Describe(loaded) ?? new AuthoringResult { Type = nameof(AnimatorController) }; + result.AssetPath = normalized; + return result; + } + + [CliCommand("add_animator_parameter", + "Add a parameter (Float | Int | Bool | Trigger) to an AnimatorController. A duplicate name returns code 'duplicate_parameter'.", + MainThreadRequired = true, + Tags = new[] { "animation/animator" })] + public static object AddAnimatorParameter( + [CliArg("controller", "Reference to the AnimatorController to edit (path / guid / globalId).", Required = true)] ObjectRef controller, + [CliArg("name", "Parameter name.", Required = true)] string name, + [CliArg("type", "Parameter type: Float | Int | Bool | Trigger.", Required = true)] string type = null, + [CliArg("defaultValue", "Default value for Float/Int/Bool (ignored for Trigger).")] JToken defaultValue = null, + [CliArg("dry_run", "If true, validate inputs without writing the parameter.")] bool dryRun = false) + { + var (ctrl, ctrlPath) = ResolveController(controller); + if (string.IsNullOrWhiteSpace(name)) + throw new ArgumentException("name is required."); + + var paramType = ParseParameterType(type); + + if (ctrl.parameters.Any(p => p.name == name)) + return ErrorResult.PackageStyle("duplicate_parameter", $"A parameter named '{name}' already exists on '{ctrlPath}'."); + + // Resolve (and validate) the default value up front so dry_run also fails on a bad value. + float defFloat = 0f; + int defInt = 0; + bool defBool = false; + switch (paramType) + { + case AnimatorControllerParameterType.Float: + if (defaultValue != null && defaultValue.Type != JTokenType.Null) defFloat = defaultValue.ToObject(); + break; + case AnimatorControllerParameterType.Int: + if (defaultValue != null && defaultValue.Type != JTokenType.Null) defInt = defaultValue.ToObject(); + break; + case AnimatorControllerParameterType.Bool: + if (defaultValue != null && defaultValue.Type != JTokenType.Null) defBool = defaultValue.ToObject(); + break; + } + + var result = new AddParameterResult + { + AssetPath = ctrlPath, + Type = nameof(AnimatorController), + Parameter = new ParameterInfo + { + Name = name, + ParamType = paramType.ToString(), + DefaultValue = DefaultValueToken(paramType, defFloat, defInt, defBool) + } + }; + + if (dryRun) + return result; + + var parameter = new AnimatorControllerParameter + { + name = name, + type = paramType, + defaultFloat = defFloat, + defaultInt = defInt, + defaultBool = defBool + }; + ctrl.AddParameter(parameter); + + Persist(ctrl); + FillIdentity(result, ctrl); + return result; + } + + [CliCommand("add_animator_layer", + "Add a layer to an AnimatorController.", + MainThreadRequired = true, + Tags = new[] { "animation/animator" })] + public static object AddAnimatorLayer( + [CliArg("controller", "Reference to the AnimatorController to edit (path / guid / globalId).", Required = true)] ObjectRef controller, + [CliArg("name", "Layer name.", Required = true)] string name, + [CliArg("weight", "Layer weight (default 1).")] float weight = 1f, + [CliArg("blendingMode", "Blending mode: Override | Additive (default Override).")] string blendingMode = "Override", + [CliArg("dry_run", "If true, validate inputs without writing the layer.")] bool dryRun = false) + { + var (ctrl, ctrlPath) = ResolveController(controller); + if (string.IsNullOrWhiteSpace(name)) + throw new ArgumentException("name is required."); + + if (!Enum.TryParse(blendingMode, ignoreCase: true, out var mode)) + throw new ArgumentException($"Unknown blendingMode '{blendingMode}'. Use Override | Additive."); + + var index = ctrl.layers.Length; + var result = new AddLayerResult + { + AssetPath = ctrlPath, + Type = nameof(AnimatorController), + Layer = new LayerSummary { Name = name, Index = index, Weight = weight } + }; + + if (dryRun) + return result; + + // AddLayer(name) appends a layer with a fresh state machine. We then set its weight/blending + // by writing the layer array back (AnimatorControllerLayer is a value-like wrapper, so the + // edited copy must be reassigned). + ctrl.AddLayer(name); + var layers = ctrl.layers; + layers[index].defaultWeight = weight; + layers[index].blendingMode = mode; + ctrl.layers = layers; + + Persist(ctrl); + FillIdentity(result, ctrl); + return result; + } + + [CliCommand("add_animator_state", + "Add a state to a layer, optionally with a motion (AnimationClip or BlendTree) and as the layer default. " + + "A layer name with no match returns code 'layer_not_found'.", + MainThreadRequired = true, + Tags = new[] { "animation/animator" })] + public static object AddAnimatorState( + [CliArg("controller", "Reference to the AnimatorController to edit (path / guid / globalId).", Required = true)] ObjectRef controller, + [CliArg("layer", "Layer index (int) or name (string). Default 0 (Base Layer).")] JToken layer = null, + [CliArg("name", "State name.", Required = true)] string name = null, + [CliArg("motion", "Optional AnimationClip or BlendTree asset to assign as the state's motion.")] ObjectRef motion = null, + [CliArg("isDefault", "If true, set this state as the layer's default state.")] bool isDefault = false, + [CliArg("position", "Optional [x, y] node position in the graph (cosmetic).")] JArray position = null, + [CliArg("dry_run", "If true, validate inputs without writing the state.")] bool dryRun = false) + { + var (ctrl, ctrlPath) = ResolveController(controller); + if (string.IsNullOrWhiteSpace(name)) + throw new ArgumentException("name is required."); + + if (!TryResolveLayer(ctrl, layer, out var layerIndex, out var layerError)) + return ErrorResult.PackageStyle("layer_not_found", layerError); + + // Resolve an optional motion. Only AnimationClip / Motion (BlendTree derives from Motion) are + // valid. A handle that doesn't resolve to a Motion is a clear error. + UnityEngine.Motion resolvedMotion = null; + if (motion != null && !motion.IsEmpty) + { + if (!ObjectResolver.TryResolve(motion, out var motionObj, out var motionError)) + throw new ArgumentException($"Could not resolve motion: {motionError}"); + resolvedMotion = motionObj as UnityEngine.Motion; + if (resolvedMotion == null) + throw new ArgumentException($"Motion reference '{motion}' resolved to a {motionObj.GetType().Name}, not an AnimationClip or BlendTree."); + + // Re-confine the motion to the authoring root: a restricted root must not be bypassed by + // referencing an AnimationClip/BlendTree that lives outside the sandbox. + ConfineToAuthoringRoot(resolvedMotion, "Motion", motion); + } + + Vector3? nodePosition = null; + if (position != null && position.Count > 0) + { + if (position.Count < 2) + throw new ArgumentException("position must be [x, y]."); + nodePosition = new Vector3(position[0].ToObject(), position[1].ToObject(), 0f); + } + + var result = new AddStateResult + { + AssetPath = ctrlPath, + Type = nameof(AnimatorController), + State = new StateSummary + { + Name = name, + Layer = layerIndex, + HasMotion = resolvedMotion != null, + IsDefault = isDefault + } + }; + + if (dryRun) + return result; + + var stateMachine = ctrl.layers[layerIndex].stateMachine; + var state = nodePosition.HasValue + ? stateMachine.AddState(name, nodePosition.Value) + : stateMachine.AddState(name); + + if (resolvedMotion != null) + state.motion = resolvedMotion; + + if (isDefault) + stateMachine.defaultState = state; + + Persist(ctrl); + FillIdentity(result, ctrl); + return result; + } + + [CliCommand("add_animator_transition", + "Add a transition between two states (or from AnyState/Entry, to Exit) on a layer, with optional conditions. " + + "Validates that the states exist and each condition's parameter exists and its mode matches the parameter type.", + MainThreadRequired = true, + Tags = new[] { "animation/animator" })] + public static object AddAnimatorTransition( + [CliArg("controller", "Reference to the AnimatorController to edit (path / guid / globalId).", Required = true)] ObjectRef controller, + [CliArg("layer", "Layer index (int) or name (string). Default 0 (Base Layer).")] JToken layer = null, + [CliArg("fromState", "Source state name, or the special \"AnyState\" / \"Entry\".", Required = true)] string fromState = null, + [CliArg("toState", "Destination state name, or the special \"Exit\".", Required = true)] string toState = null, + [CliArg("conditions", "Optional conditions: [{ parameter, mode: \"If\"|\"IfNot\"|\"Greater\"|\"Less\"|\"Equals\"|\"NotEqual\", threshold? }].")] JArray conditions = null, + [CliArg("hasExitTime", "If true, the transition uses exit time (default false).")] bool hasExitTime = false, + [CliArg("exitTime", "Normalized exit time (0..1) when hasExitTime is set.")] float exitTime = 0f, + [CliArg("duration", "Transition duration in seconds (default 0.25).")] float duration = 0.25f, + [CliArg("hasFixedDuration", "If true, duration is in seconds; otherwise normalized (default true).")] bool hasFixedDuration = true, + [CliArg("dry_run", "If true, validate everything (states, parameters, mode/type) without writing the transition.")] bool dryRun = false) + { + var (ctrl, ctrlPath) = ResolveController(controller); + if (string.IsNullOrWhiteSpace(fromState)) + throw new ArgumentException("fromState is required."); + if (string.IsNullOrWhiteSpace(toState)) + throw new ArgumentException("toState is required."); + + // exitTime is normalized (0..1) and only meaningful with hasExitTime; duration must be + // non-negative. Reject out-of-range values up front (writing nothing) rather than letting + // Unity clamp them unpredictably. + if (hasExitTime && (exitTime < 0f || exitTime > 1f)) + throw new ArgumentException($"exitTime must be in [0, 1] when hasExitTime is set (got {exitTime})."); + if (duration < 0f) + throw new ArgumentException($"duration must be >= 0 (got {duration})."); + + if (!TryResolveLayer(ctrl, layer, out var layerIndex, out var layerError)) + return ErrorResult.PackageStyle("layer_not_found", layerError); + + var stateMachine = ctrl.layers[layerIndex].stateMachine; + + const string AnyState = "AnyState"; + const string Entry = "Entry"; + const string Exit = "Exit"; + + var fromIsAny = string.Equals(fromState, AnyState, StringComparison.OrdinalIgnoreCase); + var fromIsEntry = string.Equals(fromState, Entry, StringComparison.OrdinalIgnoreCase); + var toIsExit = string.Equals(toState, Exit, StringComparison.OrdinalIgnoreCase); + + // Resolve the source state (unless it's AnyState/Entry, which are nodes on the machine). + AnimatorState fromAnimState = null; + if (!fromIsAny && !fromIsEntry) + { + fromAnimState = FindState(stateMachine, fromState); + if (fromAnimState == null) + throw new ArgumentException($"Source state '{fromState}' not found in layer {layerIndex}."); + } + + // Resolve the destination state (unless it's Exit). + AnimatorState toAnimState = null; + if (!toIsExit) + { + toAnimState = FindState(stateMachine, toState); + if (toAnimState == null) + throw new ArgumentException($"Destination state '{toState}' not found in layer {layerIndex}."); + } + + // Entry transitions cannot carry conditions/exit-time the same way; restrict combinations the + // engine forbids so an agent gets a clear error rather than a malformed transition. + if (fromIsEntry && toIsExit) + throw new ArgumentException("A transition from Entry directly to Exit is not supported."); + + // Validate conditions BEFORE creating anything (so a bad condition writes nothing). + var parsedConditions = ParseConditions(conditions, ctrl); + + var result = new AddTransitionResult + { + AssetPath = ctrlPath, + Type = nameof(AnimatorController), + Transition = new TransitionSummary + { + From = fromState, + To = toState, + ConditionCount = parsedConditions.Count + } + }; + + if (dryRun) + return result; + + // Create the transition node matching the from/to kinds. + AnimatorStateTransition stateTransition = null; + AnimatorTransition entryTransition = null; + + if (fromIsEntry) + { + // Entry -> state. Entry transitions are plain AnimatorTransition (no exit time/duration). + entryTransition = stateMachine.AddEntryTransition(toAnimState); + } + else if (fromIsAny) + { + stateTransition = toIsExit ? null : stateMachine.AddAnyStateTransition(toAnimState); + if (stateTransition == null) + throw new ArgumentException("An AnyState transition to Exit is not supported."); + } + else + { + stateTransition = toIsExit + ? fromAnimState.AddExitTransition() + : fromAnimState.AddTransition(toAnimState); + } + + if (stateTransition != null) + { + stateTransition.hasExitTime = hasExitTime; + stateTransition.exitTime = exitTime; + stateTransition.hasFixedDuration = hasFixedDuration; + stateTransition.duration = duration; + foreach (var c in parsedConditions) + stateTransition.AddCondition(c.Mode, c.Threshold, c.Parameter); + } + else if (entryTransition != null) + { + foreach (var c in parsedConditions) + entryTransition.AddCondition(c.Mode, c.Threshold, c.Parameter); + } + + Persist(ctrl); + FillIdentity(result, ctrl); + return result; + } + + [CliCommand("get_animator_controller", + "Read an AnimatorController's full structure: parameters, layers, states (with motion / default), and transitions (with conditions).", + MainThreadRequired = true, + Tags = new[] { "animation/animator" })] + public static AnimatorControllerInfo GetAnimatorController( + [CliArg("controller", "Reference to the AnimatorController to read (path / guid / globalId).", Required = true)] ObjectRef controller) + { + var (ctrl, ctrlPath) = ResolveController(controller); + + var info = new AnimatorControllerInfo { AssetPath = ctrlPath }; + + foreach (var p in ctrl.parameters) + { + info.Parameters.Add(new ParameterInfo + { + Name = p.name, + ParamType = p.type.ToString(), + DefaultValue = DefaultValueToken(p.type, p.defaultFloat, p.defaultInt, p.defaultBool) + }); + } + + for (int i = 0; i < ctrl.layers.Length; i++) + { + var layer = ctrl.layers[i]; + var sm = layer.stateMachine; + + var layerInfo = new LayerInfo + { + Name = layer.name, + Index = i, + DefaultState = sm != null && sm.defaultState != null ? sm.defaultState.name : null + }; + + if (sm != null) + { + foreach (var childState in sm.states) + { + var state = childState.state; + layerInfo.States.Add(new StateInfo + { + Name = state.name, + Motion = state.motion != null ? state.motion.name : null, + IsDefault = sm.defaultState == state + }); + + foreach (var t in state.transitions) + layerInfo.Transitions.Add(DescribeTransition(state.name, t)); + } + + foreach (var t in sm.anyStateTransitions) + layerInfo.Transitions.Add(DescribeTransition("AnyState", t)); + } + + info.Layers.Add(layerInfo); + } + + return info; + } + + // ---- helpers ---- + + private static TransitionInfo DescribeTransition(string from, AnimatorStateTransition t) + { + var to = t.isExit ? "Exit" : (t.destinationState != null ? t.destinationState.name : null); + var ti = new TransitionInfo + { + From = from, + To = to, + HasExitTime = t.hasExitTime, + Duration = t.duration + }; + foreach (var c in t.conditions) + { + ti.Conditions.Add(new ConditionInfo + { + Parameter = c.parameter, + Mode = c.mode.ToString(), + Threshold = c.threshold + }); + } + return ti; + } + + private static AnimatorState FindState(AnimatorStateMachine sm, string name) + { + if (sm == null) + return null; + foreach (var childState in sm.states) + { + if (childState.state != null && childState.state.name == name) + return childState.state; + } + return null; + } + + private struct ParsedCondition + { + public string Parameter; + public AnimatorConditionMode Mode; + public float Threshold; + } + + /// + /// Parse and validate the conditions array against the controller's parameters: each parameter + /// must exist and its type must be compatible with the condition mode (If/IfNot for Bool/Trigger; + /// numeric Greater/Less/Equals/NotEqual for Float/Int). Throws (writing nothing) on any mismatch. + /// + private static List ParseConditions(JArray conditions, AnimatorController ctrl) + { + var parsed = new List(); + if (conditions == null) + return parsed; + + foreach (var token in conditions) + { + if (!(token is JObject obj)) + throw new ArgumentException("Each condition must be an object: { parameter, mode, threshold? }."); + + var parameterName = obj["parameter"]?.ToObject(); + var modeName = obj["mode"]?.ToObject(); + if (string.IsNullOrWhiteSpace(parameterName)) + throw new ArgumentException("Each condition requires a 'parameter'."); + if (string.IsNullOrWhiteSpace(modeName)) + throw new ArgumentException($"Condition for parameter '{parameterName}' requires a 'mode'."); + + var param = ctrl.parameters.FirstOrDefault(p => p.name == parameterName); + if (param == null) + throw new ArgumentException($"Condition references parameter '{parameterName}', which does not exist on the controller."); + + if (!Enum.TryParse(modeName, ignoreCase: true, out var mode)) + throw new ArgumentException($"Unknown condition mode '{modeName}' for parameter '{parameterName}'. Use If | IfNot | Greater | Less | Equals | NotEqual."); + + ValidateModeForType(parameterName, param.type, mode); + + var threshold = obj["threshold"]?.ToObject() ?? 0f; + + parsed.Add(new ParsedCondition { Parameter = parameterName, Mode = mode, Threshold = threshold }); + } + + return parsed; + } + + /// + /// Enforce that a condition mode matches its parameter type: Bool/Trigger only accept If/IfNot; + /// Float/Int only accept the numeric modes (Greater/Less/Equals/NotEqual). Unity's editor follows + /// the same rule; we reject mismatches up front with an actionable message. + /// + private static void ValidateModeForType(string parameterName, AnimatorControllerParameterType type, AnimatorConditionMode mode) + { + var isBoolLike = type == AnimatorControllerParameterType.Bool || type == AnimatorControllerParameterType.Trigger; + var isNumeric = type == AnimatorControllerParameterType.Float || type == AnimatorControllerParameterType.Int; + + var boolMode = mode == AnimatorConditionMode.If || mode == AnimatorConditionMode.IfNot; + + if (isBoolLike && !boolMode) + throw new ArgumentException( + $"Condition mode '{mode}' is not valid for {type} parameter '{parameterName}'. Bool/Trigger parameters use If or IfNot."); + + if (isNumeric && boolMode) + throw new ArgumentException( + $"Condition mode '{mode}' is not valid for {type} parameter '{parameterName}'. Float/Int parameters use Greater, Less, Equals or NotEqual."); + } + + private static AnimatorControllerParameterType ParseParameterType(string type) + { + if (string.IsNullOrWhiteSpace(type)) + throw new ArgumentException("type is required."); + if (!Enum.TryParse(type, ignoreCase: true, out var parsed)) + throw new ArgumentException($"Unknown parameter type '{type}'. Use Float | Int | Bool | Trigger."); + return parsed; + } + + private static JToken DefaultValueToken(AnimatorControllerParameterType type, float f, int i, bool b) + { + switch (type) + { + case AnimatorControllerParameterType.Float: return new JValue(f); + case AnimatorControllerParameterType.Int: return new JValue(i); + case AnimatorControllerParameterType.Bool: return new JValue(b); + default: return JValue.CreateNull(); // Trigger has no default value + } + } + + /// + /// Resolve a layer selector (int index or string name; null/absent => 0). Returns false with an + /// error when a name doesn't match any layer (the caller surfaces 'layer_not_found'). + /// + private static bool TryResolveLayer(AnimatorController ctrl, JToken layer, out int index, out string error) + { + index = 0; + error = null; + + if (layer == null || layer.Type == JTokenType.Null) + return true; // default Base Layer + + if (layer.Type == JTokenType.Integer || layer.Type == JTokenType.Float) + { + // The layer index is an int. A float is accepted only when it is integer-valued + // (e.g. 1.0); a fractional value like 0.9 is rejected rather than silently rounded. + if (layer.Type == JTokenType.Float) + { + var asDouble = layer.ToObject(); + if (asDouble != Math.Floor(asDouble)) + { + error = $"Layer index must be an integer; got {asDouble}."; + return false; + } + index = (int)asDouble; + } + else + { + index = layer.ToObject(); + } + + if (index < 0 || index >= ctrl.layers.Length) + { + error = $"Layer index {index} is out of range (controller has {ctrl.layers.Length} layer(s))."; + return false; + } + return true; + } + + var name = layer.ToObject(); + if (string.IsNullOrWhiteSpace(name)) + return true; + + // A numeric string is treated as an index. + if (int.TryParse(name, out var asIndex)) + { + if (asIndex < 0 || asIndex >= ctrl.layers.Length) + { + error = $"Layer index {asIndex} is out of range (controller has {ctrl.layers.Length} layer(s))."; + return false; + } + index = asIndex; + return true; + } + + for (int i = 0; i < ctrl.layers.Length; i++) + { + if (ctrl.layers[i].name == name) + { + index = i; + return true; + } + } + + error = $"No layer named '{name}' on the controller. Add it first with add_animator_layer."; + return false; + } + + /// + /// Reject an on-disk asset reference that resolves outside the authoring root. Mirrors the + /// confinement applied to the controller itself so a restricted root can't be sidestepped by + /// pointing at (e.g.) an AnimationClip/BlendTree elsewhere in the project. + /// + private static void ConfineToAuthoringRoot(UnityEngine.Object asset, string label, ObjectRef reference) + { + var assetPath = AssetDatabase.GetAssetPath(asset); + if (string.IsNullOrEmpty(assetPath)) + throw new ArgumentException($"{label} reference '{reference}' does not point at an on-disk asset."); + + var confined = ProjectPaths.Resolve(assetPath, out var confineError); + if (confined == null) + throw new ArgumentException( + $"{label} '{assetPath}' is outside the authoring root '{ProjectPaths.AuthoringRoot}': {confineError}"); + } + + private static (AnimatorController controller, string path) ResolveController(ObjectRef controller) + { + if (controller == null || controller.IsEmpty) + throw new ArgumentException("controller is required."); + + if (!ObjectResolver.TryResolve(controller, out var obj, out var error)) + throw new ArgumentException(error); + + if (!(obj is AnimatorController ctrl)) + throw new ArgumentException($"Reference '{controller}' resolved to a {obj.GetType().Name}, not an AnimatorController."); + + var assetPath = AssetDatabase.GetAssetPath(ctrl); + if (string.IsNullOrEmpty(assetPath)) + throw new ArgumentException($"Reference '{controller}' does not point at an on-disk AnimatorController."); + + var confined = ProjectPaths.Resolve(assetPath, out var confineError); + if (confined == null) + throw new ArgumentException( + $"Controller '{assetPath}' is outside the authoring root '{ProjectPaths.AuthoringRoot}': {confineError}"); + + return (ctrl, confined); + } + + private static void Persist(AnimatorController ctrl) + { + EditorUtility.SetDirty(ctrl); + AssetDatabase.SaveAssets(); + } + + private static void FillIdentity(AuthoringResult result, AnimatorController ctrl) + { + var described = ObjectResolver.Describe(ctrl); + if (described == null) + return; + result.Guid = described.Guid; + result.FileId = described.FileId; + result.GlobalId = described.GlobalId; + } + + private static void EnsureParentFolder(string assetPath) + { + var parent = Path.GetDirectoryName(assetPath)?.Replace('\\', '/'); + if (string.IsNullOrEmpty(parent) || AssetDatabase.IsValidFolder(parent)) + return; + CreateFolderRecursive(parent); + } + + private static void CreateFolderRecursive(string assetsPath) + { + if (AssetDatabase.IsValidFolder(assetsPath)) + return; + + var parent = Path.GetDirectoryName(assetsPath)?.Replace('\\', '/'); + var name = Path.GetFileName(assetsPath); + if (string.IsNullOrEmpty(parent) || string.IsNullOrEmpty(name)) + throw new ArgumentException($"Invalid folder path '{assetsPath}'."); + + if (!AssetDatabase.IsValidFolder(parent)) + CreateFolderRecursive(parent); + + AssetDatabase.CreateFolder(parent, name); + } + } + + // ---- result models ---- + + /// A structured, non-throwing error envelope ({ error, code }) returned at HTTP 200. + [Serializable] + class ErrorResult + { + [JsonProperty("error")] + public string Error { get; set; } + + [JsonProperty("code")] + public string Code { get; set; } + + public static ErrorResult PackageStyle(string code, string error) => new ErrorResult { Code = code, Error = error }; + } + + [Serializable] + class ParameterInfo + { + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("type")] + public string ParamType { get; set; } + + [JsonProperty("defaultValue")] + public JToken DefaultValue { get; set; } + } + + [Serializable] + class AddParameterResult : AuthoringResult + { + [JsonProperty("parameter")] + public ParameterInfo Parameter { get; set; } + } + + [Serializable] + class LayerSummary + { + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("index")] + public int Index { get; set; } + + [JsonProperty("weight")] + public float Weight { get; set; } + } + + [Serializable] + class AddLayerResult : AuthoringResult + { + [JsonProperty("layer")] + public LayerSummary Layer { get; set; } + } + + [Serializable] + class StateSummary + { + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("layer")] + public int Layer { get; set; } + + [JsonProperty("hasMotion")] + public bool HasMotion { get; set; } + + [JsonProperty("isDefault")] + public bool IsDefault { get; set; } + } + + [Serializable] + class AddStateResult : AuthoringResult + { + [JsonProperty("state")] + public StateSummary State { get; set; } + } + + [Serializable] + class TransitionSummary + { + [JsonProperty("from")] + public string From { get; set; } + + [JsonProperty("to")] + public string To { get; set; } + + [JsonProperty("conditionCount")] + public int ConditionCount { get; set; } + } + + [Serializable] + class AddTransitionResult : AuthoringResult + { + [JsonProperty("transition")] + public TransitionSummary Transition { get; set; } + } + + [Serializable] + class AnimatorControllerInfo + { + [JsonProperty("assetPath")] + public string AssetPath { get; set; } + + [JsonProperty("parameters")] + public List Parameters { get; set; } = new List(); + + [JsonProperty("layers")] + public List Layers { get; set; } = new List(); + } + + [Serializable] + class LayerInfo + { + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("index")] + public int Index { get; set; } + + [JsonProperty("defaultState")] + public string DefaultState { get; set; } + + [JsonProperty("states")] + public List States { get; set; } = new List(); + + [JsonProperty("transitions")] + public List Transitions { get; set; } = new List(); + } + + [Serializable] + class StateInfo + { + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("motion")] + public string Motion { get; set; } + + [JsonProperty("isDefault")] + public bool IsDefault { get; set; } + } + + [Serializable] + class TransitionInfo + { + [JsonProperty("from")] + public string From { get; set; } + + [JsonProperty("to")] + public string To { get; set; } + + [JsonProperty("conditions")] + public List Conditions { get; set; } = new List(); + + [JsonProperty("hasExitTime")] + public bool HasExitTime { get; set; } + + [JsonProperty("duration")] + public float Duration { get; set; } + } + + [Serializable] + class ConditionInfo + { + [JsonProperty("parameter")] + public string Parameter { get; set; } + + [JsonProperty("mode")] + public string Mode { get; set; } + + [JsonProperty("threshold")] + public float Threshold { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/AnimatorControllerCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/AnimatorControllerCommands.cs.meta new file mode 100644 index 0000000..403e749 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/AnimatorControllerCommands.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 426c006ffb43461e94ab3dde2caed7be diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/TimelineCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/TimelineCommands.cs new file mode 100644 index 0000000..ba4d9f3 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/TimelineCommands.cs @@ -0,0 +1,641 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using Newtonsoft.Json; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Models; +using UnityEditor; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace Unity.Pipeline.Editor.Commands.Animation +{ + /// + /// Group C of CLI-214: author TimelineAssets (tracks + clips). Timeline ships in the OPTIONAL + /// com.unity.timeline package, so the Editor assembly does NOT reference Unity.Timeline + /// (that would break compilation when the package is absent). Every command: + /// + /// 1. runs ; if Timeline is absent it returns a structured + /// { error, code: "package_not_found" } at HTTP 200 (no exception thrown), and + /// 2. reaches the Timeline API entirely through reflection. + /// + /// Type names used (all in Unity.Timeline): UnityEngine.Timeline.TimelineAsset, + /// TrackAsset, TimelineClip, and the concrete track types + /// (AnimationTrack, AudioTrack, ActivationTrack, ControlTrack, + /// PlayableTrack, SignalTrack, MarkerTrack). + /// + /// Out of scope (v1): markers, signal emitters/receivers, custom playable tracks, and track bindings + /// to scene objects. + /// + static class TimelineCommands + { + private const string Asm = "Unity.Timeline"; + + // Friendly track-type name => concrete TrackAsset subclass full name. + private static readonly Dictionary TrackTypeNames = new Dictionary(StringComparer.OrdinalIgnoreCase) + { + { "Animation", "UnityEngine.Timeline.AnimationTrack" }, + { "Audio", "UnityEngine.Timeline.AudioTrack" }, + { "Activation", "UnityEngine.Timeline.ActivationTrack" }, + { "Control", "UnityEngine.Timeline.ControlTrack" }, + { "Playable", "UnityEngine.Timeline.PlayableTrack" }, + { "Signal", "UnityEngine.Timeline.SignalTrack" }, + { "Marker", "UnityEngine.Timeline.MarkerTrack" }, + }; + + [CliCommand("create_timeline", + "Create a .playable TimelineAsset under the authoring root (optional frame rate). Requires the com.unity.timeline package.", + MainThreadRequired = true, + Tags = new[] { "animation/timeline" })] + public static object CreateTimeline( + [CliArg("path", "Asset path ending in .playable, relative to the authoring root. The Assets/ prefix is optional.", Required = true)] string path, + [CliArg("frameRate", "Timeline frame rate (default 60).")] float frameRate = 60f, + [CliArg("confirm", "Required (true) only when overwriting an existing asset at the path.")] bool confirm = false, + [CliArg("dry_run", "If true, validate inputs and report what would be created without writing anything.")] bool dryRun = false) + { + if (!TimelineGuard.IsInstalled()) + return TimelineGuard.NotInstalledError(); + + var normalized = ProjectPaths.Resolve(path, out var error); + if (normalized == null) + throw new ArgumentException(error); + + if (!string.Equals(Path.GetExtension(normalized), ".playable", StringComparison.OrdinalIgnoreCase)) + throw new ArgumentException($"Timeline path '{normalized}' must end in .playable."); + + if (frameRate <= 0f) + throw new ArgumentException($"frameRate must be positive (got {frameRate})."); + + var exists = AssetDatabase.LoadMainAssetAtPath(normalized) != null; + if (exists && !confirm) + throw new ArgumentException($"An asset already exists at '{normalized}'. Pass confirm=true to overwrite it."); + + if (dryRun) + return new AuthoringResult { AssetPath = normalized, Type = "TimelineAsset" }; + + EnsureParentFolder(normalized); + + var timelineType = TimelineGuard.ResolveTimelineAssetType(); + var timeline = ScriptableObject.CreateInstance(timelineType); + SetFrameRate(timeline, timelineType, frameRate); + + if (exists) + AssetDatabase.DeleteAsset(normalized); + + AssetDatabase.CreateAsset(timeline, normalized); + EditorUtility.SetDirty(timeline); + AssetDatabase.SaveAssets(); + AssetDatabase.ImportAsset(normalized); + + var loaded = AssetDatabase.LoadMainAssetAtPath(normalized); + var result = ObjectResolver.Describe(loaded) ?? new AuthoringResult { Type = "TimelineAsset" }; + result.AssetPath = normalized; + return result; + } + + [CliCommand("add_timeline_track", + "Add a track (Animation | Audio | Activation | Control | Playable | Signal | Marker) to a TimelineAsset, optionally nested under a parent group/track. Requires the com.unity.timeline package.", + MainThreadRequired = true, + Tags = new[] { "animation/timeline" })] + public static object AddTimelineTrack( + [CliArg("timeline", "Reference to the TimelineAsset to edit (path / guid / globalId).", Required = true)] ObjectRef timeline, + [CliArg("trackType", "Track type: Animation | Audio | Activation | Control | Playable | Signal | Marker.", Required = true)] string trackType = null, + [CliArg("name", "Optional track display name.")] string name = null, + [CliArg("parentTrack", "Optional name of an existing group/track to nest the new track under.")] string parentTrack = null, + [CliArg("dry_run", "If true, validate inputs without writing the track.")] bool dryRun = false) + { + if (!TimelineGuard.IsInstalled()) + return TimelineGuard.NotInstalledError(); + + var (asset, assetPath, timelineType) = ResolveTimeline(timeline); + + if (string.IsNullOrWhiteSpace(trackType) || !TrackTypeNames.TryGetValue(trackType, out var trackTypeFullName)) + throw new ArgumentException($"Unknown trackType '{trackType}'. Use Animation | Audio | Activation | Control | Playable | Signal | Marker."); + + var concreteTrackType = Type.GetType($"{trackTypeFullName}, {Asm}", throwOnError: false); + if (concreteTrackType == null) + throw new ArgumentException($"Track type '{trackTypeFullName}' is not available in this version of {TimelineGuard.PackageId}."); + + var trackName = string.IsNullOrEmpty(name) ? trackType : name; + + // Resolve an optional parent track by name BEFORE any write so a bad parent fails clean. + object parent = null; + if (!string.IsNullOrEmpty(parentTrack)) + { + parent = FindTrackByName(asset, timelineType, parentTrack); + if (parent == null) + throw new ArgumentException($"Parent track '{parentTrack}' not found on the timeline."); + } + + var result = new AddTimelineTrackResult + { + AssetPath = assetPath, + Type = "TimelineAsset", + Track = new TimelineTrackSummary { Name = trackName, TrackType = trackType } + }; + + if (dryRun) + return result; + + // TrackAsset CreateTrack(Type type, TrackAsset parent, string name) + var createTrack = timelineType.GetMethod("CreateTrack", new[] { typeof(Type), GetTrackAssetType(), typeof(string) }); + if (createTrack == null) + throw new InvalidOperationException("TimelineAsset.CreateTrack(Type, TrackAsset, string) not found via reflection."); + + createTrack.Invoke(asset, new object[] { concreteTrackType, parent, trackName }); + + EditorUtility.SetDirty(asset); + AssetDatabase.SaveAssets(); + + FillIdentity(result, asset); + return result; + } + + [CliCommand("add_timeline_clip", + "Add a clip to a named track on a TimelineAsset. For Animation tracks pass an AnimationClip asset; for Audio tracks an AudioClip. Requires the com.unity.timeline package.", + MainThreadRequired = true, + Tags = new[] { "animation/timeline" })] + public static object AddTimelineClip( + [CliArg("timeline", "Reference to the TimelineAsset to edit (path / guid / globalId).", Required = true)] ObjectRef timeline, + [CliArg("track", "Target track name.", Required = true)] string track = null, + [CliArg("start", "Clip start time in seconds.", Required = true)] float start = 0f, + [CliArg("duration", "Clip duration in seconds.", Required = true)] float duration = 0f, + [CliArg("asset", "Source asset: for Animation tracks an AnimationClip; for Audio tracks an AudioClip. Required for those track types.")] ObjectRef asset = null, + [CliArg("dry_run", "If true, validate inputs without writing the clip.")] bool dryRun = false) + { + if (!TimelineGuard.IsInstalled()) + return TimelineGuard.NotInstalledError(); + + var (timelineAsset, assetPath, timelineType) = ResolveTimeline(timeline); + + if (string.IsNullOrWhiteSpace(track)) + throw new ArgumentException("track is required."); + if (duration <= 0f) + throw new ArgumentException($"duration must be positive (got {duration})."); + if (start < 0f) + throw new ArgumentException($"start must be >= 0 (got {start})."); + + var trackObj = FindTrackByName(timelineAsset, timelineType, track); + if (trackObj == null) + throw new ArgumentException($"Track '{track}' not found on the timeline."); + + // Resolve the optional clip-source asset BEFORE any write. + Object sourceAsset = null; + if (asset != null && !asset.IsEmpty) + { + if (!ObjectResolver.TryResolve(asset, out var srcObj, out var srcError)) + throw new ArgumentException($"Could not resolve clip asset: {srcError}"); + sourceAsset = srcObj; + + // Re-confine the clip source to the authoring root: a restricted root must not be + // bypassed by referencing an AnimationClip/AudioClip that lives outside the sandbox. + var sourcePath = AssetDatabase.GetAssetPath(sourceAsset); + if (string.IsNullOrEmpty(sourcePath)) + throw new ArgumentException($"Clip asset reference '{asset}' does not point at an on-disk asset."); + + var confinedSource = ProjectPaths.Resolve(sourcePath, out var sourceConfineError); + if (confinedSource == null) + throw new ArgumentException( + $"Clip asset '{sourcePath}' is outside the authoring root '{ProjectPaths.AuthoringRoot}': {sourceConfineError}"); + } + + var result = new AddTimelineClipResult + { + AssetPath = assetPath, + Type = "TimelineAsset", + Clip = new TimelineClipSummary { Track = track, Start = start, Duration = duration } + }; + + if (dryRun) + { + // Even in dry_run, validate that a clip can be created for this track/asset combination so + // a missing-required-asset case fails fast and writes nothing. + ValidateClipCreatable(trackObj, sourceAsset); + return result; + } + + var clip = CreateClip(trackObj, sourceAsset); + if (clip == null) + throw new InvalidOperationException($"Failed to create a clip on track '{track}'."); + + SetClipTiming(clip, start, duration); + + EditorUtility.SetDirty(timelineAsset); + AssetDatabase.SaveAssets(); + + FillIdentity(result, timelineAsset); + return result; + } + + [CliCommand("get_timeline", + "Read a TimelineAsset's structure: frame rate, duration, and its tracks with their clips. Requires the com.unity.timeline package.", + MainThreadRequired = true, + Tags = new[] { "animation/timeline" })] + public static object GetTimeline( + [CliArg("timeline", "Reference to the TimelineAsset to read (path / guid / globalId).", Required = true)] ObjectRef timeline) + { + if (!TimelineGuard.IsInstalled()) + return TimelineGuard.NotInstalledError(); + + var (asset, assetPath, timelineType) = ResolveTimeline(timeline); + + var info = new TimelineInfo + { + AssetPath = assetPath, + FrameRate = GetFrameRate(asset, timelineType), + Duration = GetDouble(asset, timelineType, "duration") + }; + + foreach (var trackObj in GetOutputTracks(asset, timelineType)) + { + if (trackObj == null) + continue; + + var trackType = trackObj.GetType(); + var trackInfo = new TimelineTrackInfo + { + Name = GetName(trackObj), + TrackType = FriendlyTrackType(trackType) + }; + + foreach (var clipObj in GetClips(trackObj)) + { + if (clipObj == null) + continue; + var clipType = clipObj.GetType(); + var clipAsset = GetMember(clipObj, clipType, "asset") as Object; + trackInfo.Clips.Add(new TimelineClipInfo + { + Start = GetDoubleMember(clipObj, clipType, "start"), + Duration = GetDoubleMember(clipObj, clipType, "duration"), + Asset = clipAsset != null ? AssetDatabase.GetAssetPath(clipAsset) : null + }); + } + + info.Tracks.Add(trackInfo); + } + + return info; + } + + // ---- reflection helpers ---- + + private static Type GetTrackAssetType() + { + var t = Type.GetType($"UnityEngine.Timeline.TrackAsset, {Asm}", throwOnError: false); + if (t == null) + throw new InvalidOperationException("UnityEngine.Timeline.TrackAsset type not found."); + return t; + } + + private static (Object asset, string path, Type timelineType) ResolveTimeline(ObjectRef timeline) + { + if (timeline == null || timeline.IsEmpty) + throw new ArgumentException("timeline is required."); + + if (!ObjectResolver.TryResolve(timeline, out var obj, out var error)) + throw new ArgumentException(error); + + var timelineType = TimelineGuard.ResolveTimelineAssetType(); + if (timelineType == null || !timelineType.IsInstanceOfType(obj)) + throw new ArgumentException($"Reference '{timeline}' resolved to a {obj.GetType().Name}, not a TimelineAsset."); + + var assetPath = AssetDatabase.GetAssetPath(obj); + if (string.IsNullOrEmpty(assetPath)) + throw new ArgumentException($"Reference '{timeline}' does not point at an on-disk TimelineAsset."); + + var confined = ProjectPaths.Resolve(assetPath, out var confineError); + if (confined == null) + throw new ArgumentException( + $"Timeline '{assetPath}' is outside the authoring root '{ProjectPaths.AuthoringRoot}': {confineError}"); + + return (obj, confined, timelineType); + } + + /// + /// Set the timeline frame rate, preferring the current editorSettings.frameRate (double) + /// and falling back to the obsolete editorSettings.fps (float) on older package versions. + /// + private static void SetFrameRate(object timeline, Type timelineType, float frameRate) + { + var editorSettings = GetMember(timeline, timelineType, "editorSettings"); + if (editorSettings == null) + return; + + var settingsType = editorSettings.GetType(); + + var frameRateProp = settingsType.GetProperty("frameRate", BindingFlags.Public | BindingFlags.Instance); + if (frameRateProp != null && frameRateProp.CanWrite) + { + frameRateProp.SetValue(editorSettings, (double)frameRate); + return; + } + + var fpsProp = settingsType.GetProperty("fps", BindingFlags.Public | BindingFlags.Instance); + if (fpsProp != null && fpsProp.CanWrite) + fpsProp.SetValue(editorSettings, frameRate); + } + + private static double GetFrameRate(object timeline, Type timelineType) + { + var editorSettings = GetMember(timeline, timelineType, "editorSettings"); + if (editorSettings == null) + return 0d; + + var settingsType = editorSettings.GetType(); + + var frameRateProp = settingsType.GetProperty("frameRate", BindingFlags.Public | BindingFlags.Instance); + if (frameRateProp != null && frameRateProp.CanRead) + return Convert.ToDouble(frameRateProp.GetValue(editorSettings)); + + var fpsProp = settingsType.GetProperty("fps", BindingFlags.Public | BindingFlags.Instance); + if (fpsProp != null && fpsProp.CanRead) + return Convert.ToDouble(fpsProp.GetValue(editorSettings)); + + return 0d; + } + + private static IEnumerable GetOutputTracks(object timeline, Type timelineType) + { + var method = timelineType.GetMethod("GetOutputTracks", Type.EmptyTypes); + if (method == null) + yield break; + + var enumerable = method.Invoke(timeline, null) as IEnumerable; + if (enumerable == null) + yield break; + + foreach (var item in enumerable) + yield return item; + } + + private static object FindTrackByName(object timeline, Type timelineType, string name) + { + foreach (var track in GetOutputTracks(timeline, timelineType)) + { + if (track != null && GetName(track) == name) + return track; + } + return null; + } + + private static IEnumerable GetClips(object track) + { + var method = track.GetType().GetMethod("GetClips", Type.EmptyTypes); + if (method == null) + yield break; + + var enumerable = method.Invoke(track, null) as IEnumerable; + if (enumerable == null) + yield break; + + foreach (var item in enumerable) + yield return item; + } + + /// + /// Find a CreateClip overload on the track that accepts the given source asset's type + /// (e.g. AnimationTrack.CreateClip(AnimationClip), AudioTrack.CreateClip(AudioClip)). Returns + /// null when no asset is given (caller then uses CreateDefaultClip). + /// + private static MethodInfo FindCreateClipForAsset(Type trackType, Object sourceAsset) + { + if (sourceAsset == null) + return null; + + var assetType = sourceAsset.GetType(); + MethodInfo best = null; + foreach (var m in trackType.GetMethods(BindingFlags.Public | BindingFlags.Instance)) + { + if (m.Name != "CreateClip") + continue; + if (m.IsGenericMethodDefinition) + continue; + var ps = m.GetParameters(); + if (ps.Length != 1) + continue; + if (ps[0].ParameterType.IsAssignableFrom(assetType)) + { + // Prefer an exact match over a UnityEngine.Object-typed overload. + if (ps[0].ParameterType == assetType) + return m; + best = best ?? m; + } + } + return best; + } + + private static void ValidateClipCreatable(object track, Object sourceAsset) + { + var trackType = track.GetType(); + var isAnimation = trackType.FullName == "UnityEngine.Timeline.AnimationTrack"; + var isAudio = trackType.FullName == "UnityEngine.Timeline.AudioTrack"; + + if ((isAnimation || isAudio) && sourceAsset == null) + throw new ArgumentException($"Track type '{FriendlyTrackType(trackType)}' requires an 'asset' (AnimationClip / AudioClip) to create a clip."); + + if (sourceAsset != null && FindCreateClipForAsset(trackType, sourceAsset) == null) + throw new ArgumentException( + $"Track type '{FriendlyTrackType(trackType)}' has no CreateClip overload accepting a {sourceAsset.GetType().Name}."); + } + + private static object CreateClip(object track, Object sourceAsset) + { + var trackType = track.GetType(); + + if (sourceAsset != null) + { + var createClip = FindCreateClipForAsset(trackType, sourceAsset); + if (createClip == null) + throw new ArgumentException( + $"Track type '{FriendlyTrackType(trackType)}' has no CreateClip overload accepting a {sourceAsset.GetType().Name}."); + return createClip.Invoke(track, new object[] { sourceAsset }); + } + + var isAnimation = trackType.FullName == "UnityEngine.Timeline.AnimationTrack"; + var isAudio = trackType.FullName == "UnityEngine.Timeline.AudioTrack"; + if (isAnimation || isAudio) + throw new ArgumentException($"Track type '{FriendlyTrackType(trackType)}' requires an 'asset' (AnimationClip / AudioClip) to create a clip."); + + // For tracks that don't take a source asset, create a default (empty) clip. + var createDefault = trackType.GetMethod("CreateDefaultClip", Type.EmptyTypes); + if (createDefault != null) + return createDefault.Invoke(track, null); + + throw new InvalidOperationException($"No CreateClip / CreateDefaultClip available on '{trackType.Name}'."); + } + + private static void SetClipTiming(object clip, double start, double duration) + { + var clipType = clip.GetType(); + SetDoubleMember(clip, clipType, "start", start); + SetDoubleMember(clip, clipType, "duration", duration); + } + + private static string FriendlyTrackType(Type trackType) + { + foreach (var pair in TrackTypeNames) + { + if (pair.Value == trackType.FullName) + return pair.Key; + } + // Strip the trailing "Track" suffix for any unmapped subclass. + var n = trackType.Name; + return n.EndsWith("Track", StringComparison.Ordinal) ? n.Substring(0, n.Length - "Track".Length) : n; + } + + private static string GetName(object obj) + { + var prop = obj.GetType().GetProperty("name", BindingFlags.Public | BindingFlags.Instance); + return prop?.GetValue(obj) as string; + } + + private static object GetMember(object obj, Type type, string name) + { + var prop = type.GetProperty(name, BindingFlags.Public | BindingFlags.Instance); + if (prop != null) + return prop.GetValue(obj); + var field = type.GetField(name, BindingFlags.Public | BindingFlags.Instance); + return field?.GetValue(obj); + } + + private static double GetDouble(object obj, Type type, string name) + { + var value = GetMember(obj, type, name); + return value == null ? 0d : Convert.ToDouble(value); + } + + private static double GetDoubleMember(object obj, Type type, string name) => GetDouble(obj, type, name); + + private static void SetDoubleMember(object obj, Type type, string name, double value) + { + var prop = type.GetProperty(name, BindingFlags.Public | BindingFlags.Instance); + if (prop != null && prop.CanWrite) + { + prop.SetValue(obj, value); + return; + } + var field = type.GetField(name, BindingFlags.Public | BindingFlags.Instance); + field?.SetValue(obj, value); + } + + private static void FillIdentity(AuthoringResult result, Object asset) + { + var described = ObjectResolver.Describe(asset); + if (described == null) + return; + result.Guid = described.Guid; + result.FileId = described.FileId; + result.GlobalId = described.GlobalId; + } + + private static void EnsureParentFolder(string assetPath) + { + var parent = Path.GetDirectoryName(assetPath)?.Replace('\\', '/'); + if (string.IsNullOrEmpty(parent) || AssetDatabase.IsValidFolder(parent)) + return; + CreateFolderRecursive(parent); + } + + private static void CreateFolderRecursive(string assetsPath) + { + if (AssetDatabase.IsValidFolder(assetsPath)) + return; + + var parent = Path.GetDirectoryName(assetsPath)?.Replace('\\', '/'); + var name = Path.GetFileName(assetsPath); + if (string.IsNullOrEmpty(parent) || string.IsNullOrEmpty(name)) + throw new ArgumentException($"Invalid folder path '{assetsPath}'."); + + if (!AssetDatabase.IsValidFolder(parent)) + CreateFolderRecursive(parent); + + AssetDatabase.CreateFolder(parent, name); + } + } + + // ---- result models ---- + + [Serializable] + class TimelineTrackSummary + { + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("type")] + public string TrackType { get; set; } + } + + [Serializable] + class AddTimelineTrackResult : AuthoringResult + { + [JsonProperty("track")] + public TimelineTrackSummary Track { get; set; } + } + + [Serializable] + class TimelineClipSummary + { + [JsonProperty("track")] + public string Track { get; set; } + + [JsonProperty("start")] + public float Start { get; set; } + + [JsonProperty("duration")] + public float Duration { get; set; } + } + + [Serializable] + class AddTimelineClipResult : AuthoringResult + { + [JsonProperty("clip")] + public TimelineClipSummary Clip { get; set; } + } + + [Serializable] + class TimelineInfo + { + [JsonProperty("assetPath")] + public string AssetPath { get; set; } + + [JsonProperty("frameRate")] + public double FrameRate { get; set; } + + [JsonProperty("duration")] + public double Duration { get; set; } + + [JsonProperty("tracks")] + public List Tracks { get; set; } = new List(); + } + + [Serializable] + class TimelineTrackInfo + { + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("type")] + public string TrackType { get; set; } + + [JsonProperty("clips")] + public List Clips { get; set; } = new List(); + } + + [Serializable] + class TimelineClipInfo + { + [JsonProperty("start")] + public double Start { get; set; } + + [JsonProperty("duration")] + public double Duration { get; set; } + + [JsonProperty("asset")] + public string Asset { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/TimelineCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/TimelineCommands.cs.meta new file mode 100644 index 0000000..538c4fc --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/TimelineCommands.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: dcf5399fb1544ee3a5b069c535bcd002 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/TimelineGuard.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/TimelineGuard.cs new file mode 100644 index 0000000..5a75224 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/TimelineGuard.cs @@ -0,0 +1,58 @@ +using System; +#if UNITY_6000_5_OR_NEWER +using Unity.Scripting.LifecycleManagement; +#endif + +namespace Unity.Pipeline.Editor.Commands.Animation +{ + /// + /// Presence guard for the optional com.unity.timeline package (CLI-214, Group C). + /// + /// The Editor assembly deliberately does NOT reference Unity.Timeline (an asmdef reference + /// would break compilation in any project that doesn't have the package installed). Instead, the + /// Timeline commands reach the package via reflection, and this guard reports whether the package's + /// core type is loadable — the optional-package guard pattern for commands backed by a package that + /// may not be present. + /// + /// The guard caches its result for the lifetime of the domain; a package add/remove triggers a + /// domain reload, which resets the cache. + /// +#if UNITY_6000_5_OR_NEWER + [NoAutoStaticsCleanup] +#endif + static class TimelineGuard + { + /// The package id, surfaced in the not-installed error message. + public const string PackageId = "com.unity.timeline"; + + /// Assembly-qualified name of the package's root asset type. + public const string TimelineAssetTypeName = "UnityEngine.Timeline.TimelineAsset, Unity.Timeline"; + + private static bool? s_Installed; + + /// + /// True when the Timeline package is installed (its TimelineAsset type resolves). + /// + public static bool IsInstalled() + { + if (s_Installed.HasValue) + return s_Installed.Value; + + s_Installed = ResolveTimelineAssetType() != null; + return s_Installed.Value; + } + + /// + /// The UnityEngine.Timeline.TimelineAsset , or null if the package is + /// absent. Callers use this as the entry point for further reflection. + /// + public static Type ResolveTimelineAssetType() => Type.GetType(TimelineAssetTypeName, throwOnError: false); + + /// + /// The structured "package not installed" error (HTTP 200, no exception) that every Timeline + /// command returns when is false. + /// + public static ErrorResult NotInstalledError() => + ErrorResult.PackageStyle("package_not_found", $"{PackageId} is not installed"); + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/TimelineGuard.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/TimelineGuard.cs.meta new file mode 100644 index 0000000..607fca6 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Animation/TimelineGuard.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f3f8120d06814b2c86d46503ac132022 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets.meta new file mode 100644 index 0000000..23d44dc --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 39163f849a3aebd47a3f718fdc0224f9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/AssetCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/AssetCommands.cs new file mode 100644 index 0000000..f5e3fa3 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/AssetCommands.cs @@ -0,0 +1,585 @@ +using System; +using System.IO; +using System.Reflection; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Models; +using UnityEditor; +using UnityEngine; +using Object = UnityEngine.Object; +#if !UNITY_6000_0_OR_NEWER +using PhysicsMaterial = UnityEngine.PhysicMaterial; +#endif + +namespace Unity.Pipeline.Editor.Commands.Assets +{ + /// + /// Asset lifecycle authoring commands (CLI-191): create / import / move / copy / rename / delete + /// project assets. They sit on top of the CLI-190 authoring foundation, so: + /// + /// - every agent-supplied path is funnelled through (sandboxed + /// to the authoring root; rejects "../" and out-of-project writes), + /// - results are returned as the canonical envelope so an agent can + /// reference the asset in a follow-up call, + /// - existing assets are addressed with an resolved by + /// . + /// + /// NOTE: AssetDatabase create/move/copy/rename/delete are NOT part of Unity's Undo system, so + /// would have no effect here — these operations are intentionally + /// not wrapped in an undo scope, and destructive/overwriting operations instead require an explicit + /// confirm argument (and support dry_run) so an agent cannot silently lose data. + /// + static class AssetCommands + { + [CliCommand("create_asset", "Create a new ScriptableObject (or other UnityEngine.Object) asset of the given type at a path under the authoring root.", Tags = new[] { "assets" })] + public static AuthoringResult CreateAsset( + [CliArg("path", "Asset path relative to the authoring root, including extension (e.g. Data/Config.asset or Materials/Wall.mat). The Assets/ prefix is optional.", Required = true)] string path, + [CliArg("type", "Fully-qualified or short type name to instantiate (e.g. UnityEngine.Material, MyGame.GameConfig). Must derive from UnityEngine.Object and be creatable.", Required = true)] string type, + [CliArg("shader", "Material-only (ignored otherwise): shader name to assign (e.g. Standard, \"Universal Render Pipeline/Lit\"). When omitted, defaults to \"Universal Render Pipeline/Lit\" if a Scriptable Render Pipeline is active, otherwise the built-in \"Standard\" shader (falling back to \"Standard\" if URP/Lit is unavailable).")] string shader = null, + [CliArg("confirm", "Required (true) only when overwriting an existing asset at the path. Ignored when the path is empty.")] bool confirm = false, + [CliArg("dry_run", "If true, validate inputs and report what would be created without writing anything.")] bool dryRun = false) + { + var normalized = ProjectPaths.Resolve(path, out var error); + if (normalized == null) + throw new ArgumentException(error); + + if (string.IsNullOrEmpty(Path.GetExtension(normalized))) + throw new ArgumentException($"Asset path '{normalized}' must include a file extension (e.g. .asset, .mat)."); + + var resolvedType = ResolveType(type); + if (resolvedType == null) + throw new ArgumentException($"Could not resolve type '{type}'. Use a fully-qualified name (e.g. UnityEngine.Material)."); + if (!typeof(Object).IsAssignableFrom(resolvedType)) + throw new ArgumentException($"Type '{resolvedType.FullName}' does not derive from UnityEngine.Object."); + + // CLI-222: Unity 6 renamed PhysicMaterial -> PhysicsMaterial, but the on-disk asset + // extension is still ".physicMaterial". AssetDatabase.CreateAsset rejects a + // ".physicsMaterial" file ("should not be used to create a file of type 'physicsMaterial'"), + // so accept either spelling from the agent and normalize to the extension Unity writes. + if (typeof(PhysicsMaterial).IsAssignableFrom(resolvedType) && + normalized.EndsWith(".physicsMaterial", StringComparison.OrdinalIgnoreCase)) + { + normalized = normalized.Substring(0, normalized.Length - ".physicsMaterial".Length) + ".physicMaterial"; + } + + var exists = AssetDatabase.LoadMainAssetAtPath(normalized) != null; + if (exists && !confirm) + throw new ArgumentException($"An asset already exists at '{normalized}'. Pass confirm=true to overwrite it."); + + // CLI-221: for a Material, resolve (and thereby validate) the shader up front so dry_run + // also fails fast on an unknown shader — dry_run is documented as "validate inputs". + Shader materialShader = null; + if (typeof(Material).IsAssignableFrom(resolvedType)) + materialShader = ResolveShader(shader); + + if (dryRun) + return new AuthoringResult { AssetPath = normalized, Type = resolvedType.Name }; + + EnsureParentFolder(normalized); + + Object asset; + if (typeof(ScriptableObject).IsAssignableFrom(resolvedType)) + { + asset = ScriptableObject.CreateInstance(resolvedType); + } + else if (typeof(Material).IsAssignableFrom(resolvedType)) + { + // CLI-221: Material has no public parameterless ctor (Activator.CreateInstance produces + // an invalid Material with a null shader), so construct it explicitly from the shader + // resolved (and validated) above. The `shader` arg is Material-specific and ignored for + // every other type. + asset = new Material(materialShader); + } + else if (typeof(PhysicsMaterial).IsAssignableFrom(resolvedType)) + { + // CLI-222: PhysicsMaterial has a public parameterless ctor, but create it explicitly so + // we can stamp the documented sensible defaults rather than relying on engine defaults. + asset = new PhysicsMaterial + { + dynamicFriction = 0.6f, + staticFriction = 0.6f, + bounciness = 0f, + }; + } + else + { + // Other UnityEngine.Object subclasses with a public parameterless ctor. + // Activator.CreateInstance throws for abstract types or types without an accessible + // parameterless ctor — surface that as an actionable ArgumentException. + try + { + asset = Activator.CreateInstance(resolvedType) as Object; + } + catch (Exception ex) + { + throw new ArgumentException( + $"Type '{resolvedType.FullName}' could not be instantiated (it may be abstract or lack a public parameterless constructor): {ex.Message}"); + } + } + + if (asset == null) + throw new ArgumentException($"Type '{resolvedType.FullName}' could not be instantiated as a creatable asset."); + + // AssetDatabase.CreateAsset does not reliably overwrite an existing asset at the path, so + // explicitly delete it first. The confirm guard above gates that an asset already exists. + if (exists) + AssetDatabase.DeleteAsset(normalized); + + AssetDatabase.CreateAsset(asset, normalized); + AssetDatabase.SaveAssets(); + AssetDatabase.ImportAsset(normalized); + + var loaded = AssetDatabase.LoadMainAssetAtPath(normalized); + var result = ObjectResolver.Describe(loaded) ?? new AuthoringResult { Type = resolvedType.Name }; + result.AssetPath = normalized; + return result; + } + + [CliCommand("import_asset", "Import an external file (e.g. a texture, model, audio clip) into the project by copying it to a path under the authoring root, then importing it.", Tags = new[] { "assets/import" })] + public static AuthoringResult ImportAsset( + [CliArg("source", "Absolute filesystem path to the external file to import.", Required = true)] string source, + [CliArg("path", "Destination asset path relative to the authoring root, including extension. The Assets/ prefix is optional.", Required = true)] string path, + [CliArg("confirm", "Required (true) only when overwriting an existing asset at the destination path.")] bool confirm = false, + [CliArg("dry_run", "If true, validate inputs and report what would be imported without writing anything.")] bool dryRun = false) + { + if (string.IsNullOrWhiteSpace(source)) + throw new ArgumentException("source is required."); + if (!File.Exists(source)) + throw new ArgumentException($"Source file '{source}' does not exist."); + + var normalized = ProjectPaths.Resolve(path, out var error); + if (normalized == null) + throw new ArgumentException(error); + + var exists = AssetDatabase.LoadMainAssetAtPath(normalized) != null || File.Exists(ToAbsolute(normalized)); + if (exists && !confirm) + throw new ArgumentException($"An asset already exists at '{normalized}'. Pass confirm=true to overwrite it."); + + if (dryRun) + return new AuthoringResult { AssetPath = normalized, Type = "ImportedAsset" }; + + EnsureParentFolder(normalized); + File.Copy(source, ToAbsolute(normalized), overwrite: true); + AssetDatabase.ImportAsset(normalized, ImportAssetOptions.ForceUpdate); + + var loaded = AssetDatabase.LoadMainAssetAtPath(normalized); + var result = ObjectResolver.Describe(loaded) ?? new AuthoringResult(); + result.AssetPath = normalized; + return result; + } + + [CliCommand("move_asset", "Move (or rename via a new path) an asset to a new location under the authoring root. Preserves the asset's GUID.", Tags = new[] { "assets" })] + public static AuthoringResult MoveAsset( + [CliArg("asset", "Reference to the asset to move (path / guid / globalId).", Required = true)] ObjectRef asset, + [CliArg("destination", "Destination asset path relative to the authoring root, including extension. The Assets/ prefix is optional.", Required = true)] string destination, + [CliArg("dry_run", "If true, validate the move (via AssetDatabase.ValidateMoveAsset) without performing it.")] bool dryRun = false) + { + var sourcePath = ResolveAssetPath(asset); + + var dest = ProjectPaths.Resolve(destination, out var error); + if (dest == null) + throw new ArgumentException(error); + + // For a real move, create the destination's parent folder *before* validating: Unity's + // ValidateMoveAsset reports failure ("move as a subdirectory") when the target folder + // doesn't exist yet. Dry-run must not create folders, so it validates against the current + // project state only. + if (!dryRun) + EnsureParentFolder(dest); + + var validation = AssetDatabase.ValidateMoveAsset(sourcePath, dest); + if (!string.IsNullOrEmpty(validation)) + throw new ArgumentException($"Cannot move '{sourcePath}' to '{dest}': {validation}"); + + if (dryRun) + return new AuthoringResult { AssetPath = dest, Type = AssetDatabase.GetMainAssetTypeAtPath(sourcePath)?.Name }; + + var moveError = AssetDatabase.MoveAsset(sourcePath, dest); + if (!string.IsNullOrEmpty(moveError)) + throw new ArgumentException($"Failed to move '{sourcePath}' to '{dest}': {moveError}"); + + var loaded = AssetDatabase.LoadMainAssetAtPath(dest); + var result = ObjectResolver.Describe(loaded) ?? new AuthoringResult(); + result.AssetPath = dest; + return result; + } + + [CliCommand("copy_asset", "Copy an asset to a new path under the authoring root. The copy gets a fresh GUID.", Tags = new[] { "assets" })] + public static AuthoringResult CopyAsset( + [CliArg("asset", "Reference to the asset to copy (path / guid / globalId).", Required = true)] ObjectRef asset, + [CliArg("destination", "Destination asset path relative to the authoring root, including extension. The Assets/ prefix is optional.", Required = true)] string destination, + [CliArg("confirm", "Required (true) only when overwriting an existing asset at the destination path.")] bool confirm = false, + [CliArg("dry_run", "If true, validate inputs and report what would be copied without writing anything.")] bool dryRun = false) + { + var sourcePath = ResolveAssetPath(asset); + + var dest = ProjectPaths.Resolve(destination, out var error); + if (dest == null) + throw new ArgumentException(error); + + var exists = AssetDatabase.LoadMainAssetAtPath(dest) != null; + if (exists && !confirm) + throw new ArgumentException($"An asset already exists at '{dest}'. Pass confirm=true to overwrite it."); + + if (dryRun) + return new AuthoringResult { AssetPath = dest, Type = AssetDatabase.GetMainAssetTypeAtPath(sourcePath)?.Name }; + + EnsureParentFolder(dest); + + // AssetDatabase.CopyAsset fails if the destination already exists, so delete it first when + // the caller has confirmed an overwrite (the confirm guard above gates that). + if (exists) + AssetDatabase.DeleteAsset(dest); + + if (!AssetDatabase.CopyAsset(sourcePath, dest)) + throw new ArgumentException($"Failed to copy '{sourcePath}' to '{dest}'."); + + var loaded = AssetDatabase.LoadMainAssetAtPath(dest); + var result = ObjectResolver.Describe(loaded) ?? new AuthoringResult(); + result.AssetPath = dest; + return result; + } + + [CliCommand("rename_asset", "Rename an asset in place (keeps it in the same folder, keeps its GUID).", Tags = new[] { "assets" })] + public static AuthoringResult RenameAsset( + [CliArg("asset", "Reference to the asset to rename (path / guid / globalId).", Required = true)] ObjectRef asset, + [CliArg("new_name", "New file name WITHOUT a folder path. The extension is preserved if omitted.", Required = true)] string newName, + [CliArg("dry_run", "If true, validate the rename without performing it.")] bool dryRun = false) + { + if (string.IsNullOrWhiteSpace(newName)) + throw new ArgumentException("new_name is required."); + if (newName.Contains("/") || newName.Contains("\\")) + throw new ArgumentException("new_name must be a file name only, not a path. Use move_asset to relocate an asset."); + + var sourcePath = ResolveAssetPath(asset); + + // Preserve the original extension when the agent omits one (AssetDatabase.RenameAsset expects no extension). + var bareName = Path.GetFileNameWithoutExtension(newName); + var extension = Path.GetExtension(sourcePath); + var folder = Path.GetDirectoryName(sourcePath)?.Replace('\\', '/'); + var destPath = $"{folder}/{bareName}{extension}"; + + if (AssetDatabase.LoadMainAssetAtPath(destPath) != null) + throw new ArgumentException($"An asset already exists at '{destPath}'."); + + if (dryRun) + return new AuthoringResult { AssetPath = destPath, Type = AssetDatabase.GetMainAssetTypeAtPath(sourcePath)?.Name }; + + var renameError = AssetDatabase.RenameAsset(sourcePath, bareName); + if (!string.IsNullOrEmpty(renameError)) + throw new ArgumentException($"Failed to rename '{sourcePath}': {renameError}"); + + var loaded = AssetDatabase.LoadMainAssetAtPath(destPath); + var result = ObjectResolver.Describe(loaded) ?? new AuthoringResult(); + result.AssetPath = destPath; + return result; + } + + [CliCommand("delete_asset", "Delete an asset from the project. Destructive: requires confirm=true.", Tags = new[] { "assets" })] + public static AuthoringResult DeleteAsset( + [CliArg("asset", "Reference to the asset to delete (path / guid / globalId).", Required = true)] ObjectRef asset, + [CliArg("confirm", "Must be true to actually delete. Without it the command refuses (destructive guard).")] bool confirm = false, + [CliArg("dry_run", "If true, report the asset that would be deleted without deleting it.")] bool dryRun = false) + { + var sourcePath = ResolveAssetPath(asset); + + // Capture the identity before deletion so the agent gets a record of what was removed. + var loaded = AssetDatabase.LoadMainAssetAtPath(sourcePath); + var result = ObjectResolver.Describe(loaded) ?? new AuthoringResult { Type = AssetDatabase.GetMainAssetTypeAtPath(sourcePath)?.Name }; + result.AssetPath = sourcePath; + + if (dryRun) + return result; + + if (!confirm) + throw new ArgumentException($"Refusing to delete '{sourcePath}'. Pass confirm=true to delete it (destructive, not undoable via Unity's Undo)."); + + if (!AssetDatabase.DeleteAsset(sourcePath)) + throw new ArgumentException($"Failed to delete '{sourcePath}'."); + + return result; + } + + [CliCommand("find_assets", "Find assets by type and/or name and/or label, returning their path, GUID and type. At least one filter is required.", Tags = new[] { "assets" })] + public static FindAssetsResult FindAssets( + [CliArg("type", "Type name to filter by (e.g. Material, GameObject, ScriptableObject, MyGame.GameConfig). Resolved to a System.Type and matched against each asset's actual main type.")] string type = null, + [CliArg("name", "Name substring to filter by (AssetDatabase name filter).")] string name = null, + [CliArg("label", "Asset label to filter by (AssetDatabase 'l:' filter).")] string label = null, + [CliArg("search_in", "Folder to scope the search to, relative to the authoring root (default: the authoring root).")] string searchIn = null, + [CliArg("limit", "Maximum number of results to return (default 200).")] int limit = 200) + { + if (string.IsNullOrWhiteSpace(type) && string.IsNullOrWhiteSpace(name) && string.IsNullOrWhiteSpace(label)) + throw new ArgumentException("At least one of type, name, or label is required."); + + // The type filter is applied by post-filtering on each asset's actual loaded type rather + // than via AssetDatabase's "t:" token: "t:" does NOT reliably match freshly-created/custom + // ScriptableObject assets (it can return 0 even for "t:ScriptableObject"), though it works + // for built-in types. Name/label searches do work, so build the query from those only. + var filterParts = new System.Collections.Generic.List(); + if (!string.IsNullOrWhiteSpace(name)) + filterParts.Add(name.Trim()); + if (!string.IsNullOrWhiteSpace(label)) + filterParts.Add($"l:{label.Trim()}"); + var filter = string.Join(" ", filterParts); + + // Default the search scope to the authoring root (not the whole project) so an agent only + // ever discovers assets within its sandbox unless an explicit scope is given. + var scopeError = (string)null; + var scope = !string.IsNullOrWhiteSpace(searchIn) + ? ProjectPaths.Resolve(searchIn, out scopeError) + : ProjectPaths.AuthoringRoot; + if (scope == null) + throw new ArgumentException(scopeError); + var searchFolders = new[] { scope }; + + // Resolve the type filter up front so an unresolvable name fails fast with a clear message. + Type typeFilter = null; + if (!string.IsNullOrWhiteSpace(type)) + { + typeFilter = ResolveTypeName(type.Trim()); + if (typeFilter == null) + throw new ArgumentException( + $"Could not resolve type '{type}'. Use a short name (e.g. Material) or a fully-qualified name (e.g. MyGame.GameConfig)."); + } + + // An empty name/label filter enumerates every asset under the search folders. + var guids = AssetDatabase.FindAssets(filter ?? string.Empty, searchFolders); + + var result = new FindAssetsResult { Filter = filter }; + foreach (var guid in guids) + { + var assetPath = AssetDatabase.GUIDToAssetPath(guid); + if (string.IsNullOrEmpty(assetPath)) + continue; + + var mainType = AssetDatabase.GetMainAssetTypeAtPath(assetPath); + if (typeFilter != null && (mainType == null || !typeFilter.IsAssignableFrom(mainType))) + continue; + + if (result.Assets.Count >= limit) + { + result.Truncated = true; + break; + } + + result.Assets.Add(new AuthoringResult + { + AssetPath = assetPath, + Guid = guid, + Type = mainType?.Name + }); + } + + result.Count = result.Assets.Count; + return result; + } + + /// + /// Resolve a user-supplied type name (short or fully-qualified) to a by + /// scanning non-dynamic loaded assemblies. Returns null when no match is found. + /// + private static Type ResolveTypeName(string typeName) + { + var direct = Type.GetType(typeName, throwOnError: false); + if (direct != null) + return direct; + + foreach (var assembly in PipelineUtils.GetLoadedAssemblies()) + { + if (assembly.IsDynamic) + continue; + + var byFullName = assembly.GetType(typeName, throwOnError: false); + if (byFullName != null) + return byFullName; + } + + foreach (var assembly in PipelineUtils.GetLoadedAssemblies()) + { + if (assembly.IsDynamic) + continue; + + Type[] types; + try + { + types = assembly.GetTypes(); + } + catch (ReflectionTypeLoadException ex) + { + types = ex.Types; + } + + foreach (var candidate in types) + { + if (candidate != null && candidate.Name == typeName) + return candidate; + } + } + + return null; + } + + /// + /// Resolve an to a project-relative asset path, rejecting handles that + /// do not resolve to an on-disk asset (scene objects have no asset path). The resolved path is + /// confined to the authoring root so a GUID/globalId handle cannot make a destructive command + /// (delete/move/copy/rename) operate on an asset outside the sandbox. + /// + private static string ResolveAssetPath(ObjectRef asset) + { + var assetPath = ObjectResolver.TryResolve(asset, out var obj, out var error) + ? AssetDatabase.GetAssetPath(obj) + : null; + + // Fallback: a path reference that points at an asset which exists on disk (a GUID is + // registered) but whose object cannot be loaded — e.g. a just-moved asset whose object + // isn't reloadable this frame, or an asset with an unresolved/broken script. We can still + // operate on it by path, so honor the path rather than failing the whole command. + if (string.IsNullOrEmpty(assetPath) && !string.IsNullOrEmpty(asset?.Path)) + { + var candidate = ProjectPaths.Resolve(asset.Path, out _); + if (candidate != null && !string.IsNullOrEmpty(AssetDatabase.AssetPathToGUID(candidate))) + assetPath = candidate; + } + + if (string.IsNullOrEmpty(assetPath)) + throw new ArgumentException(error ?? $"Reference '{asset}' does not point at an on-disk asset."); + + // Confine to the authoring root. ProjectPaths.Resolve treats explicit "Assets/..." paths as + // project-relative and rejects anything outside the configured root. + var confined = ProjectPaths.Resolve(assetPath, out var confineError); + if (confined == null) + throw new ArgumentException( + $"Asset '{assetPath}' is outside the authoring root '{ProjectPaths.AuthoringRoot}': {confineError}"); + + return confined; + } + + /// Create the asset's parent folder chain if it does not yet exist. + private static void EnsureParentFolder(string assetPath) + { + var parent = Path.GetDirectoryName(assetPath)?.Replace('\\', '/'); + if (string.IsNullOrEmpty(parent) || AssetDatabase.IsValidFolder(parent)) + return; + + CreateFolderRecursive(parent); + } + + private static void CreateFolderRecursive(string assetsPath) + { + if (AssetDatabase.IsValidFolder(assetsPath)) + return; + + var parent = Path.GetDirectoryName(assetsPath)?.Replace('\\', '/'); + var name = Path.GetFileName(assetsPath); + if (string.IsNullOrEmpty(parent) || string.IsNullOrEmpty(name)) + throw new ArgumentException($"Invalid folder path '{assetsPath}'."); + + if (!AssetDatabase.IsValidFolder(parent)) + CreateFolderRecursive(parent); + + AssetDatabase.CreateFolder(parent, name); + } + + /// Convert a project-relative asset path to an absolute filesystem path. + private static string ToAbsolute(string projectRelative) + { + return $"{ProjectPaths.ProjectRoot.Replace('\\', '/')}/{projectRelative}"; + } + + /// + /// CLI-221: resolve the shader to assign to a newly-created . + /// - An explicit must resolve via ; + /// a miss is a clear, actionable error (no null Material / null-ref downstream). + /// - When omitted, default to the active render pipeline's lit shader: "Universal Render + /// Pipeline/Lit" when an SRP asset is active, else built-in "Standard". If that default + /// can't be found, fall back to "Standard"; if even that is missing, error clearly. + /// + private static Shader ResolveShader(string shaderName) + { + if (!string.IsNullOrWhiteSpace(shaderName)) + { + var requested = Shader.Find(shaderName.Trim()); + if (requested == null) + throw new ArgumentException($"Shader '{shaderName}' not found."); + return requested; + } + + var usingSrp = UnityEngine.Rendering.GraphicsSettings.currentRenderPipeline != null; + var defaultName = usingSrp ? "Universal Render Pipeline/Lit" : "Standard"; + + var defaultShader = Shader.Find(defaultName); + if (defaultShader != null) + return defaultShader; + + // Fall back to the built-in Standard shader (always present in the Built-in RP, and a sane + // last resort even under an SRP project that lacks the URP/Lit shader). + var standard = Shader.Find("Standard"); + if (standard != null) + return standard; + + throw new ArgumentException( + $"Could not resolve a default shader ('{defaultName}' or 'Standard'). Pass an explicit shader= argument."); + } + + /// + /// Resolve a user-supplied type name to a . Tries the name as-is (covers + /// fully-qualified names), then scans loaded assemblies for an exact full-name or short-name + /// match (covers "Material" or a user type given without its namespace). + /// + private static Type ResolveType(string typeName) + { + if (string.IsNullOrWhiteSpace(typeName)) + return null; + + // Trim once up front so every resolution path below (special-case + assembly/type scans) + // sees the same normalized name — leading/trailing whitespace must not be accepted for one + // type and rejected for another. + typeName = typeName.Trim(); + + // CLI-222: in Unity 6 the type is UnityEngine.PhysicsMaterial (renamed from PhysicMaterial). + // A short name "PhysicsMaterial" resolves fine, but the legacy short name "PhysicMaterial" + // matches the obsolete forwarder/alias inconsistently across versions — normalize BOTH the + // current and legacy names (short or fully-qualified) to the real type up front so callers + // can use either spelling. + if (typeName == "PhysicsMaterial" || typeName == "PhysicMaterial" + || typeName == "UnityEngine.PhysicsMaterial" || typeName == "UnityEngine.PhysicMaterial") + { + return typeof(PhysicsMaterial); + } + + var direct = Type.GetType(typeName, throwOnError: false); + if (direct != null) + return direct; + + foreach (var assembly in PipelineUtils.GetLoadedAssemblies()) + { + var byFullName = assembly.GetType(typeName, throwOnError: false); + if (byFullName != null) + return byFullName; + } + + // Fall back to a short-name match across all loaded types. + foreach (var assembly in PipelineUtils.GetLoadedAssemblies()) + { + Type[] types; + try + { + types = assembly.GetTypes(); + } + catch (ReflectionTypeLoadException ex) + { + types = ex.Types; + } + + foreach (var candidate in types) + { + if (candidate != null && candidate.Name == typeName) + return candidate; + } + } + + return null; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/AssetCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/AssetCommands.cs.meta new file mode 100644 index 0000000..6afcc35 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/AssetCommands.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 47b49bf20465486fb6ffdf6c03775b16 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/AssetImportCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/AssetImportCommands.cs new file mode 100644 index 0000000..ecbb5f5 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/AssetImportCommands.cs @@ -0,0 +1,660 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using Newtonsoft.Json.Linq; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Models; +using UnityEditor; +#if UNITY_6000_5_OR_NEWER +using Unity.Scripting.LifecycleManagement; +#endif + +namespace Unity.Pipeline.Editor.Commands.Assets +{ + /// + /// + /// Import-settings authoring commands (CLI-191 + CLI-212). Reads and edits the + /// for an asset. + /// + /// + /// + /// set_import_settings sets named members on the importer from a JSON object and re-imports. + /// For the Default platform it sets top-level public properties/fields via reflection (works + /// across every importer kind). For a real platform on a / + /// , keys are applied onto the platform-override struct + /// ( / ) which + /// is unreachable by top-level reflection. has no per-platform overrides. + /// + /// + /// + /// get_import_settings reads the importer state structured by importer type (texture / model / + /// audio), including the default-platform fields and, for textures/audio, one platform override block. + /// + /// + /// + /// Unknown keys are reported back rather than silently ignored, so an agent gets actionable feedback. + /// + /// + /// + /// NOTE: import settings live in the asset's .meta file via the importer; this is an AssetDatabase + /// operation and is not part of Unity's Undo system. SaveAndReimport is not destructive to the + /// source file, so no confirm is required. + /// + /// +#if UNITY_6000_5_OR_NEWER + [NoAutoStaticsCleanup] +#endif + static class AssetImportCommands + { + // Caller-facing platform names accepted by both commands. "Default" means the default platform + // (top-level importer properties / default sample settings); the rest are real build platforms. + private static readonly HashSet s_SupportedPlatforms = new HashSet(StringComparer.OrdinalIgnoreCase) + { + "Default", "Standalone", "iOS", "Android", "WebGL", "tvOS" + }; + + [CliCommand("set_import_settings", "Set import settings on an asset's AssetImporter (default platform top-level properties, or a texture/audio per-platform override) and re-import it.", Tags = new[] { "assets/import" })] + public static SetImportSettingsResult SetImportSettings( + [CliArg("asset", "Reference to the asset whose importer to edit (path / guid / globalId).", Required = true)] ObjectRef asset, + [CliArg("settings", "JSON object of importer property/field names to values, e.g. {\"isReadable\": true, \"textureType\": \"NormalMap\"}. For platform != Default on a texture/audio importer, keys map onto the platform-settings struct (e.g. maxTextureSize, format, compressionFormat, quality, and overridden).", Required = true)] JObject settings, + [CliArg("platform", "Target platform: Default | Standalone | iOS | Android | WebGL | tvOS. Defaults to Default (top-level importer properties). A real platform writes a per-platform override (textures/audio only).")] string platform = "Default", + [CliArg("dry_run", "If true, validate which settings would apply (and which are unknown) without writing or re-importing.")] bool dryRun = false) + { + var importer = ResolveImporter(asset, out var assetPath); + + if (settings == null || settings.Count == 0) + throw new ArgumentException("settings must be a non-empty JSON object."); + + if (!s_SupportedPlatforms.Contains(platform)) + throw new ArgumentException( + Serialize(new ErrorResult { Code = "unknown_platform", Message = $"Unknown platform '{platform}'. Supported: {string.Join(", ", s_SupportedPlatforms)}." })); + + var canonicalPlatform = Canonical(platform); + var isDefault = string.Equals(canonicalPlatform, "Default", StringComparison.OrdinalIgnoreCase); + + var result = new SetImportSettingsResult + { + AssetPath = assetPath, + ImporterType = importer.GetType().Name, + Platform = canonicalPlatform + }; + + // Strip the server-injected token before iterating: it is never an importer setting. + var keys = new List(); + foreach (var pair in settings) + { + if (pair.Key == "token") + continue; + keys.Add(pair.Key); + } + if (keys.Count == 0) + throw new ArgumentException("settings must be a non-empty JSON object."); + + if (isDefault) + { + ApplyDefaultPlatform(importer, settings, keys, result, write: !dryRun); + } + else + { + switch (importer) + { + case TextureImporter texture: + ApplyTexturePlatform(texture, settings, keys, canonicalPlatform, result, write: !dryRun); + break; + case AudioImporter audio: + ApplyAudioPlatform(audio, settings, keys, canonicalPlatform, result, write: !dryRun); + break; + case ModelImporter _: + throw new ArgumentException( + Serialize(new ErrorResult { Code = "no_platform_overrides", Message = "ModelImporter has no per-platform overrides; use platform=Default." })); + default: + throw new ArgumentException( + Serialize(new ErrorResult { Code = "no_platform_overrides", Message = $"Importer '{result.ImporterType}' has no per-platform overrides; use platform=Default." })); + } + } + + if (result.Unknown.Count > 0 && result.Applied.Count == 0) + throw new ArgumentException($"None of the supplied settings could be applied to '{result.ImporterType}' (unknown key or invalid value): {string.Join(", ", result.Unknown)}."); + + if (dryRun) + return result; + + importer.SaveAndReimport(); + return result; + } + + [CliCommand("get_import_settings", "Read an asset's import settings, structured by importer type (texture/model/audio), including the default-platform fields and (for textures/audio) one platform override block.", Tags = new[] { "assets/import" })] + public static GetImportSettingsResult GetImportSettings( + [CliArg("asset", "Reference to the asset whose importer to read (path / guid / globalId).", Required = true)] ObjectRef asset, + [CliArg("platform", "Platform whose override to read: Default | Standalone | iOS | Android | WebGL | tvOS. Defaults to Default.")] string platform = "Default") + { + var importer = ResolveImporter(asset, out var assetPath); + + if (!s_SupportedPlatforms.Contains(platform)) + throw new ArgumentException( + Serialize(new ErrorResult { Code = "unknown_platform", Message = $"Unknown platform '{platform}'. Supported: {string.Join(", ", s_SupportedPlatforms)}." })); + + var canonicalPlatform = Canonical(platform); + var isDefault = string.Equals(canonicalPlatform, "Default", StringComparison.OrdinalIgnoreCase); + + var result = new GetImportSettingsResult + { + AssetPath = assetPath, + ImporterType = importer.GetType().Name, + Platform = canonicalPlatform + }; + + switch (importer) + { + case TextureImporter texture: + result.Settings = ReadTextureDefaults(texture); + result.PlatformOverride = ReadTexturePlatformOverride(texture, canonicalPlatform, isDefault); + break; + case ModelImporter model: + result.Settings = ReadModelDefaults(model); + result.PlatformOverride = null; // ModelImporter has no per-platform overrides. + break; + case AudioImporter audio: + result.Settings = ReadAudioDefaults(audio); + result.PlatformOverride = ReadAudioPlatformOverride(audio, canonicalPlatform, isDefault); + break; + default: + // Non-import asset (e.g. a ScriptableObject via NativeFormatImporter): return a + // minimal settings block rather than throwing. + result.Settings = new Dictionary + { + ["userData"] = importer.userData, + ["assetBundleName"] = importer.assetBundleName + }; + result.PlatformOverride = null; + break; + } + + return result; + } + + // ------------------------------------------------------------------ resolution / helpers + + /// + /// Resolve an to its , confined to the + /// authoring root. Throws an actionable on any failure. + /// + private static AssetImporter ResolveImporter(ObjectRef asset, out string assetPath) + { + if (!ObjectResolver.TryResolve(asset, out var obj, out var error)) + throw new ArgumentException(error); + + assetPath = AssetDatabase.GetAssetPath(obj); + if (string.IsNullOrEmpty(assetPath)) + throw new ArgumentException($"Reference '{asset}' does not point at an on-disk asset."); + + // Confine to the authoring root so a GUID/globalId handle cannot reach an asset outside the + // sandbox. + assetPath = ProjectPaths.Resolve(assetPath, out var confineError); + if (assetPath == null) + throw new ArgumentException( + $"Asset '{asset}' is outside the authoring root '{ProjectPaths.AuthoringRoot}': {confineError}"); + + var importer = AssetImporter.GetAtPath(assetPath); + if (importer == null) + throw new ArgumentException($"No AssetImporter found for '{assetPath}'."); + + return importer; + } + + /// Normalize a caller platform name to its canonical capitalization (e.g. "ios" -> "iOS"). + private static string Canonical(string platform) + { + foreach (var supported in s_SupportedPlatforms) + { + if (string.Equals(supported, platform, StringComparison.OrdinalIgnoreCase)) + return supported; + } + return platform; + } + + /// + /// Map a caller-facing platform name to the build-platform string Unity's importer APIs expect. + /// Most match 1:1; iOS is "iPhone" to those APIs. + /// + private static string UnityPlatformName(string canonicalPlatform) + { + return string.Equals(canonicalPlatform, "iOS", StringComparison.OrdinalIgnoreCase) ? "iPhone" : canonicalPlatform; + } + + // ------------------------------------------------------------------ default-platform reflection + + private static void ApplyDefaultPlatform(AssetImporter importer, JObject settings, List keys, SetImportSettingsResult result, bool write) + { + var importerType = importer.GetType(); + const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase; + + foreach (var key in keys) + { + // In dry_run we only validate the member exists and the value converts — never mutate the + // (possibly cached) importer instance, so a dry run leaves no trace. + var applied = TryApplyMember(importer, importerType, flags, key, settings[key], write); + if (applied) + result.Applied.Add(key); + else + result.Unknown.Add(key); + } + } + + /// + /// Set a single named property or field on the target from a JSON token. Returns false when no + /// writable member with that name exists or the value cannot be converted to the member type. + /// Enum members accept the value name (case-insensitive) as well as numeric values. + /// + private static bool TryApplyMember(object target, Type type, BindingFlags flags, string memberName, JToken value, bool write) + { + var property = type.GetProperty(memberName, flags); + if (property != null && property.CanWrite && property.GetIndexParameters().Length == 0) + { + return TryConvertAndSet(property.PropertyType, value, + converted => { if (write) property.SetValue(target, converted); }); + } + + var field = type.GetField(memberName, flags); + if (field != null) + { + return TryConvertAndSet(field.FieldType, value, + converted => { if (write) field.SetValue(target, converted); }); + } + + return false; + } + + /// + /// Convert a JSON token to (with case-insensitive enum-name support) + /// and, on success, invoke . Returns false when the value cannot convert. + /// + private static bool TryConvertAndSet(Type targetType, JToken value, Action set) + { + try + { + if (!TryConvert(targetType, value, out var converted)) + return false; + set(converted); + return true; + } + catch + { + return false; + } + } + + /// + /// Convert a JSON token to a CLR value. Enums accept their value name (case-insensitive) or an + /// integral value; everything else defers to Newtonsoft's . + /// + private static bool TryConvert(Type targetType, JToken value, out object converted) + { + converted = null; + var underlying = Nullable.GetUnderlyingType(targetType) ?? targetType; + + if (underlying.IsEnum) + { + if (value.Type == JTokenType.String) + { + var name = value.Value(); + if (string.IsNullOrEmpty(name)) + return false; + try + { + converted = Enum.Parse(underlying, name, ignoreCase: true); + return true; + } + catch + { + return false; + } + } + + if (value.Type == JTokenType.Integer) + { + converted = Enum.ToObject(underlying, value.Value()); + return true; + } + + return false; + } + + converted = value.ToObject(targetType); + return true; + } + + // ------------------------------------------------------------------ texture platform overrides + + private static void ApplyTexturePlatform(TextureImporter texture, JObject settings, List keys, string canonicalPlatform, SetImportSettingsResult result, bool write) + { + var unityPlatform = UnityPlatformName(canonicalPlatform); + // Boxed struct so reflection SetValue mutates the local copy; written back via SetPlatformTextureSettings. + object boxed = texture.GetPlatformTextureSettings(unityPlatform); + var type = typeof(TextureImporterPlatformSettings); + const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase; + + // Only treat "overridden" as explicitly provided when the caller passes a valid boolean. + // A non-boolean value is caught by TrySetBoolMember (reported to unknown[]), so we must + // not suppress the default overridden=true in that case or the override is silently skipped. + var explicitOverridden = settings.TryGetValue("overridden", StringComparison.OrdinalIgnoreCase, out var overriddenTok) + && overriddenTok.Type == JTokenType.Boolean; + + foreach (var key in keys) + { + if (string.Equals(key, "overridden", StringComparison.OrdinalIgnoreCase)) + { + // Handled explicitly below; still report it as applied. + if (TrySetBoolMember(type, flags, boxed, "overridden", settings[key], write)) + result.Applied.Add(key); + else + result.Unknown.Add(key); + continue; + } + + if (TryApplyMember(boxed, type, flags, key, settings[key], write)) + result.Applied.Add(key); + else + result.Unknown.Add(key); + } + + // Default the override on (the caller intends to set platform-specific values) unless they + // explicitly passed overridden:false (in which case the value they passed is already in the + // boxed copy from the loop above). + if (!explicitOverridden) + SetBool(type, flags, boxed, "overridden", true); + + if (write && result.Applied.Count > 0) + { + var settingsStruct = (TextureImporterPlatformSettings)boxed; + settingsStruct.name = unityPlatform; + texture.SetPlatformTextureSettings(settingsStruct); + } + } + + /// + /// Set a named boolean member from a JSON token. Returns false when the token is not a boolean or + /// no settable bool member with that name exists, so a non-existent member is reported as unknown + /// rather than falsely applied. In =false (dry-run) mode the member is only + /// probed for existence, never mutated. + /// + private static bool TrySetBoolMember(Type type, BindingFlags flags, object boxed, string member, JToken token, bool write) + { + if (token.Type != JTokenType.Boolean) + return false; + if (!write) + return BoolMemberExists(type, flags, member); + return SetBool(type, flags, boxed, member, token.Value()); + } + + /// True when a settable boolean property or field with that name exists on the type. + private static bool BoolMemberExists(Type type, BindingFlags flags, string member) + { + var property = type.GetProperty(member, flags); + if (property != null && property.CanWrite && property.PropertyType == typeof(bool) + && property.GetIndexParameters().Length == 0) + return true; + + var field = type.GetField(member, flags); + return field != null && field.FieldType == typeof(bool); + } + + /// + /// Write a boolean property or field (matching 's property-then-field + /// resolution so a bool implemented as a property is also honored). Returns false — without + /// mutating anything — when no settable bool member with that name exists. + /// + private static bool SetBool(Type type, BindingFlags flags, object boxed, string member, bool value) + { + var property = type.GetProperty(member, flags); + if (property != null && property.CanWrite && property.PropertyType == typeof(bool) + && property.GetIndexParameters().Length == 0) + { + property.SetValue(boxed, value); + return true; + } + + var field = type.GetField(member, flags); + if (field != null && field.FieldType == typeof(bool)) + { + field.SetValue(boxed, value); + return true; + } + + return false; + } + + private static Dictionary ReadTextureDefaults(TextureImporter texture) + { + return new Dictionary + { + ["textureType"] = texture.textureType.ToString(), + ["textureShape"] = texture.textureShape.ToString(), + ["sRGBTexture"] = texture.sRGBTexture, + ["alphaSource"] = texture.alphaSource.ToString(), + ["alphaIsTransparency"] = texture.alphaIsTransparency, + ["isReadable"] = texture.isReadable, + ["streamingMipmaps"] = texture.streamingMipmaps, + ["mipmapEnabled"] = texture.mipmapEnabled, + ["wrapMode"] = texture.wrapMode.ToString(), + ["filterMode"] = texture.filterMode.ToString(), + ["anisoLevel"] = texture.anisoLevel, + ["spriteImportMode"] = texture.spriteImportMode.ToString(), + ["spritePixelsPerUnit"] = texture.spritePixelsPerUnit, + ["npotScale"] = texture.npotScale.ToString(), + ["maxTextureSize"] = texture.maxTextureSize + }; + } + + private static Dictionary ReadTexturePlatformOverride(TextureImporter texture, string canonicalPlatform, bool isDefault) + { + var settings = isDefault + ? texture.GetDefaultPlatformTextureSettings() + : texture.GetPlatformTextureSettings(UnityPlatformName(canonicalPlatform)); + + return new Dictionary + { + ["overridden"] = !isDefault && settings.overridden, + ["maxTextureSize"] = settings.maxTextureSize, + ["resizeAlgorithm"] = settings.resizeAlgorithm.ToString(), + ["format"] = settings.format.ToString(), + ["textureCompression"] = settings.textureCompression.ToString(), + ["compressionQuality"] = settings.compressionQuality, + ["crunchedCompression"] = settings.crunchedCompression, + ["androidETC2FallbackOverride"] = settings.androidETC2FallbackOverride.ToString() + }; + } + + // ------------------------------------------------------------------ audio platform overrides + + private static void ApplyAudioPlatform(AudioImporter audio, JObject settings, List keys, string canonicalPlatform, SetImportSettingsResult result, bool write) + { + var unityPlatform = UnityPlatformName(canonicalPlatform); + + // overridden:false clears the override entirely (and ignores any other keys). + if (settings.TryGetValue("overridden", StringComparison.OrdinalIgnoreCase, out var overriddenToken) + && overriddenToken.Type == JTokenType.Boolean + && !overriddenToken.Value()) + { + result.Applied.Add("overridden"); + if (write) + audio.ClearSampleSettingOverride(unityPlatform); + return; + } + + object boxed = audio.GetOverrideSampleSettings(unityPlatform); + var type = typeof(AudioImporterSampleSettings); + const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase; + + foreach (var key in keys) + { + if (string.Equals(key, "overridden", StringComparison.OrdinalIgnoreCase)) + { + // Only accept a boolean; anything else is a misuse and goes to unknown[]. + if (settings[key].Type == JTokenType.Boolean) + result.Applied.Add(key); + else + result.Unknown.Add(key); + continue; + } + + if (TryApplyMember(boxed, type, flags, key, settings[key], write)) + result.Applied.Add(key); + else + result.Unknown.Add(key); + } + + if (write && result.Applied.Count > 0) + { + var settingsStruct = (AudioImporterSampleSettings)boxed; + audio.SetOverrideSampleSettings(unityPlatform, settingsStruct); + } + } + + private static Dictionary ReadAudioDefaults(AudioImporter audio) + { + var sample = audio.defaultSampleSettings; + return new Dictionary + { + ["forceToMono"] = audio.forceToMono, + ["loadInBackground"] = audio.loadInBackground, + ["ambisonic"] = audio.ambisonic, + ["loadType"] = sample.loadType.ToString(), + ["compressionFormat"] = sample.compressionFormat.ToString(), + ["quality"] = sample.quality, + ["sampleRateSetting"] = sample.sampleRateSetting.ToString(), + ["sampleRateOverride"] = sample.sampleRateOverride + }; + } + + private static Dictionary ReadAudioPlatformOverride(AudioImporter audio, string canonicalPlatform, bool isDefault) + { + if (isDefault) + { + var sample = audio.defaultSampleSettings; + return new Dictionary + { + ["overridden"] = false, + ["loadType"] = sample.loadType.ToString(), + ["compressionFormat"] = sample.compressionFormat.ToString(), + ["quality"] = sample.quality, + ["sampleRateSetting"] = sample.sampleRateSetting.ToString(), + ["sampleRateOverride"] = sample.sampleRateOverride + }; + } + + var unityPlatform = UnityPlatformName(canonicalPlatform); + var overridden = audio.ContainsSampleSettingsOverride(unityPlatform); + var settings = audio.GetOverrideSampleSettings(unityPlatform); + return new Dictionary + { + ["overridden"] = overridden, + ["loadType"] = settings.loadType.ToString(), + ["compressionFormat"] = settings.compressionFormat.ToString(), + ["quality"] = settings.quality, + ["sampleRateSetting"] = settings.sampleRateSetting.ToString(), + ["sampleRateOverride"] = settings.sampleRateOverride + }; + } + + // ------------------------------------------------------------------ model defaults (no overrides) + + private static Dictionary ReadModelDefaults(ModelImporter model) + { + return new Dictionary + { + // Meshes + ["globalScale"] = model.globalScale, + ["useFileScale"] = model.useFileScale, + ["meshCompression"] = model.meshCompression.ToString(), + ["isReadable"] = model.isReadable, + ["meshOptimizationFlags"] = model.meshOptimizationFlags.ToString(), + ["weldVertices"] = model.weldVertices, + ["indexFormat"] = model.indexFormat.ToString(), + ["keepQuads"] = model.keepQuads, + // Normals / Tangents + ["importNormals"] = model.importNormals.ToString(), + ["normalCalculationMode"] = model.normalCalculationMode.ToString(), + ["normalSmoothingAngle"] = model.normalSmoothingAngle, + ["importTangents"] = model.importTangents.ToString(), + ["importBlendShapes"] = model.importBlendShapes, + // Geometry + ["importCameras"] = model.importCameras, + ["importLights"] = model.importLights, + ["swapUVChannels"] = model.swapUVChannels, + ["generateSecondaryUV"] = model.generateSecondaryUV, + // Materials + ["materialImportMode"] = model.materialImportMode.ToString(), + ["materialLocation"] = model.materialLocation.ToString(), + // Animation + ["importAnimation"] = model.importAnimation, + ["animationType"] = model.animationType.ToString(), + ["importConstraints"] = model.importConstraints, + ["importVisibility"] = model.importVisibility + }; + } + + private static string Serialize(object value) + { + return Newtonsoft.Json.JsonConvert.SerializeObject(value); + } + } + + /// + /// Result of set_import_settings: target platform plus which keys were applied vs. unknown. + /// + [Serializable] + class SetImportSettingsResult + { + [Newtonsoft.Json.JsonProperty("assetPath")] + public string AssetPath { get; set; } + + [Newtonsoft.Json.JsonProperty("importerType")] + public string ImporterType { get; set; } + + [Newtonsoft.Json.JsonProperty("platform")] + public string Platform { get; set; } + + [Newtonsoft.Json.JsonProperty("applied")] + public List Applied { get; set; } = new List(); + + [Newtonsoft.Json.JsonProperty("unknown")] + public List Unknown { get; set; } = new List(); + } + + /// + /// Result of get_import_settings: the importer type, default-platform settings, and (for + /// textures/audio) one platform-override block. platformOverride is null for ModelImporter and + /// non-import assets. + /// + [Serializable] + class GetImportSettingsResult + { + [Newtonsoft.Json.JsonProperty("assetPath")] + public string AssetPath { get; set; } + + [Newtonsoft.Json.JsonProperty("importerType")] + public string ImporterType { get; set; } + + [Newtonsoft.Json.JsonProperty("settings")] + public Dictionary Settings { get; set; } + + [Newtonsoft.Json.JsonProperty("platform")] + public string Platform { get; set; } + + [Newtonsoft.Json.JsonProperty("platformOverride")] + public Dictionary PlatformOverride { get; set; } + } + + /// Structured error payload serialized into the thrown ArgumentException message. + [Serializable] + class ErrorResult + { + [Newtonsoft.Json.JsonProperty("code")] + public string Code { get; set; } + + [Newtonsoft.Json.JsonProperty("message")] + public string Message { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/AssetImportCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/AssetImportCommands.cs.meta new file mode 100644 index 0000000..f1ef29b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/AssetImportCommands.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: cb5b302104dc446d8d94f33252087062 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/FindAssetsResult.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/FindAssetsResult.cs new file mode 100644 index 0000000..bfbd46e --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/FindAssetsResult.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Unity.Pipeline.Models; + +namespace Unity.Pipeline.Editor.Commands.Assets +{ + /// + /// Structured result for the find_assets command (CLI-191): a list of matched assets, each + /// described as the canonical (path / GUID / type) so an agent can + /// feed any entry straight back into another command as an . + /// + /// Lives in the Editor command assembly (rather than Runtime/Models) because find_assets is an + /// Editor-only command and the foundation Runtime/Models are shared/frozen for parallel work. + /// + [System.Serializable] + class FindAssetsResult + { + /// The AssetDatabase filter string that was executed (for diagnostics). + [JsonProperty("filter")] + public string Filter { get; set; } + + /// Number of assets returned (after the limit is applied). + [JsonProperty("count")] + public int Count { get; set; } + + /// True when the result was capped by the limit argument. + [JsonProperty("truncated")] + public bool Truncated { get; set; } + + /// The matched assets, each with path / GUID / type. + [JsonProperty("assets")] + public List Assets { get; set; } = new List(); + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/FindAssetsResult.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/FindAssetsResult.cs.meta new file mode 100644 index 0000000..c916640 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/FindAssetsResult.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7ff032cead554b7f97cd2467a83abd35 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/FolderCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/FolderCommands.cs new file mode 100644 index 0000000..327dc23 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/FolderCommands.cs @@ -0,0 +1,51 @@ +using System; +using System.IO; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Models; +using UnityEditor; + +namespace Unity.Pipeline.Editor.Commands.Assets +{ + /// + /// Asset-folder authoring commands. Reference exemplar for the authoring foundation (CLI-190): + /// it validates input through the project-path sandbox () and returns + /// the canonical envelope so an agent can reference the created + /// folder in follow-up calls. + /// + static class FolderCommands + { + [CliCommand("create_folder", "Create a folder under the authoring root (creates intermediate folders).", Tags = new[] { "assets" })] + public static AuthoringResult CreateFolder( + [CliArg("path", "Folder path relative to the authoring root (default Assets/); the Assets/ prefix is optional. e.g. Gameplay/Enemies or Assets/Gameplay/Enemies", Required = true)] string path) + { + var normalized = ProjectPaths.Resolve(path, out var error); + if (normalized == null) + throw new ArgumentException(error); + + CreateFolderRecursive(normalized); + AssetDatabase.Refresh(); + + var folder = AssetDatabase.LoadAssetAtPath(normalized); + var result = ObjectResolver.Describe(folder) ?? new AuthoringResult { Type = "DefaultAsset" }; + result.AssetPath = normalized; + return result; + } + + private static void CreateFolderRecursive(string assetsPath) + { + if (AssetDatabase.IsValidFolder(assetsPath)) + return; + + var parent = Path.GetDirectoryName(assetsPath)?.Replace('\\', '/'); + var name = Path.GetFileName(assetsPath); + if (string.IsNullOrEmpty(parent) || string.IsNullOrEmpty(name)) + throw new ArgumentException($"Invalid folder path '{assetsPath}'."); + + if (!AssetDatabase.IsValidFolder(parent)) + CreateFolderRecursive(parent); + + AssetDatabase.CreateFolder(parent, name); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/FolderCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/FolderCommands.cs.meta new file mode 100644 index 0000000..25bacd0 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/FolderCommands.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b78420627d9cd1e43835d9088975e691 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/TextFileCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/TextFileCommands.cs new file mode 100644 index 0000000..8be2e0a --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/TextFileCommands.cs @@ -0,0 +1,126 @@ +using System; +using System.IO; +using Newtonsoft.Json; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Models; +using UnityEditor; + +namespace Unity.Pipeline.Editor.Commands.Assets +{ + /// + /// Text-file authoring commands (CLI-191): read and write UTF-8 text files inside the authoring + /// sandbox. Useful for editing data assets that are plain text (JSON/CSV/.txt/.cs/.shader, etc.). + /// + /// Every path is funnelled through , so reads/writes are confined + /// to the authoring root and "../"/out-of-project paths are rejected. Writing imports the file back + /// into the AssetDatabase so Unity picks up the change. + /// + /// NOTE: writing is potentially destructive (it can overwrite an existing file), so overwriting an + /// existing file requires an explicit confirm argument; dry_run is supported. + /// Filesystem writes are not part of Unity's Undo system. + /// + static class TextFileCommands + { + [CliCommand("read_text_file", "Read a UTF-8 text file under the authoring root and return its contents.", MainThreadRequired = true, Tags = new[] { "assets/text" })] + public static ReadTextFileResult ReadTextFile( + [CliArg("path", "Text file path relative to the authoring root. The Assets/ prefix is optional.", Required = true)] string path, + [CliArg("max_bytes", "Reject files larger than this many bytes (default 1048576 = 1 MiB) to avoid huge payloads.")] int maxBytes = 1024 * 1024) + { + var normalized = ProjectPaths.Resolve(path, out var error); + if (normalized == null) + throw new ArgumentException(error); + + var absolute = ToAbsolute(normalized); + if (!File.Exists(absolute)) + throw new ArgumentException($"No file at '{normalized}'."); + + var length = new FileInfo(absolute).Length; + if (length > maxBytes) + throw new ArgumentException($"File '{normalized}' is {length} bytes, which exceeds max_bytes={maxBytes}."); + + return new ReadTextFileResult + { + AssetPath = normalized, + Bytes = (int)length, + Contents = File.ReadAllText(absolute) + }; + } + + [CliCommand("write_text_file", "Write UTF-8 text to a file under the authoring root, then import it. Overwriting an existing file requires confirm=true.", Tags = new[] { "assets/text" })] + public static AuthoringResult WriteTextFile( + [CliArg("path", "Text file path relative to the authoring root, including extension. The Assets/ prefix is optional.", Required = true)] string path, + [CliArg("contents", "The full text content to write (replaces the file).", Required = true)] string contents, + [CliArg("confirm", "Required (true) only when overwriting an existing file at the path.")] bool confirm = false, + [CliArg("dry_run", "If true, validate inputs and report what would be written without writing anything.")] bool dryRun = false) + { + var normalized = ProjectPaths.Resolve(path, out var error); + if (normalized == null) + throw new ArgumentException(error); + + if (contents == null) + throw new ArgumentException("contents is required (use an empty string to write an empty file)."); + + var absolute = ToAbsolute(normalized); + var exists = File.Exists(absolute); + if (exists && !confirm) + throw new ArgumentException($"A file already exists at '{normalized}'. Pass confirm=true to overwrite it."); + + if (dryRun) + return new AuthoringResult { AssetPath = normalized, Type = "TextAsset" }; + + EnsureParentFolder(normalized); + File.WriteAllText(absolute, contents); + AssetDatabase.ImportAsset(normalized, ImportAssetOptions.ForceUpdate); + + var loaded = AssetDatabase.LoadMainAssetAtPath(normalized); + var result = ObjectResolver.Describe(loaded) ?? new AuthoringResult { Type = "TextAsset" }; + result.AssetPath = normalized; + return result; + } + + private static void EnsureParentFolder(string assetPath) + { + var parent = Path.GetDirectoryName(assetPath)?.Replace('\\', '/'); + if (string.IsNullOrEmpty(parent) || AssetDatabase.IsValidFolder(parent)) + return; + + CreateFolderRecursive(parent); + } + + private static void CreateFolderRecursive(string assetsPath) + { + if (AssetDatabase.IsValidFolder(assetsPath)) + return; + + var parent = Path.GetDirectoryName(assetsPath)?.Replace('\\', '/'); + var name = Path.GetFileName(assetsPath); + if (string.IsNullOrEmpty(parent) || string.IsNullOrEmpty(name)) + throw new ArgumentException($"Invalid folder path '{assetsPath}'."); + + if (!AssetDatabase.IsValidFolder(parent)) + CreateFolderRecursive(parent); + + AssetDatabase.CreateFolder(parent, name); + } + + private static string ToAbsolute(string projectRelative) + { + return $"{ProjectPaths.ProjectRoot.Replace('\\', '/')}/{projectRelative}"; + } + } + + /// Result of read_text_file: the file contents plus its identity and size. + [Serializable] + class ReadTextFileResult + { + [JsonProperty("assetPath")] + public string AssetPath { get; set; } + + [JsonProperty("bytes")] + public int Bytes { get; set; } + + [JsonProperty("contents")] + public string Contents { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/TextFileCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/TextFileCommands.cs.meta new file mode 100644 index 0000000..b8375b8 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Assets/TextFileCommands.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f57a6d794d1e4c40976f65ec3774b8ed diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Authoring.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Authoring.meta new file mode 100644 index 0000000..6184fe6 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Authoring.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7512e3b6952430f4b8fb5c67dd22f13f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Authoring/AuthoringConfigCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Authoring/AuthoringConfigCommands.cs new file mode 100644 index 0000000..f31bb4f --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Authoring/AuthoringConfigCommands.cs @@ -0,0 +1,29 @@ +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor.Authoring; + +namespace Unity.Pipeline.Editor.Commands.Authoring +{ + /// + /// Commands to inspect and configure the authoring root — the base folder (under Assets/) that + /// bare authoring paths resolve against and that authoring writes are confined to. Persisted + /// per project; the default is "Assets" (full Assets access). + /// + static class AuthoringConfigCommands + { + [CliCommand("get_authoring_root", "Get the base folder (under Assets/) that bare authoring paths resolve against.", Tags = new[] { "authoring" })] + public static object GetAuthoringRoot() + { + return new { root = ProjectPaths.AuthoringRoot }; + } + + [CliCommand("set_authoring_root", "Set the base folder (under Assets/) that bare authoring paths resolve against and are confined to. Use 'Assets' for full project access.", Tags = new[] { "authoring" })] + public static object SetAuthoringRoot( + [CliArg("root", "Project-relative folder under Assets/, e.g. Assets/AgentWork. Use 'Assets' to allow the whole project.", Required = true)] string root) + { + // Throws ArgumentException for invalid roots (outside Assets/ or containing ".."); the + // server surfaces that message to the caller. + ProjectPaths.AuthoringRoot = root; + return new { root = ProjectPaths.AuthoringRoot }; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Authoring/AuthoringConfigCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Authoring/AuthoringConfigCommands.cs.meta new file mode 100644 index 0000000..76c13ef --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Authoring/AuthoringConfigCommands.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c4429604fb18e8347a2e2efdefc49663 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/AutoTickCommand.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/AutoTickCommand.cs new file mode 100644 index 0000000..7961582 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/AutoTickCommand.cs @@ -0,0 +1,194 @@ +using System; +using System.Reflection; +using Unity.Pipeline.Commands; +using UnityEditor; +#if UNITY_6000_5_OR_NEWER +using Unity.Scripting.LifecycleManagement; +#endif + +namespace Unity.Pipeline.Editor.Commands +{ + /// + /// Opt-in mode that keeps the Unity Editor ticking at full rate even when its window is + /// unfocused. Unity throttles EditorApplication.update when the editor is in the background, + /// which can stall long-running work (HTTP commands, async test runs) driven from the CLI. + /// + /// When enabled, this forces EditorApplication.SignalTick() on every update, which schedules + /// the next tick immediately and keeps the loop spinning. It is off by default and changes + /// nothing in normal package behavior. Cross-platform: no native/OS calls. + /// + /// Note: the update-loop subscription is static and does not survive a domain reload, but the + /// enabled/interval choice is persisted to SessionState and restored by + /// (called from EditorPipelineStartup on every server + /// (re)start, including after a recompile). Forcing full-rate ticks uses CPU like a focused editor. + /// +#if UNITY_6000_5_OR_NEWER + [NoAutoStaticsCleanup] +#endif + static class AutoTickCommand + { + // Default interval when nothing else applies (fresh editor session, no prior SetAutoTick call). + internal const int DefaultIntervalMs = 16; + + // SessionState keys: session-scoped editor state, survives domain reload, dies with the editor. + private const string EnabledKey = "Unity.Pipeline.AutoTick.Enabled"; + private const string IntervalKey = "Unity.Pipeline.AutoTick.IntervalMs"; + + private static bool s_Enabled; + private static Action s_SignalTick; + private static EditorApplication.CallbackFunction s_Pump; + private static readonly System.Diagnostics.Stopwatch s_Stopwatch = new System.Diagnostics.Stopwatch(); + private static long s_IntervalMs; + + internal static bool IsEnabled => s_Enabled; + internal static long CurrentIntervalMs => s_IntervalMs; + + [CliCommand("set_autotick", "Keep the editor ticking while unfocused by forcing EditorApplication.SignalTick at a throttled rate", MainThreadRequired = true, Tags = new[] { "editor" })] + public static string SetAutoTick( + [CliArg("enable", "Enable (true) or disable (false) auto-tick mode")] bool enable = true, + [CliArg("interval_ms", "Minimum milliseconds between forced ticks. 0 = every update (max rate, pegs a CPU core). Default 16 (~60Hz).")] int intervalMs = DefaultIntervalMs, + [CliArg("persist", "Persist this choice to SessionState so it survives a domain reload. Set false for a one-off/expensive setting (e.g. interval_ms=0) that should revert to the last persisted choice (or the default) after the next recompile instead of sticking for the rest of the session.")] bool persist = true) + { + var result = ApplyAutoTick(enable, intervalMs); + if (!persist) + return result.StartsWith("Error:") ? result : result + " (session-only, won't survive a domain reload)"; + + if (result.StartsWith("Error:")) + return result; + + SessionState.SetBool(EnabledKey, s_Enabled); + SessionState.SetInt(IntervalKey, (int)s_IntervalMs); + return result; + } + + /// + /// Restore auto-tick to whatever the user last explicitly set via + /// this editor session (surviving the domain reload that just wiped the statics). If nothing + /// was ever explicitly set this session, apply at + /// instead — this is the only case where the watchdog's + /// enabled setting decides auto-tick's state. Call on the main thread (touches SessionState). + /// + internal static void RestoreFromSession(bool defaultEnabled) + { + var storedInterval = SessionState.GetInt(IntervalKey, -1); + if (storedInterval < 0) + { + ApplyAutoTick(defaultEnabled, DefaultIntervalMs); + return; + } + + var storedEnabled = SessionState.GetBool(EnabledKey, defaultEnabled); + ApplyAutoTick(storedEnabled, storedInterval); + } + + /// + /// Test-only: drop the in-memory state (statics + update-loop subscription) but keep + /// SessionState, to simulate a domain reload (statics cleared, SessionState survives). + /// + internal static void ResetForTests() + { + if (s_Pump != null) + { + EditorApplication.update -= s_Pump; + s_Pump = null; + } + s_Stopwatch.Stop(); + s_Enabled = false; + s_IntervalMs = 0; + } + + /// + /// Test-only: erase the persisted SessionState copy (unlike , which + /// deliberately leaves it intact). Use for test isolation, not to simulate a reload. + /// + internal static void EraseSessionForTests() + { + SessionState.EraseInt(IntervalKey); + SessionState.EraseBool(EnabledKey); + } + + /// + /// Test-only: read the persisted SessionState copy without touching the in-memory statics. + /// Returns false if nothing has ever been persisted this session. + /// + internal static bool TryGetPersistedSessionForTests(out bool enabled, out long intervalMs) + { + var storedInterval = SessionState.GetInt(IntervalKey, -1); + if (storedInterval < 0) + { + enabled = false; + intervalMs = 0; + return false; + } + + enabled = SessionState.GetBool(EnabledKey, false); + intervalMs = storedInterval; + return true; + } + + /// + /// Test-only: write the persisted SessionState copy directly, bypassing ApplyAutoTick. + /// + internal static void SetPersistedSessionForTests(bool enabled, long intervalMs) + { + SessionState.SetBool(EnabledKey, enabled); + SessionState.SetInt(IntervalKey, (int)intervalMs); + } + + private static string ApplyAutoTick(bool enable, int intervalMs) + { + if (enable && s_Enabled) + { + s_IntervalMs = Math.Max(0, intervalMs); + return $"Auto-tick already enabled (interval updated to {s_IntervalMs}ms)"; + } + if (!enable && !s_Enabled) + return "Auto-tick already disabled"; + + if (enable) + { + if (s_SignalTick == null) + { + var method = typeof(EditorApplication).GetMethod( + "SignalTick", + BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); + + if (method == null) + return "Error: EditorApplication.SignalTick not found (internal API may have changed)"; + + try + { + s_SignalTick = (Action)Delegate.CreateDelegate(typeof(Action), method); + } + catch (Exception ex) + { + return $"Error: could not bind EditorApplication.SignalTick: {ex.Message}"; + } + } + + s_IntervalMs = Math.Max(0, intervalMs); + s_Stopwatch.Restart(); + s_Pump = () => + { + if (s_IntervalMs <= 0 || s_Stopwatch.ElapsedMilliseconds >= s_IntervalMs) + { + s_Stopwatch.Restart(); + s_SignalTick(); + } + }; + EditorApplication.update += s_Pump; + s_Enabled = true; + return $"Auto-tick enabled (interval {s_IntervalMs}ms)"; + } + + if (s_Pump != null) + { + EditorApplication.update -= s_Pump; + s_Pump = null; + } + s_Stopwatch.Stop(); + s_Enabled = false; + return "Auto-tick disabled"; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/AutoTickCommand.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/AutoTickCommand.cs.meta new file mode 100644 index 0000000..1b29ec1 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/AutoTickCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 76bae7b5ceb53dd498f891ed7f1e0d19 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking.meta new file mode 100644 index 0000000..131b032 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 758dc2e598a448e5b80e66443fede0d9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/BakeSceneGuard.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/BakeSceneGuard.cs new file mode 100644 index 0000000..4122776 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/BakeSceneGuard.cs @@ -0,0 +1,42 @@ +using System.Linq; +using UnityEngine.SceneManagement; + +namespace Unity.Pipeline.Editor.Commands.Baking +{ + /// + /// Shared helpers for the CLI-215 bake commands (lighting / NavMesh / occlusion). All three bakes + /// act on the currently open scene(s) — there is no per-asset target — so before triggering + /// any bake we verify at least one open, saved scene exists. A bake against no open/saved scene is + /// rejected up front with the documented { code: "no_scene" } result (returned, not thrown, + /// to match the CLI-215 spec), and nothing is started. + /// + internal static class BakeSceneGuard + { + /// The structured "no_scene" error payload returned by a trigger with no bakeable scene. + internal static object NoSceneResult() + { + return new + { + code = "no_scene", + message = "No open, saved scene to bake. Open a scene first (open_scene) and ensure it is saved to disk." + }; + } + + /// + /// True when there is at least one open, loaded scene that has been saved to disk (a non-empty + /// path). An untitled/never-saved scene has an empty and cannot host a + /// bake (its data has nowhere to live), so it does not count. + /// + internal static bool HasBakeableScene() + { + return OpenScenes().Any(s => s.isLoaded && !string.IsNullOrEmpty(s.path)); + } + + /// Enumerate every open scene by index. + internal static System.Collections.Generic.IEnumerable OpenScenes() + { + for (int i = 0; i < SceneManager.sceneCount; i++) + yield return SceneManager.GetSceneAt(i); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/BakeSceneGuard.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/BakeSceneGuard.cs.meta new file mode 100644 index 0000000..40ddf75 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/BakeSceneGuard.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cf05be2261cb475c9cf3d7fccbf65ff5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/LightingBakeCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/LightingBakeCommands.cs new file mode 100644 index 0000000..87e6ccd --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/LightingBakeCommands.cs @@ -0,0 +1,646 @@ +using System; +using System.IO; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Unity.Pipeline.Commands; +using UnityEditor; +using UnityEngine; +#if UNITY_6000_5_OR_NEWER +using Unity.Scripting.LifecycleManagement; +#endif + +namespace Unity.Pipeline.Editor.Commands.Baking +{ + /// + /// CLI-215 Group A — Lightmapping bake commands. Trigger an async lightmap bake of the open + /// scene(s), poll its status, cancel it, clear baked data, and read/configure the active + /// . + /// + /// Why async (trigger-then-poll, mirroring ): a full lightmap bake runs + /// for seconds-to-minutes. kicks the bake off and returns + /// immediately; bake_lighting therefore returns { status: "baking", bakeId } right + /// away and the caller polls lighting_bake_status until it reports completed. + /// + /// In-flight state is held in static fields and is domain-reload aware: a bake can survive (or + /// resume across) a domain reload, so on reload reconciles our recorded + /// state against the live flag and a small status file under + /// Temp/ (which persists across the reload, mirroring RecompileCommand). Completion is detected via + /// the callback and, defensively, by polling + /// flipping false in . + /// + [InitializeOnLoad] +#if UNITY_6000_5_OR_NEWER + [NoAutoStaticsCleanup] +#endif + static class LightingBakeCommands + { + const string StatusFile = "Temp/pipeline_lighting_bake_status.json"; + + static readonly object s_Lock = new object(); + + // True between trigger and the completion callback / isRunning flipping false. + static bool s_Tracking; + static string s_BakeId; + static DateTime s_StartedUtc; + + static LightingBakeCommands() + { + // Reconcile any in-flight bake recorded before a domain reload, then keep watching. + OnReload(); + Lightmapping.bakeCompleted += OnBakeCompleted; + EditorApplication.update += OnUpdate; + } + + #region bake_lighting + + [CliCommand("bake_lighting", "Trigger an async lightmap bake of the open scene(s) via Lightmapping.BakeAsync(). Returns immediately; poll lighting_bake_status until completed.", Tags = new[] { "baking/lighting" })] + public static object BakeLighting( + [CliArg("confirm", "Recommended (true): a bake overwrites existing lightmap data. Accepted for parity; not required.")] bool confirm = false, + [CliArg("dry_run", "If true, validate there is an open bakeable scene and return the current lighting settings without baking.")] bool dryRun = false) + { + if (!BakeSceneGuard.HasBakeableScene()) + return BakeSceneGuard.NoSceneResult(); + + // Reconcile before the in-progress check so a stale flag from a finished/cancelled bake + // doesn't wrongly report bake_in_progress. + OnUpdate(); + + if (Lightmapping.isRunning) + return new { code = "bake_in_progress", message = "A lighting bake is already running. Poll lighting_bake_status." }; + + if (dryRun) + return new { status = "dry_run", wouldBake = true, settings = ReadLightingSettings() }; + + var bakeId = Guid.NewGuid().ToString("N"); + lock (s_Lock) + { + s_Tracking = true; + s_BakeId = bakeId; + s_StartedUtc = DateTime.UtcNow; + } + + WriteStatus(new LightingBakeStatus + { + Status = "baking", + BakeId = bakeId, + IsBaking = true, + StartedUtcTicks = s_StartedUtc.Ticks + }); + + // BakeAsync returns false if the bake could not be started (e.g. another job in flight). + if (!Lightmapping.BakeAsync()) + { + lock (s_Lock) { s_Tracking = false; } + WriteStatus(new LightingBakeStatus { Status = "idle" }); + return new { code = "bake_in_progress", message = "Lightmapping.BakeAsync() refused to start (a bake may already be running)." }; + } + + return new { status = "baking", bakeId }; + } + + [CliCommand("lighting_bake_status", "Get the status of the last lighting bake: idle | baking | completed.", MainThreadRequired = false, Tags = new[] { "baking/lighting" })] + public static string LightingBakeStatus() + { + if (File.Exists(StatusFile)) + return File.ReadAllText(StatusFile); + return "{\"status\":\"idle\"}"; + } + + [CliCommand("cancel_lighting_bake", "Cancel an in-progress lighting bake (Lightmapping.Cancel()).", Tags = new[] { "baking/lighting" })] + public static object CancelLightingBake() + { + var wasRunning = Lightmapping.isRunning; + if (wasRunning) + Lightmapping.Cancel(); + + lock (s_Lock) + { + if (s_Tracking) + { + var ms = (int)Math.Max(0, (DateTime.UtcNow - s_StartedUtc).TotalMilliseconds); + WriteStatus(new LightingBakeStatus + { + Status = "completed", + Result = "cancelled", + BakeId = s_BakeId, + BakeTimeMs = ms + }); + s_Tracking = false; + } + } + + return new { cancelled = wasRunning }; + } + + [CliCommand("clear_baked_lighting", "Clear baked lightmap data for the open scene(s). Destructive: requires confirm=true.", Tags = new[] { "baking/lighting" })] + public static object ClearBakedLighting( + [CliArg("confirm", "Must be true to actually clear (destructive, not undoable via Unity's Undo).")] bool confirm = false, + [CliArg("include_disk_cache", "If true, also clear the GI disk cache (Lightmapping.ClearDiskCache()).")] bool includeDiskCache = false, + [CliArg("dry_run", "If true, report what would be cleared without clearing.")] bool dryRun = false) + { + if (!confirm) + throw new ArgumentException("Refusing to clear baked lighting. Pass confirm=true (destructive, not undoable via Unity's Undo)."); + + if (dryRun) + return new { status = "dry_run", wouldClear = true, includeDiskCache }; + + Lightmapping.Clear(); + if (includeDiskCache) + Lightmapping.ClearDiskCache(); + + return new { cleared = true, includeDiskCache }; + } + + #endregion + + #region settings + + [CliCommand("get_lighting_settings", "Read the active LightingSettings (lightmapper, bounces, resolution, directional mode, AO, etc.).", Tags = new[] { "baking/lighting" })] + public static LightingSettingsResult GetLightingSettings() + { + return ReadLightingSettings(); + } + + [CliCommand("set_lighting_settings", "Apply a subset of lighting settings to the active LightingSettings. Returns { applied[], unknown[] }.", Tags = new[] { "baking/lighting" })] + public static object SetLightingSettings( + [CliArg("settings", "JSON object with a subset of lighting fields to set (same names/enums as get_lighting_settings).", Required = true)] JObject settings, + [CliArg("dry_run", "If true, validate the keys and report applied/unknown without changing anything.")] bool dryRun = false) + { + if (settings == null) + throw new ArgumentException("settings is required (a JSON object of lighting fields to set)."); + + // In dry_run we must not create or assign a LightingSettings asset (no writes). When no + // settings exist yet, validate the requested keys against a transient throwaway instance + // that is never assigned, so applied/unknown is still reported without persisting anything. + var ls = ActiveLightingSettings(allowCreate: !dryRun, out var source); + LightingSettings transient = null; + if (ls == null) + { + transient = new LightingSettings { name = "PipelineLightingSettings (dry-run)" }; + ls = transient; + source = "none"; + } + + var applied = new System.Collections.Generic.List(); + var unknown = new System.Collections.Generic.List(); + + foreach (var prop in settings.Properties()) + { + if (TryApply(ls, prop.Name, prop.Value, dryRun)) + applied.Add(prop.Name); + else + unknown.Add(prop.Name); + } + + if (!dryRun && applied.Count > 0) + EditorUtility.SetDirty(ls); + + // The transient dry-run instance is never assigned anywhere; destroy it so it doesn't leak. + if (transient != null) + UnityEngine.Object.DestroyImmediate(transient); + + return new + { + applied = applied.ToArray(), + unknown = unknown.ToArray(), + settingsSource = source, + dryRun + }; + } + + #endregion + + #region completion / reload bookkeeping + + static void OnBakeCompleted() + { + lock (s_Lock) + { + if (!s_Tracking) + return; + Finish("succeeded"); + } + } + + /// + /// Defensive completion detector: if we are tracking a bake but Lightmapping reports it is no + /// longer running and the completion callback didn't fire (e.g. a cancel, or a bake that ended + /// during a frame we didn't get the callback), finalize the status here. + /// + static void OnUpdate() + { + lock (s_Lock) + { + if (s_Tracking && !Lightmapping.isRunning) + Finish("succeeded"); + } + } + + // Must be called under s_Lock. + static void Finish(string result) + { + var ms = (int)Math.Max(0, (DateTime.UtcNow - s_StartedUtc).TotalMilliseconds); + var status = new LightingBakeStatus + { + Status = "completed", + Result = result, + BakeId = s_BakeId, + BakeTimeMs = ms, + Stats = result == "succeeded" ? CollectStats() : null + }; + WriteStatus(status); + s_Tracking = false; + } + + /// + /// Reconcile recorded in-flight state after a domain reload. The status file under Temp/ survives + /// the reload; if it said "baking" but Lightmapping is no longer running, the bake finished while + /// the domain was being reloaded, so mark it completed. If it is still running, resume tracking. + /// + static void OnReload() + { + if (!File.Exists(StatusFile)) + return; + + LightingBakeStatus prior; + try + { + prior = JsonConvert.DeserializeObject(File.ReadAllText(StatusFile)); + } + catch + { + return; + } + + if (prior == null || prior.Status != "baking") + return; + + lock (s_Lock) + { + s_BakeId = prior.BakeId; + s_StartedUtc = prior.StartedUtcTicks > 0 ? new DateTime(prior.StartedUtcTicks, DateTimeKind.Utc) : DateTime.UtcNow; + + if (Lightmapping.isRunning) + { + s_Tracking = true; // resume; OnUpdate/OnBakeCompleted will finalize. + } + else + { + s_Tracking = true; + Finish("succeeded"); // ended during the reload window. + } + } + } + + #endregion + + #region settings read/write helpers + + /// + /// The active for the open scene. When the scene has no explicit + /// LightingSettings asset assigned, Unity falls back to a hidden per-scene default that + /// / + /// still exposes; we read/write that. records which we used. + /// + /// When none is available and is true, a new settings asset is + /// created and assigned so a real (non-dry_run) set has a target. When + /// is false (dry_run), this returns null rather than creating/assigning anything, so the + /// dry_run "no writes" contract holds. + /// + static LightingSettings ActiveLightingSettings(bool allowCreate, out string source) + { + // Lightmapping.lightingSettings returns the active scene's settings (assigned asset or the + // scene's embedded/default settings). It throws if there is genuinely none; guard for that. + try + { + var ls = Lightmapping.lightingSettings; + if (ls != null) + { + source = AssetDatabase.Contains(ls) ? "asset" : "scene-default"; + return ls; + } + } + catch + { + // fall through to (optionally) creating one + } + + if (!allowCreate) + { + source = "none"; + return null; + } + + // No settings available: create and assign one so set_lighting_settings has a target. + var created = new LightingSettings { name = "PipelineLightingSettings" }; + Lightmapping.lightingSettings = created; + source = "created"; + return created; + } + + static LightingSettingsResult ReadLightingSettings() + { + LightingSettings ls; + try + { + ls = Lightmapping.lightingSettings; + } + catch + { + ls = null; + } + + if (ls == null) + return new LightingSettingsResult { Available = false }; + + return new LightingSettingsResult + { + Available = true, + Lightmapper = ls.lightmapper.ToString(), + BakedGI = ls.bakedGI, + RealtimeGI = ls.realtimeGI, + DirectSampleCount = ls.directSampleCount, + IndirectSampleCount = ls.indirectSampleCount, + EnvironmentSampleCount = ls.environmentSampleCount, + Bounces = ls.maxBounces, + LightmapResolution = ls.lightmapResolution, + LightmapPadding = ls.lightmapPadding, + MaxLightmapSize = ls.lightmapMaxSize, + LightmapCompression = ls.lightmapCompression.ToString(), + // Unity 6000 serialises directionalityMode as a flags enum whose .ToString() can + // produce compound strings (e.g. "Single, Dual") for values that span multiple bits. + // Map to the two-value contract the spec guarantees: 0 → NonDirectional, else → Directional. + DirectionalMode = (int)ls.directionalityMode == 0 ? "NonDirectional" : "Directional", + Ao = ls.ao, + AoMaxDistance = ls.aoMaxDistance, + FilteringMode = ls.filteringMode.ToString() + }; + } + + /// + /// Apply one settings key/value to the LightingSettings. Returns false for unrecognized keys so + /// the caller can report them as unknown[]. Enum-valued fields accept their string names + /// (case-insensitive). In dry-run mode we still validate (parse) the value but do not assign. + /// + static bool TryApply(LightingSettings ls, string key, JToken value, bool dryRun) + { + switch (key) + { + case "lightmapper": + return SetEnum(value, dryRun, v => ls.lightmapper = v); + case "bakedGI": + if (!dryRun) ls.bakedGI = value.Value(); + return true; + case "realtimeGI": + if (!dryRun) ls.realtimeGI = value.Value(); + return true; + case "directSampleCount": + if (!dryRun) ls.directSampleCount = value.Value(); + return true; + case "indirectSampleCount": + if (!dryRun) ls.indirectSampleCount = value.Value(); + return true; + case "environmentSampleCount": + if (!dryRun) ls.environmentSampleCount = value.Value(); + return true; + case "bounces": + if (!dryRun) ls.maxBounces = value.Value(); + return true; + case "lightmapResolution": + if (!dryRun) ls.lightmapResolution = value.Value(); + return true; + case "lightmapPadding": + if (!dryRun) ls.lightmapPadding = value.Value(); + return true; + case "maxLightmapSize": + if (!dryRun) ls.lightmapMaxSize = value.Value(); + return true; + case "lightmapCompression": + return SetEnum(value, dryRun, v => ls.lightmapCompression = v); + case "directionalMode": + // Accept the two spec names ("NonDirectional", "Directional") and also Unity's + // internal name ("CombinedDirectional") for back-compat. Integer values pass through + // as-is so callers can target any raw enum slot Unity exposes. + if (value.Type == JTokenType.Integer) + { + if (!dryRun) ls.directionalityMode = (LightmapsMode)value.Value(); + return true; + } + var modeStr = value.Value() ?? string.Empty; + if (modeStr.Equals("NonDirectional", StringComparison.OrdinalIgnoreCase)) + { + if (!dryRun) ls.directionalityMode = (LightmapsMode)0; + return true; + } + if (modeStr.Equals("Directional", StringComparison.OrdinalIgnoreCase) || + modeStr.Equals("CombinedDirectional", StringComparison.OrdinalIgnoreCase)) + { + if (!dryRun) ls.directionalityMode = (LightmapsMode)1; + return true; + } + throw new ArgumentException( + $"Value '{modeStr}' is not valid for directionalMode. Valid: NonDirectional, Directional."); + case "ao": + if (!dryRun) ls.ao = value.Value(); + return true; + case "aoMaxDistance": + if (!dryRun) ls.aoMaxDistance = value.Value(); + return true; + case "filteringMode": + return SetEnum(value, dryRun, v => ls.filteringMode = v); + default: + return false; + } + } + + static bool SetEnum(JToken value, bool dryRun, Action assign) where TEnum : struct + { + // Accept either the enum's string name (case-insensitive) or its integer value. + if (value.Type == JTokenType.Integer) + { + var iv = value.Value(); + if (!Enum.IsDefined(typeof(TEnum), iv)) + throw new ArgumentException($"Value '{iv}' is not valid for {typeof(TEnum).Name}."); + if (!dryRun) assign((TEnum)Enum.ToObject(typeof(TEnum), iv)); + return true; + } + + var name = value.Value(); + if (!Enum.TryParse(name, ignoreCase: true, out var parsed)) + throw new ArgumentException( + $"Value '{name}' is not valid for {typeof(TEnum).Name}. Valid: {string.Join(", ", Enum.GetNames(typeof(TEnum)))}."); + if (!dryRun) assign(parsed); + return true; + } + + #endregion + + #region stats + + /// + /// Collect post-bake lightmap statistics from : the + /// number of baked lightmaps, their total texture size in bytes (color maps), the atlas size, + /// the active lightmap resolution, and the baked light-probe count. + /// + static LightingBakeStats CollectStats() + { + var stats = new LightingBakeStats(); + + var maps = LightmapSettings.lightmaps; + if (maps != null) + { + stats.LightmapCount = maps.Length; + long total = 0; + int atlas = 0; + foreach (var data in maps) + { + var tex = data?.lightmapColor; + if (tex == null) + continue; + atlas = Mathf.Max(atlas, Mathf.Max(tex.width, tex.height)); + total += EstimateTextureBytes(tex); + } + stats.TotalLightmapSizeBytes = total; + stats.AtlasSize = atlas; + } + + try + { + stats.LightmapResolution = Lightmapping.lightingSettings != null + ? Lightmapping.lightingSettings.lightmapResolution + : 0f; + } + catch + { + stats.LightmapResolution = 0f; + } + + var probes = LightmapSettings.lightProbes; + stats.BakedProbeCount = probes != null ? probes.count : 0; + + return stats; + } + + /// Rough byte estimate for a baked lightmap texture (4 bytes/pixel; good enough for a size signal). + static long EstimateTextureBytes(Texture tex) + { + return (long)tex.width * tex.height * 4; + } + + #endregion + + static void WriteStatus(LightingBakeStatus status) + { + try + { + File.WriteAllText(StatusFile, JsonConvert.SerializeObject(status)); + } + catch (Exception ex) + { + Debug.LogError($"[LightingBake] Failed to write status file: {ex.Message}"); + } + } + } + + /// Status/result payload for bake_lighting / lighting_bake_status. + [Serializable] + class LightingBakeStatus + { + [JsonProperty("status")] + public string Status { get; set; } + + [JsonProperty("bakeId")] + public string BakeId { get; set; } + + [JsonProperty("result", NullValueHandling = NullValueHandling.Ignore)] + public string Result { get; set; } + + [JsonProperty("isBaking")] + public bool IsBaking { get; set; } + + [JsonProperty("bakeTimeMs")] + public int BakeTimeMs { get; set; } + + [JsonProperty("stats", NullValueHandling = NullValueHandling.Ignore)] + public LightingBakeStats Stats { get; set; } + + // Internal bookkeeping so a bake can be reconciled across a domain reload. Not part of the + // documented schema, but harmless to expose. + [JsonProperty("startedUtcTicks")] + public long StartedUtcTicks { get; set; } + } + + /// Post-bake lightmap statistics (CLI-215 acceptance: lightmapCount >= 1, bakeTimeMs > 0). + [Serializable] + class LightingBakeStats + { + [JsonProperty("lightmapCount")] + public int LightmapCount { get; set; } + + [JsonProperty("totalLightmapSizeBytes")] + public long TotalLightmapSizeBytes { get; set; } + + [JsonProperty("atlasSize")] + public int AtlasSize { get; set; } + + [JsonProperty("lightmapResolution")] + public float LightmapResolution { get; set; } + + [JsonProperty("bakedProbeCount")] + public int BakedProbeCount { get; set; } + } + + /// Result of get_lighting_settings (and the dry-run payload of bake_lighting). + [Serializable] + class LightingSettingsResult + { + /// False when no LightingSettings could be read for the active scene. + [JsonProperty("available")] + public bool Available { get; set; } + + [JsonProperty("lightmapper", NullValueHandling = NullValueHandling.Ignore)] + public string Lightmapper { get; set; } + + [JsonProperty("bakedGI")] + public bool BakedGI { get; set; } + + [JsonProperty("realtimeGI")] + public bool RealtimeGI { get; set; } + + [JsonProperty("directSampleCount")] + public int DirectSampleCount { get; set; } + + [JsonProperty("indirectSampleCount")] + public int IndirectSampleCount { get; set; } + + [JsonProperty("environmentSampleCount")] + public int EnvironmentSampleCount { get; set; } + + [JsonProperty("bounces")] + public int Bounces { get; set; } + + [JsonProperty("lightmapResolution")] + public float LightmapResolution { get; set; } + + [JsonProperty("lightmapPadding")] + public int LightmapPadding { get; set; } + + [JsonProperty("maxLightmapSize")] + public int MaxLightmapSize { get; set; } + + [JsonProperty("lightmapCompression", NullValueHandling = NullValueHandling.Ignore)] + public string LightmapCompression { get; set; } + + [JsonProperty("directionalMode", NullValueHandling = NullValueHandling.Ignore)] + public string DirectionalMode { get; set; } + + [JsonProperty("ao")] + public bool Ao { get; set; } + + [JsonProperty("aoMaxDistance")] + public float AoMaxDistance { get; set; } + + [JsonProperty("filteringMode", NullValueHandling = NullValueHandling.Ignore)] + public string FilteringMode { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/LightingBakeCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/LightingBakeCommands.cs.meta new file mode 100644 index 0000000..e8d6736 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/LightingBakeCommands.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dd7529c9d1f14ff98b9eb3e9a1e8ba5b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/NavMeshBakeCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/NavMeshBakeCommands.cs new file mode 100644 index 0000000..7fcb0ed --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/NavMeshBakeCommands.cs @@ -0,0 +1,430 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Unity.Pipeline.Commands; +using UnityEditor; +using UnityEditor.AI; +using UnityEngine; +#if UNITY_6000_5_OR_NEWER +using Unity.Scripting.LifecycleManagement; +#endif + +// CLI-215 deliberately targets the built-in legacy UnityEditor.AI.NavMeshBuilder (see class doc). It is +// [Obsolete] in Unity 6000.x (the modern path is the com.unity.ai.navigation package), but is the +// intentional v1 baker here, so suppress CS0618 file-wide rather than migrate. +#pragma warning disable CS0618 + +namespace Unity.Pipeline.Editor.Commands.Baking +{ + /// + /// CLI-215 Group B — NavMesh bake commands, targeting the built-in legacy baker + /// (always available; bakes a single scene NavMesh from + /// the Navigation-static geometry of the open scene). Trigger an async build, poll its status, + /// cancel it, clear the baked NavMesh, and read/configure the default agent's bake settings. + /// + /// The newer AI Navigation package (com.unity.ai.navigation, NavMeshSurface + /// components) is OUT for v1 — we do NOT add an asmdef reference to it. bake_navmesh_surfaces + /// is a guarded stub that probes for the package by reflection and returns + /// { code: "package_not_found" } when it is absent (full support is a follow-up). + /// + /// Async pattern mirrors / : trigger + /// returns immediately, completion is detected by flipping + /// false (polled in ), and in-flight state is held in static + /// fields reconciled against a Temp/ status file across domain reloads. + /// + [InitializeOnLoad] +#if UNITY_6000_5_OR_NEWER + [NoAutoStaticsCleanup] +#endif + static class NavMeshBakeCommands + { + const string StatusFile = "Temp/pipeline_navmesh_bake_status.json"; + + // The serialized NavMesh bake-settings live on the Navigation window's settings object, keyed by + // these property names (stable across 2019+ / Unity 6). + const string PropAgentRadius = "m_BuildSettings.agentRadius"; + const string PropAgentHeight = "m_BuildSettings.agentHeight"; + const string PropAgentSlope = "m_BuildSettings.agentSlope"; + const string PropAgentClimb = "m_BuildSettings.agentClimb"; + const string PropMinRegionArea = "m_BuildSettings.minRegionArea"; + const string PropManualCellSize = "m_BuildSettings.manualCellSize"; + const string PropCellSize = "m_BuildSettings.cellSize"; + + static readonly object s_Lock = new object(); + static bool s_Tracking; + static string s_BakeId; + static DateTime s_StartedUtc; + + static NavMeshBakeCommands() + { + OnReload(); + EditorApplication.update += OnUpdate; + } + + #region bake_navmesh + + [CliCommand("bake_navmesh", "Trigger an async legacy NavMesh bake of the open scene(s) via UnityEditor.AI.NavMeshBuilder. Returns immediately; poll navmesh_bake_status until completed.", Tags = new[] { "baking/navmesh" })] + public static object BakeNavMesh( + [CliArg("confirm", "Accepted for parity (a bake overwrites the existing NavMesh); not required.")] bool confirm = false, + [CliArg("dry_run", "If true, validate there is an open scene and return current NavMesh settings without baking.")] bool dryRun = false) + { + if (!BakeSceneGuard.HasBakeableScene()) + return BakeSceneGuard.NoSceneResult(); + + OnUpdate(); // reconcile a possibly-stale tracking flag first. + + if (NavMeshBuilder.isRunning) + return new { code = "bake_in_progress", message = "A NavMesh bake is already running. Poll navmesh_bake_status." }; + + if (dryRun) + return new { status = "dry_run", wouldBake = true, settings = ReadNavMeshSettings() }; + + var bakeId = Guid.NewGuid().ToString("N"); + lock (s_Lock) + { + s_Tracking = true; + s_BakeId = bakeId; + s_StartedUtc = DateTime.UtcNow; + } + + WriteStatus(new NavMeshBakeStatus + { + Status = "baking", + BakeId = bakeId, + StartedUtcTicks = s_StartedUtc.Ticks + }); + + NavMeshBuilder.BuildNavMeshAsync(); + return new { status = "baking", bakeId }; + } + + [CliCommand("navmesh_bake_status", "Get the status of the last NavMesh bake: idle | baking | completed.", MainThreadRequired = false, Tags = new[] { "baking/navmesh" })] + public static string NavMeshBakeStatus() + { + if (File.Exists(StatusFile)) + return File.ReadAllText(StatusFile); + return "{\"status\":\"idle\"}"; + } + + [CliCommand("cancel_navmesh_bake", "Cancel an in-progress NavMesh bake (NavMeshBuilder.Cancel()).", Tags = new[] { "baking/navmesh" })] + public static object CancelNavMeshBake() + { + var wasRunning = NavMeshBuilder.isRunning; + if (wasRunning) + NavMeshBuilder.Cancel(); + + lock (s_Lock) + { + if (s_Tracking) + { + var ms = (int)Math.Max(0, (DateTime.UtcNow - s_StartedUtc).TotalMilliseconds); + WriteStatus(new NavMeshBakeStatus + { + Status = "completed", + Result = "cancelled", + BakeId = s_BakeId, + BakeTimeMs = ms + }); + s_Tracking = false; + } + } + + return new { cancelled = wasRunning }; + } + + [CliCommand("clear_navmesh", "Clear the baked NavMesh for the open scene(s). Destructive: requires confirm=true.", Tags = new[] { "baking/navmesh" })] + public static object ClearNavMesh( + [CliArg("confirm", "Must be true to actually clear (destructive, not undoable via Unity's Undo).")] bool confirm = false, + [CliArg("dry_run", "If true, report what would be cleared without clearing.")] bool dryRun = false) + { + if (!confirm) + throw new ArgumentException("Refusing to clear the NavMesh. Pass confirm=true (destructive, not undoable via Unity's Undo)."); + + if (dryRun) + return new { status = "dry_run", wouldClear = true }; + + NavMeshBuilder.ClearAllNavMeshes(); + return new { cleared = true }; + } + + #endregion + + #region settings + + [CliCommand("get_navmesh_settings", "Read the default agent's legacy NavMesh bake settings (agentRadius/Height/Slope/Climb, minRegionArea, voxelSize).", Tags = new[] { "baking/navmesh" })] + public static NavMeshSettingsResult GetNavMeshSettings() + { + return ReadNavMeshSettings(); + } + + [CliCommand("set_navmesh_settings", "Apply a subset of legacy NavMesh bake settings to the default agent. Returns { applied[], unknown[] }.", Tags = new[] { "baking/navmesh" })] + public static object SetNavMeshSettings( + [CliArg("settings", "JSON object with a subset of NavMesh fields to set (same names as get_navmesh_settings).", Required = true)] JObject settings, + [CliArg("dry_run", "If true, validate the keys and report applied/unknown without changing anything.")] bool dryRun = false) + { + if (settings == null) + throw new ArgumentException("settings is required (a JSON object of NavMesh fields to set)."); + + // NavMeshBuilder.navMeshSettingsObject is a UnityEngine.Object (the Navigation window's + // settings holder); wrap it in a SerializedObject to read/write the m_BuildSettings fields. + var settingsObject = NavMeshBuilder.navMeshSettingsObject; + if (settingsObject == null) + return new { code = "settings_unavailable", message = "Could not access the legacy NavMesh settings object." }; + + var so = new SerializedObject(settingsObject); + so.Update(); + + var applied = new List(); + var unknown = new List(); + + foreach (var prop in settings.Properties()) + { + if (TryApply(so, prop.Name, prop.Value, dryRun)) + applied.Add(prop.Name); + else + unknown.Add(prop.Name); + } + + if (!dryRun && applied.Count > 0) + so.ApplyModifiedPropertiesWithoutUndo(); + + return new { applied = applied.ToArray(), unknown = unknown.ToArray(), dryRun }; + } + + /// + /// Guarded stub for the AI Navigation package (com.unity.ai.navigation) NavMeshSurface + /// bake path. We never reference that assembly, so probe for the type by reflection; absent → the + /// documented package_not_found result. Full multi-surface baking is a follow-up. + /// + [CliCommand("bake_navmesh_surfaces", "Bake NavMeshSurface components (AI Navigation package). v1 stub: returns package_not_found when the package is absent.", Tags = new[] { "baking/navmesh" })] + public static object BakeNavMeshSurfaces() + { + var surfaceType = Type.GetType("Unity.AI.Navigation.NavMeshSurface, Unity.AI.Navigation") + ?? Type.GetType("UnityEngine.AI.NavMeshSurface, Unity.AI.Navigation"); + + if (surfaceType == null) + return new + { + code = "package_not_found", + message = "The AI Navigation package (com.unity.ai.navigation) is not installed. " + + "NavMeshSurface-based baking is out of scope for v1; use bake_navmesh for the built-in baker." + }; + + return new + { + code = "not_implemented", + message = "AI Navigation package detected, but NavMeshSurface baking is not implemented in v1 (follow-up). Use bake_navmesh." + }; + } + + #endregion + + #region completion / reload bookkeeping + + static void OnUpdate() + { + lock (s_Lock) + { + if (s_Tracking && !NavMeshBuilder.isRunning) + Finish("succeeded"); + } + } + + // Must be called under s_Lock. + static void Finish(string result) + { + var ms = (int)Math.Max(0, (DateTime.UtcNow - s_StartedUtc).TotalMilliseconds); + WriteStatus(new NavMeshBakeStatus + { + Status = "completed", + Result = result, + BakeId = s_BakeId, + BakeTimeMs = ms + }); + s_Tracking = false; + } + + static void OnReload() + { + if (!File.Exists(StatusFile)) + return; + + NavMeshBakeStatus prior; + try + { + prior = JsonConvert.DeserializeObject(File.ReadAllText(StatusFile)); + } + catch + { + return; + } + + if (prior == null || prior.Status != "baking") + return; + + lock (s_Lock) + { + s_BakeId = prior.BakeId; + s_StartedUtc = prior.StartedUtcTicks > 0 ? new DateTime(prior.StartedUtcTicks, DateTimeKind.Utc) : DateTime.UtcNow; + s_Tracking = true; + if (!NavMeshBuilder.isRunning) + Finish("succeeded"); + } + } + + #endregion + + #region settings read/write helpers + + static NavMeshSettingsResult ReadNavMeshSettings() + { + var settingsObject = NavMeshBuilder.navMeshSettingsObject; + if (settingsObject == null) + return new NavMeshSettingsResult { Available = false }; + + var so = new SerializedObject(settingsObject); + so.Update(); + var manual = FindBool(so, PropManualCellSize, false); + return new NavMeshSettingsResult + { + Available = true, + AgentRadius = FindFloat(so, PropAgentRadius, 0.5f), + AgentHeight = FindFloat(so, PropAgentHeight, 2f), + AgentSlope = FindFloat(so, PropAgentSlope, 45f), + AgentClimb = FindFloat(so, PropAgentClimb, 0.4f), + MinRegionArea = FindFloat(so, PropMinRegionArea, 2f), + VoxelSize = FindFloat(so, PropCellSize, 0f), + ManualVoxelSize = manual + }; + } + + static bool TryApply(SerializedObject so, string key, JToken value, bool dryRun) + { + switch (key) + { + case "agentRadius": + return SetFloat(so, PropAgentRadius, value, dryRun); + case "agentHeight": + return SetFloat(so, PropAgentHeight, value, dryRun); + case "agentSlope": + return SetFloat(so, PropAgentSlope, value, dryRun); + case "agentClimb": + return SetFloat(so, PropAgentClimb, value, dryRun); + case "minRegionArea": + return SetFloat(so, PropMinRegionArea, value, dryRun); + case "voxelSize": + // Setting an explicit voxel size implies manual override on. + { + var ok = SetFloat(so, PropCellSize, value, dryRun); + if (ok && !dryRun) + { + var manual = so.FindProperty(PropManualCellSize); + if (manual != null) manual.boolValue = true; + } + return ok; + } + case "manualVoxelSize": + return SetBool(so, PropManualCellSize, value, dryRun); + default: + return false; + } + } + + static bool SetFloat(SerializedObject so, string propPath, JToken value, bool dryRun) + { + var prop = so.FindProperty(propPath); + if (prop == null) + return false; + var f = value.Value(); + if (!dryRun) prop.floatValue = f; + return true; + } + + static bool SetBool(SerializedObject so, string propPath, JToken value, bool dryRun) + { + var prop = so.FindProperty(propPath); + if (prop == null) + return false; + var b = value.Value(); + if (!dryRun) prop.boolValue = b; + return true; + } + + static float FindFloat(SerializedObject so, string propPath, float fallback) + { + var prop = so.FindProperty(propPath); + return prop != null ? prop.floatValue : fallback; + } + + static bool FindBool(SerializedObject so, string propPath, bool fallback) + { + var prop = so.FindProperty(propPath); + return prop != null ? prop.boolValue : fallback; + } + + #endregion + + static void WriteStatus(NavMeshBakeStatus status) + { + try + { + File.WriteAllText(StatusFile, JsonConvert.SerializeObject(status)); + } + catch (Exception ex) + { + Debug.LogError($"[NavMeshBake] Failed to write status file: {ex.Message}"); + } + } + } + + /// Status/result payload for bake_navmesh / navmesh_bake_status. + [Serializable] + class NavMeshBakeStatus + { + [JsonProperty("status")] + public string Status { get; set; } + + [JsonProperty("bakeId")] + public string BakeId { get; set; } + + [JsonProperty("result", NullValueHandling = NullValueHandling.Ignore)] + public string Result { get; set; } + + [JsonProperty("bakeTimeMs")] + public int BakeTimeMs { get; set; } + + [JsonProperty("startedUtcTicks")] + public long StartedUtcTicks { get; set; } + } + + /// Result of get_navmesh_settings (default-agent legacy bake settings). + [Serializable] + class NavMeshSettingsResult + { + [JsonProperty("available")] + public bool Available { get; set; } + + [JsonProperty("agentRadius")] + public float AgentRadius { get; set; } + + [JsonProperty("agentHeight")] + public float AgentHeight { get; set; } + + [JsonProperty("agentSlope")] + public float AgentSlope { get; set; } + + [JsonProperty("agentClimb")] + public float AgentClimb { get; set; } + + [JsonProperty("minRegionArea")] + public float MinRegionArea { get; set; } + + [JsonProperty("voxelSize")] + public float VoxelSize { get; set; } + + [JsonProperty("manualVoxelSize")] + public bool ManualVoxelSize { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/NavMeshBakeCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/NavMeshBakeCommands.cs.meta new file mode 100644 index 0000000..a3be55d --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/NavMeshBakeCommands.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5173e39c97c44308ad4b80462eaf7982 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/OcclusionBakeCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/OcclusionBakeCommands.cs new file mode 100644 index 0000000..19503c4 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/OcclusionBakeCommands.cs @@ -0,0 +1,271 @@ +using System; +using System.IO; +using Newtonsoft.Json; +using Unity.Pipeline.Commands; +using UnityEditor; +using UnityEngine; +#if UNITY_6000_5_OR_NEWER +using Unity.Scripting.LifecycleManagement; +#endif + +namespace Unity.Pipeline.Editor.Commands.Baking +{ + /// + /// CLI-215 Group C — Occlusion Culling bake commands. Trigger an async occlusion bake of the open + /// scene(s) via , poll its status, cancel + /// it, and clear the baked occlusion data. + /// + /// Async pattern mirrors / : trigger + /// returns immediately; completion is detected by + /// flipping false (polled in ); in-flight state is held in + /// static fields and reconciled against a Temp/ status file across domain reloads. + /// + [InitializeOnLoad] +#if UNITY_6000_5_OR_NEWER + [NoAutoStaticsCleanup] +#endif + static class OcclusionBakeCommands + { + const string StatusFile = "Temp/pipeline_occlusion_bake_status.json"; + + // Sentinel for "argument omitted" on the float bake parameters. float.NaN is not a + // compile-time constant (so it can't be a default parameter value), but float.MinValue is, and + // it is not a plausible real value for any of these positive bake parameters. + const float Unset = float.MinValue; + + static readonly object s_Lock = new object(); + static bool s_Tracking; + static string s_BakeId; + static DateTime s_StartedUtc; + + static OcclusionBakeCommands() + { + OnReload(); + EditorApplication.update += OnUpdate; + } + + #region bake_occlusion_culling + + [CliCommand("bake_occlusion_culling", "Trigger an async occlusion-culling bake of the open scene(s) via StaticOcclusionCulling.GenerateInBackground(). Returns immediately; poll occlusion_bake_status until completed.", Tags = new[] { "baking/occlusion" })] + public static object BakeOcclusionCulling( + [CliArg("smallest_occluder", "Smallest object that will occlude others (meters). Defaults to Unity's current value.")] float smallestOccluder = Unset, + [CliArg("smallest_hole", "Smallest gap geometry can have that the view can see through (meters). Defaults to Unity's current value.")] float smallestHole = Unset, + [CliArg("backface_threshold", "Backface threshold (1-100); lower trims more backfaces. Defaults to Unity's current value.")] float backfaceThreshold = Unset, + [CliArg("confirm", "Accepted for parity (a bake overwrites existing occlusion data); not required.")] bool confirm = false, + [CliArg("dry_run", "If true, validate there is an open scene and report the parameters that would be used without baking.")] bool dryRun = false) + { + if (!BakeSceneGuard.HasBakeableScene()) + return BakeSceneGuard.NoSceneResult(); + + OnUpdate(); // reconcile any stale tracking flag first. + + if (StaticOcclusionCulling.isRunning) + return new { code = "bake_in_progress", message = "An occlusion bake is already running. Poll occlusion_bake_status." }; + + // Validate explicitly provided values before resolving. An omitted arg is the Unset + // sentinel (float.MinValue); NaN is never <= Unset, so a NaN arg is treated as provided + // and rejected here. smallest_occluder / smallest_hole must be positive; backface_threshold + // is documented as 1-100. + if (!IsOmitted(smallestOccluder) && !(smallestOccluder > 0f)) + throw new ArgumentException($"smallest_occluder must be greater than 0 (got {smallestOccluder})."); + if (!IsOmitted(smallestHole) && !(smallestHole > 0f)) + throw new ArgumentException($"smallest_hole must be greater than 0 (got {smallestHole})."); + if (!IsOmitted(backfaceThreshold) && !(backfaceThreshold >= 1f && backfaceThreshold <= 100f)) + throw new ArgumentException($"backface_threshold must be between 1 and 100 (got {backfaceThreshold})."); + + // Resolve effective parameters: an omitted arg (the Unset sentinel) keeps Unity's current value. + var occluder = IsOmitted(smallestOccluder) ? StaticOcclusionCulling.smallestOccluder : smallestOccluder; + var hole = IsOmitted(smallestHole) ? StaticOcclusionCulling.smallestHole : smallestHole; + var backface = IsOmitted(backfaceThreshold) ? StaticOcclusionCulling.backfaceThreshold : backfaceThreshold; + + if (dryRun) + { + return new + { + status = "dry_run", + wouldBake = true, + parameters = new { smallestOccluder = occluder, smallestHole = hole, backfaceThreshold = backface } + }; + } + + // Apply the (possibly overridden) bake parameters before generating. + StaticOcclusionCulling.smallestOccluder = occluder; + StaticOcclusionCulling.smallestHole = hole; + StaticOcclusionCulling.backfaceThreshold = backface; + + var bakeId = Guid.NewGuid().ToString("N"); + lock (s_Lock) + { + s_Tracking = true; + s_BakeId = bakeId; + s_StartedUtc = DateTime.UtcNow; + } + + WriteStatus(new OcclusionBakeStatus + { + Status = "baking", + BakeId = bakeId, + StartedUtcTicks = s_StartedUtc.Ticks + }); + + StaticOcclusionCulling.GenerateInBackground(); + return new { status = "baking", bakeId }; + } + + [CliCommand("occlusion_bake_status", "Get the status of the last occlusion bake: idle | baking | completed.", MainThreadRequired = false, Tags = new[] { "baking/occlusion" })] + public static string OcclusionBakeStatus() + { + if (File.Exists(StatusFile)) + return File.ReadAllText(StatusFile); + return "{\"status\":\"idle\"}"; + } + + [CliCommand("cancel_occlusion_bake", "Cancel an in-progress occlusion bake (StaticOcclusionCulling.Cancel()).", Tags = new[] { "baking/occlusion" })] + public static object CancelOcclusionBake() + { + var wasRunning = StaticOcclusionCulling.isRunning; + if (wasRunning) + StaticOcclusionCulling.Cancel(); + + lock (s_Lock) + { + if (s_Tracking) + { + var ms = (int)Math.Max(0, (DateTime.UtcNow - s_StartedUtc).TotalMilliseconds); + WriteStatus(new OcclusionBakeStatus + { + Status = "completed", + Result = "cancelled", + BakeId = s_BakeId, + BakeTimeMs = ms + }); + s_Tracking = false; + } + } + + return new { cancelled = wasRunning }; + } + + [CliCommand("clear_occlusion_culling", "Clear baked occlusion-culling data for the open scene(s). Destructive: requires confirm=true.", Tags = new[] { "baking/occlusion" })] + public static object ClearOcclusionCulling( + [CliArg("confirm", "Must be true to actually clear (destructive, not undoable via Unity's Undo).")] bool confirm = false, + [CliArg("dry_run", "If true, report what would be cleared without clearing.")] bool dryRun = false) + { + if (!confirm) + throw new ArgumentException("Refusing to clear occlusion culling data. Pass confirm=true (destructive, not undoable via Unity's Undo)."); + + if (dryRun) + return new { status = "dry_run", wouldClear = true }; + + StaticOcclusionCulling.Clear(); + return new { cleared = true }; + } + + // True when the caller omitted a float bake arg (left it at the Unset sentinel). NaN is never + // <= Unset, so NaN counts as provided and is caught by the range validation above. + static bool IsOmitted(float value) => value <= Unset; + + #endregion + + #region completion / reload bookkeeping + + static void OnUpdate() + { + lock (s_Lock) + { + if (s_Tracking && !StaticOcclusionCulling.isRunning) + Finish("succeeded"); + } + } + + // Must be called under s_Lock. + static void Finish(string result) + { + var ms = (int)Math.Max(0, (DateTime.UtcNow - s_StartedUtc).TotalMilliseconds); + WriteStatus(new OcclusionBakeStatus + { + Status = "completed", + Result = result, + BakeId = s_BakeId, + BakeTimeMs = ms, + Stats = result == "succeeded" + ? new OcclusionBakeStats { UmbraDataSizeBytes = StaticOcclusionCulling.umbraDataSize } + : null + }); + s_Tracking = false; + } + + static void OnReload() + { + if (!File.Exists(StatusFile)) + return; + + OcclusionBakeStatus prior; + try + { + prior = JsonConvert.DeserializeObject(File.ReadAllText(StatusFile)); + } + catch + { + return; + } + + if (prior == null || prior.Status != "baking") + return; + + lock (s_Lock) + { + s_BakeId = prior.BakeId; + s_StartedUtc = prior.StartedUtcTicks > 0 ? new DateTime(prior.StartedUtcTicks, DateTimeKind.Utc) : DateTime.UtcNow; + s_Tracking = true; + if (!StaticOcclusionCulling.isRunning) + Finish("succeeded"); + } + } + + #endregion + + static void WriteStatus(OcclusionBakeStatus status) + { + try + { + File.WriteAllText(StatusFile, JsonConvert.SerializeObject(status)); + } + catch (Exception ex) + { + Debug.LogError($"[OcclusionBake] Failed to write status file: {ex.Message}"); + } + } + } + + /// Status/result payload for bake_occlusion_culling / occlusion_bake_status. + [Serializable] + class OcclusionBakeStatus + { + [JsonProperty("status")] + public string Status { get; set; } + + [JsonProperty("bakeId")] + public string BakeId { get; set; } + + [JsonProperty("result", NullValueHandling = NullValueHandling.Ignore)] + public string Result { get; set; } + + [JsonProperty("bakeTimeMs")] + public int BakeTimeMs { get; set; } + + [JsonProperty("stats", NullValueHandling = NullValueHandling.Ignore)] + public OcclusionBakeStats Stats { get; set; } + + [JsonProperty("startedUtcTicks")] + public long StartedUtcTicks { get; set; } + } + + /// Post-bake occlusion statistics (umbra data size in bytes). + [Serializable] + class OcclusionBakeStats + { + [JsonProperty("umbraDataSizeBytes")] + public long UmbraDataSizeBytes { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/OcclusionBakeCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/OcclusionBakeCommands.cs.meta new file mode 100644 index 0000000..eb800ab --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Baking/OcclusionBakeCommands.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 00b06ed57bce4c0bb281527e016889dd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch.meta new file mode 100644 index 0000000..6155104 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2b9ea99052584c228968a32f1c614458 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchCommand.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchCommand.cs new file mode 100644 index 0000000..3f3afa4 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchCommand.cs @@ -0,0 +1,660 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor.Authoring; +using UnityEditor; +#if UNITY_6000_5_OR_NEWER +using Unity.Scripting.LifecycleManagement; +#endif + +namespace Unity.Pipeline.Editor.Commands.Batch +{ + /// + /// The batch command (AUTHAPI-27): transactional multi-operation execution with cross-op + /// result references, atomic Undo, and dry-run. + /// + /// WHY it exists: a "create → add components → wire fields" job is otherwise 10–90 sequential + /// calls at ~0.8s each, and eval — the only alternative today — leaves partial state when it + /// throws mid-way, which is unacceptable on user-owned scenes. batch collapses the round + /// trips AND adds what eval structurally lacks: atomicity/rollback, dry-run validation, and + /// cross-step references. + /// + /// Scope guard (epic AUTHAPI-24 design principle): batch is transactional object CRUD with + /// references. It deliberately has NO invoke/loop/conditional op types — that path reinvents + /// eval inside JSON and collapses the auditability story. Arbitrary logic belongs in + /// run_script (code as files on disk), not here. + /// + /// Dispatch reuse: each sub-operation runs through + /// , the exact parameter + /// extraction / required-validation / reflection-invoke path /api/exec uses, so every per-op + /// result is shaped identically to running that command standalone. + /// + /// Atomicity: the whole batch runs inside one , so all ops + /// (each of which registers its own Undo operations) collapse into a single Editor Undo step. When + /// transactional (the default) and an op fails under on_error=abort, every applied op + /// is reverted with — the scene returns to its + /// pre-batch state and there is nothing left on the Undo stack. Rollback is only real for + /// Undo-tracked mutations, which is why commands that mutate state OUTSIDE the Undo system + /// () are rejected in a transactional batch — see that field's + /// doc for the v1 caveat. + /// + /// Timing: the batch executes in a single main-thread turn (no frame-spanning), so the + /// Editor UI is frozen for its duration. time_budget_ms is the cooperative bound on that + /// freeze: the elapsed time is checked before each operation after the first, and when the budget + /// is exhausted the remaining ops are skipped and a transactional batch rolls back. Long batches + /// should be submitted as detached jobs ("job": true) — cancellation is checked between + /// ops, and per-op progress is reported via . + /// +#if UNITY_6000_5_OR_NEWER + [NoAutoStaticsCleanup] +#endif + static class BatchCommand + { + /// Hard cap on operations per batch (payload bound). + private const int MaxOperations = 200; + + /// Default cooperative time budget for one batch execution (see ). + private const int DefaultTimeBudgetMs = 50_000; + + /// Upper bound on time_budget_ms (1 hour). + private const int MaxTimeBudgetMs = 3_600_000; + + /// + /// Per-op result size (serialized UTF-8 BYTES — what actually goes on the wire, not UTF-16 + /// chars, which undercount CJK/emoji-heavy payloads 3x) above which the result is replaced + /// by a truncation marker so a large sub-result cannot bloat the batch envelope. + /// + private const int MaxPerOpResultBytes = 16 * 1024; + + /// + /// Aggregate budget for ALL per-op results in one batch response (UTF-8 bytes). Bounds the + /// whole envelope: 200 ops each just under the per-op cap would otherwise produce a ~3.2 MB + /// reply. Once exhausted, later results are replaced by truncation markers (the ops still + /// execute normally — only the echoed result payload is elided). + /// + internal const int MaxBatchResultBytes = 256 * 1024; + + /// + /// Operation ids must look like identifiers: they may not be purely numeric (a numeric id + /// would be ambiguous with a 0-based index in a "$<id-or-index>" reference) and + /// may not contain '.' (the reference path separator). + /// + private static readonly Regex m_IdPattern = new Regex("^[A-Za-z_][A-Za-z0-9_-]*$", RegexOptions.Compiled); + + /// + /// Commands excluded from batch (structured not_batchable error). These either escape + /// the "object CRUD with references" scope (build/platform/package/play-mode/recompile), carry + /// arbitrary code that belongs in run_script (eval/eval_file/run_script), + /// can pop modal dialogs that wedge an unattended batch (menu), or would nest a batch + /// inside a batch. (The ticket names eval; eval_file is its file-based twin and + /// is excluded on the same grounds.) + /// + private static readonly HashSet m_ExcludedCommands = new HashSet(StringComparer.Ordinal) + { + "build", "switch_build_target", + "editor_play", "editor_stop", "editor_pause", + "recompile", "eval", "eval_file", "run_script", "menu", "batch", + // A synchronous wait inside a batch cannot make progress: the batch holds the main + // thread for its whole turn, so the editor state the condition watches cannot change — + // the wait just burns its full timeout inside the batch. Use an async wait_for before + // or after the batch instead. (wait_status/wait_cancel are quick reads and stay + // batchable.) + "wait_for" + }; + + /// Excluded command families matched by name prefix (e.g. all package_*). + private static readonly string[] m_ExcludedPrefixes = { "package_" }; + + /// + /// Commands that CLEAR the Editor Undo stack, destroying the batch's ability to revert any + /// prior operation. Always rejected inside a batch (even with transactional=false the + /// single-Undo-step contract would silently break). + /// + /// V1 CAVEAT: like below, this is a curated list — + /// any new command that clears or truncates the Undo stack must be added here, or it will + /// silently break the revert-integrity contract. The durable fix is command-site metadata + /// ([CliCommand(Revertible = ...)]). + /// + private static readonly HashSet m_UndoStackWipingCommands = new HashSet(StringComparer.Ordinal) + { + "open_scene", "create_scene" + }; + + /// + /// Commands whose mutations live OUTSIDE the Editor Undo system — asset/file writes + /// (AssetDatabase / File IO), scene saves, Build Settings, project settings — so + /// cannot roll them back. In a transactional + /// batch they are rejected (not_batchable_transactional): allowing them would make + /// reverted: true a lie. With transactional=false they run, and their per-op + /// result reports revertible: false. + /// + /// V1 CAVEAT: this is a curated list, assembled by auditing each command's + /// implementation (AssetDatabase.SaveAssets / File writes / settings assets). The durable fix + /// is a [CliCommand(Revertible = ...)] metadata flag declared at the command site so + /// new commands can't silently fall through; until then, new non-Undo-tracked commands must + /// be added here. + /// + private static readonly HashSet m_NonRevertibleCommands = new HashSet(StringComparer.Ordinal) + { + // Assets & files (AssetDatabase ops / direct file IO). + "create_asset", "import_asset", "move_asset", "copy_asset", "rename_asset", "delete_asset", + "create_folder", "set_import_settings", "write_text_file", "create_script", + // Prefab ASSET writes (scene-side prefab ops — instantiate/unpack/revert overrides — are + // Undo-tracked and stay batchable). + "create_prefab", "create_prefab_variant", "apply_prefab_overrides", "save_prefab_contents", + // Scene persistence and Build Settings scene list. + "save_scene", "save_all", "add_scene_to_build", "remove_scene_from_build", "set_build_settings", + // Project settings (their own descriptions say "Not undoable via Ctrl+Z"). + "set_audio_settings", "set_graphics_settings", "set_input_settings", "set_lighting_settings", + "set_navmesh_settings", "set_physics_settings", "set_player_settings", "set_quality_settings", + "set_tags_layers", "set_time_settings", "set_authoring_root", + // Animation / Animator / Timeline commands persist their asset with AssetDatabase.SaveAssets. + "create_animation_clip", "set_animation_curve", "remove_animation_curve", + "create_animator_controller", "add_animator_layer", "add_animator_parameter", + "add_animator_state", "add_animator_transition", + "create_timeline", "add_timeline_track", "add_timeline_clip", + // Persists the .mat asset with AssetDatabase.SaveAssetIfDirty (the in-memory change is + // Undo-recorded, but the disk write is not reverted by Undo). + "set_material_properties", + // Baking writes/deletes baked data on disk (GI / NavMesh / occlusion). + "bake_lighting", "clear_baked_lighting", + "bake_navmesh", "bake_navmesh_surfaces", "clear_navmesh", + "bake_occlusion_culling", "clear_occlusion_culling" + }; + + [CliCommand("batch", + "Run multiple registered commands in one transactional request. Later ops can reference earlier " + + "results with \"$.\" (e.g. \"$0.instanceId\"; \"$$\" escapes a literal '$'). " + + "transactional=true (default) groups every op into one Undo step and reverts all applied ops if any " + + "op fails; commands that mutate outside the Undo system (asset/file/settings writes) are rejected " + + "unless transactional=false. on_error=abort|continue (continue forces transactional=false); dry_run " + + "validates without mutating; time_budget_ms (default 50000) bounds execution — when exceeded the " + + "remaining ops are skipped and a transactional batch rolls back (submit long batches with " + + "\"job\": true). Excludes build, switch_build_target, package_*, editor_play/stop/pause, recompile, " + + "eval, eval_file, run_script, menu, open_scene/create_scene, async commands (run_tests/list_tests), " + + "runtime-only commands, and nested batch.", + MainThreadRequired = true, + Tags = new[] { "batch" })] + public static BatchResult Batch( + [CliArg("operations", "Ordered operations to run; each is { id?, command, params }. Max 200.", Required = true)] List operations = null, + [CliArg("transactional", "Group all ops into one Undo step and revert every applied op if any op fails. Default true. Forced false when on_error=continue. Rejects commands whose mutations Undo cannot revert (asset/file/settings writes).")] bool transactional = true, + [CliArg("on_error", "abort (default): stop at the first failing op. continue: run every op, collecting per-op errors (forces transactional=false).")] string onError = "abort", + [CliArg("dry_run", "Validate command names, parameters, reference topology and excluded commands without mutating anything.")] bool dryRun = false, + [CliArg("result_fields", "Optional per-op result projection: map of op id-or-index -> array of result field paths to keep (context economy).")] JObject resultFields = null, + [CliArg("time_budget_ms", "Cooperative time budget for the whole batch in milliseconds (default 50000, max 3600000). Checked before each op after the first; when exhausted the remaining ops are skipped and a transactional batch rolls back. Use \"job\": true for long batches.")] int timeBudgetMs = DefaultTimeBudgetMs) + { + if (operations == null || operations.Count == 0) + throw new ArgumentException("batch 'operations' must contain at least one operation."); + if (operations.Count > MaxOperations) + throw new ArgumentException( + $"batch supports at most {MaxOperations} operations, but {operations.Count} were provided."); + if (timeBudgetMs < 0 || timeBudgetMs > MaxTimeBudgetMs) + throw new ArgumentException( + $"batch 'time_budget_ms' must be between 0 and {MaxTimeBudgetMs}, got {timeBudgetMs}."); + + onError = string.IsNullOrWhiteSpace(onError) ? "abort" : onError.Trim().ToLowerInvariant(); + if (onError != "abort" && onError != "continue") + throw new ArgumentException($"batch 'on_error' must be 'abort' or 'continue', got '{onError}'."); + + // "continue" collects per-op errors and applies the independent ops, so it cannot also + // promise an all-or-nothing rollback — it forces transactional off (per the ticket). + var effectiveTransactional = transactional && onError != "continue"; + + var idToIndex = BuildAndValidateIdIndex(operations); + + if (dryRun) + return DryRun(operations, idToIndex, effectiveTransactional, onError); + + return Execute(operations, idToIndex, effectiveTransactional, onError, resultFields, timeBudgetMs); + } + + /// + /// Validate operation ids (well-formed and unique when supplied) and build the id → index map + /// used to resolve "$id.field" references. + /// + private static Dictionary BuildAndValidateIdIndex(List operations) + { + var idToIndex = new Dictionary(StringComparer.Ordinal); + for (int i = 0; i < operations.Count; i++) + { + var op = operations[i]; + if (op == null) + throw new ArgumentException($"batch operation at index {i} is null."); + if (op.Id == null) + continue; + if (!m_IdPattern.IsMatch(op.Id)) + throw new ArgumentException( + $"batch operation id '{op.Id}' (index {i}) is invalid: ids must match " + + "^[A-Za-z_][A-Za-z0-9_-]*$ (start with a letter or '_'; letters, digits, '_' or '-' " + + "after). Purely numeric ids would be ambiguous with 0-based index selectors in " + + "\"$\" references, and '.' collides with the reference path separator."); + if (idToIndex.ContainsKey(op.Id)) + throw new ArgumentException( + $"batch operation id '{op.Id}' is used more than once; ids must be unique within a batch."); + idToIndex[op.Id] = i; + } + return idToIndex; + } + + /// + /// Execute the batch: run each op (resolving its references against earlier results) inside one + /// Undo group, and on a transactional abort revert every applied op. Between ops, cooperative + /// cancellation and the time budget are checked, and per-op progress is reported. + /// + private static BatchResult Execute(List operations, Dictionary idToIndex, + bool transactional, string onError, JObject resultFields, int timeBudgetMs) + { + var server = BasePipelineServer.CurrentServer; + if (server == null) + throw new InvalidOperationException( + "batch must run inside a pipeline server request (no active server on this thread)."); + + var result = new BatchResult { Transactional = transactional, OnError = onError }; + // One name-indexed lookup per batch call instead of an O(commands) scan per op. + var commandsByName = BuildCommandIndex(); + var resultsByIndex = new JToken[operations.Count]; + var stoppedAt = -1; // index of the op that failed under on_error=abort + var skippedFrom = -1; // first op never attempted because of a batch-level abort (budget/cancel) + var stopwatch = System.Diagnostics.Stopwatch.StartNew(); + + var remainingResultBytes = MaxBatchResultBytes; + + using (var undoScope = new AuthoringUndoScope("batch")) + { + var batchGroup = Undo.GetCurrentGroup(); + result.UndoGroup = batchGroup; + + for (int i = 0; i < operations.Count; i++) + { + // Cooperative cancellation (detached jobs: POST /api/job/cancel) — abort between + // ops and let the transactional rollback below restore the pre-batch state. + if (PipelineCancellation.IsCancellationRequested) + { + result.Error = "batch canceled: cooperative cancellation was requested; " + + (transactional ? "applied operations were reverted and " : "") + + "remaining operations were skipped."; + skippedFrom = i; + break; + } + + // Cooperative time budget: the batch holds the main thread for its whole duration, + // so this is the bound on how long the Editor stays frozen. Op 0 always gets to + // run; every later op requires remaining budget. + if (i > 0 && stopwatch.ElapsedMilliseconds >= timeBudgetMs) + { + result.Error = $"batch time budget exceeded: {stopwatch.ElapsedMilliseconds}ms elapsed " + + $"after {i} of {operations.Count} operations (time_budget_ms={timeBudgetMs}). " + + (transactional ? "Applied operations were reverted and remaining operations were skipped. " + : "Remaining operations were skipped. ") + + "For long batches submit the request with \"job\": true and a larger time_budget_ms."; + skippedFrom = i; + break; + } + + var op = operations[i]; + CliProgress.Report("batch", $"op {i + 1}/{operations.Count}: {op.Command}", + i, operations.Count, i / (double)operations.Count); + + var opResult = new BatchOperationResult { Id = op.Id, Command = op.Command }; + result.Results.Add(opResult); + + try + { + var command = ResolveBatchable(op.Command, transactional, commandsByName); + opResult.Revertible = !m_NonRevertibleCommands.Contains(op.Command); + var resolvedParams = BatchReferenceResolver.Resolve( + op.Params, i, operations, idToIndex, resultsByIndex, result.Results); + + // Dispatched WITHOUT re-checking the server's busy gate (GetBusyReason): + // the batch itself was admitted through it in HandleExecRequest, the settle + // gate is a one-way latch that never re-arms mid-session, and the batch + // holds the main thread for its entire turn — the Editor cannot transition + // into a busy state between two ops of the same batch. + var raw = server.DispatchCommandOnMainThread(command, resolvedParams); + + // Capture the result as a token for later references. A serialization failure + // here must NOT fail an op that already ran — leave the slot null (a later + // reference into it will error clearly) and still report success. + try + { + resultsByIndex[i] = raw == null ? JValue.CreateNull() : JToken.FromObject(raw); + } + catch + { + resultsByIndex[i] = null; + } + + opResult.Success = true; + opResult.Result = ProjectResult(raw, resultsByIndex[i], op, i, resultFields, opResult, ref remainingResultBytes); + result.Applied++; + } + catch (Exception ex) + { + opResult.Success = false; + opResult.Error = ex.Message; + + if (onError == "abort") + { + stoppedAt = i; + break; + } + // on_error=continue: keep going with the remaining independent ops. + } + } + + if ((stoppedAt >= 0 || skippedFrom >= 0) && transactional) + { + // Revert every mutation registered since the batch started — one atomic rollback + // to the pre-batch state (nothing is left on the Undo stack). Deliberately NOT + // conditioned on Applied > 0: a FIRST op that partially mutates and then throws + // has registered exactly the Undo operations this revert must unwind, and + // reverting an empty group is harmless. + Undo.RevertAllDownToGroup(batchGroup); + result.Reverted = true; + // The revert discarded batchGroup from the Undo stack; the scope must not + // collapse a group id that no longer refers to this batch's operations. + undoScope.Cancel(); + } + } + + // Record the operations that were never attempted because the batch aborted (op failure + // under on_error=abort, cancellation, or an exhausted time budget), so the caller can see + // exactly where it stopped. + var firstSkipped = skippedFrom >= 0 ? skippedFrom + : stoppedAt >= 0 ? stoppedAt + 1 + : operations.Count; + for (int j = firstSkipped; j < operations.Count; j++) + { + result.Results.Add(new BatchOperationResult + { + Id = operations[j].Id, + Command = operations[j].Command, + Success = false, + Skipped = true + }); + } + + return result; + } + + /// + /// Validate every operation without executing any of it: command names, that no excluded / + /// non-batchable command is used (including the transactional non-revertible rejection), + /// unknown/missing parameters, and reference topology (unknown/forward refs). Mutates nothing. + /// + private static BatchResult DryRun(List operations, Dictionary idToIndex, + bool transactional, string onError) + { + var result = new BatchResult + { + DryRun = true, + Valid = true, + Transactional = transactional, + OnError = onError + }; + var commandsByName = BuildCommandIndex(); + + for (int i = 0; i < operations.Count; i++) + { + var op = operations[i]; + var opResult = new BatchOperationResult { Id = op.Id, Command = op.Command }; + result.Results.Add(opResult); + + try + { + var command = ResolveBatchable(op.Command, transactional, commandsByName); + opResult.Revertible = !m_NonRevertibleCommands.Contains(op.Command); + ValidateKnownParameters(command, op.Params); + ValidateRequiredParameters(command, op.Params); + BatchReferenceResolver.Validate(op.Params, i, operations, idToIndex); + opResult.Success = true; // would run + } + catch (Exception ex) + { + opResult.Success = false; + opResult.Error = ex.Message; + result.Valid = false; + } + } + + return result; + } + + /// + /// Resolve a command name to its , rejecting non-batchable commands: + /// the excluded list (not_batchable), Undo-stack-wiping scene loads, runtime-only + /// commands, async (Task-returning) commands — which are completed by + /// EditorApplication.update callbacks that can never fire while the batch holds the + /// main thread, so awaiting them inline would freeze the Editor permanently — and, when + /// , commands whose mutations Undo cannot revert + /// (not_batchable_transactional). Unknown commands get an unknown command error. + /// Uses the registry directly (no server-side logging) so dry-run validation of an + /// intentionally bad name stays quiet. + /// + /// + /// Name-indexed snapshot of the registered commands, built once per batch call (the registry + /// list itself is cached; this avoids an O(commands) scan per op). NOTE: this deliberately + /// does not reuse BasePipelineServer.ResolveCommand — that helper serves the exec + /// request path (logging, envelope error shape); unifying the two belongs to a follow-up so + /// the server's hot path is not reshaped from this command. + /// + private static Dictionary BuildCommandIndex() + { + var byName = new Dictionary(StringComparer.Ordinal); + foreach (var c in CommandRegistry.DiscoverCommands()) + if (!byName.ContainsKey(c.Name)) + byName.Add(c.Name, c); + return byName; + } + + private static CommandInfo ResolveBatchable(string name, bool transactional, IReadOnlyDictionary byName) + { + if (string.IsNullOrWhiteSpace(name)) + throw new ArgumentException("operation 'command' is required."); + + if (IsExcluded(name)) + throw new ArgumentException( + $"Command '{name}' is not batchable (not_batchable): commands that build, switch platform, " + + "manage packages, control play mode, recompile, evaluate code, execute Editor menu items " + + "(which can open modal dialogs and wedge an unattended batch), or nest a batch are excluded."); + + if (m_UndoStackWipingCommands.Contains(name)) + throw new ArgumentException( + $"Command '{name}' is not batchable (not_batchable): it clears the Editor Undo stack, which " + + "would make every prior batch operation unrevertible. Call it standalone instead."); + + if (!byName.TryGetValue(name, out var command)) + throw new ArgumentException($"No command named '{name}' is available (unknown command)."); + + if (command.RuntimeOnly) + throw new ArgumentException( + $"Command '{name}' is not batchable (not_batchable): runtime-only command (Player server " + + "surface); it cannot execute on this Editor server."); + + if (typeof(Task).IsAssignableFrom(command.Method.ReturnType)) + throw new ArgumentException( + $"Command '{name}' is not batchable (not_batchable): async commands cannot run inside a " + + "synchronous batch. They complete via EditorApplication.update callbacks, which cannot fire " + + "while the batch holds the main thread — the batch would deadlock the Editor. Call it " + + "standalone instead."); + + if (transactional && m_NonRevertibleCommands.Contains(name)) + throw new ArgumentException( + $"Command '{name}' is not batchable in a transactional batch (not_batchable_transactional): " + + "it mutates state outside the Editor Undo system (asset/file/settings writes), so a rollback " + + "could not revert it. Run the batch with transactional:false, or call the command standalone."); + + return command; + } + + private static bool IsExcluded(string name) + { + if (m_ExcludedCommands.Contains(name)) + return true; + foreach (var prefix in m_ExcludedPrefixes) + { + if (name.StartsWith(prefix, StringComparison.Ordinal)) + return true; + } + return false; + } + + /// Reject parameter keys that are not parameters of the command (dry-run check). + private static void ValidateKnownParameters(CommandInfo command, JObject parameters) + { + if (parameters == null) + return; + var known = new HashSet(command.Parameters.Select(p => p.Name), StringComparer.Ordinal); + foreach (var prop in parameters.Properties()) + { + if (!known.Contains(prop.Name)) + throw new ArgumentException( + $"Command '{command.Name}' has no parameter '{prop.Name}' (unknown parameter). " + + $"Known parameters: [{string.Join(", ", known)}]."); + } + } + + /// + /// Ensure every required parameter is present (dry-run check). A reference string counts as + /// present; an explicit JSON null does not. + /// + private static void ValidateRequiredParameters(CommandInfo command, JObject parameters) + { + foreach (var p in command.Parameters) + { + if (!p.Required) + continue; + var token = parameters?[p.Name]; + if (token == null || token.Type == JTokenType.Null) + throw new ArgumentException( + $"Command '{command.Name}' is missing required parameter '{p.Name}'."); + } + } + + /// + /// Shape an op's result: apply the optional result_fields projection, then replace an + /// oversized result with a truncation marker. With neither in play the raw result object is + /// returned unchanged, so it serializes byte-identically to the standalone command. + /// + internal static object ProjectResult(object raw, JToken rawToken, BatchOperationInput op, int index, + JObject resultFields, BatchOperationResult opResult, ref int remainingResultBytes) + { + object projected = raw; + + var fields = LookupResultFields(resultFields, op, index); + if (fields != null && rawToken != null && rawToken.Type != JTokenType.Null) + { + var projection = new JObject(); + List invalidPaths = null; + foreach (var path in fields) + { + if (string.IsNullOrEmpty(path)) + continue; + JToken value; + try + { + value = rawToken.SelectToken(path); + } + catch (Exception) + { + // A malformed JSONPath must NEVER throw here: by this point the op has + // already run and mutated state, and the outer catch would flip its + // Success to false — triggering a rollback of a succeeded op under + // on_error=abort, and poisoning later $refs into a perfectly valid + // captured result under on_error=continue. Report the bad path in the + // projection instead. + (invalidPaths ?? (invalidPaths = new List())).Add(path); + continue; + } + if (value != null) + projection[path] = value; + } + if (invalidPaths != null) + projection["invalidResultFields"] = new JArray(invalidPaths); + projected = projection; + } + + string json; + try + { + // Measure with the same formatting the wire envelope uses: since the lean envelope + // (AUTHAPI-21) /api/exec serializes compact (Formatting.None) in every mode, so the + // measurement matches what actually goes on the wire. + json = JsonConvert.SerializeObject(projected, Formatting.None); + } + catch (Exception ex) + { + // A result Newtonsoft cannot serialize would fail (or bloat) the whole batch envelope + // later. Replace it with a structured marker — and still flag resultTruncated — rather + // than skipping truncation for exactly the results we know nothing about. + opResult.ResultTruncated = true; + return new JObject + { + ["resultTruncated"] = true, + ["error"] = $"op result could not be serialized: {ex.Message}" + }; + } + + var bytes = System.Text.Encoding.UTF8.GetByteCount(json); + if (bytes > MaxPerOpResultBytes) + { + opResult.ResultTruncated = true; + return new JObject + { + ["resultTruncated"] = true, + ["length"] = bytes, + ["preview"] = json.Substring(0, Math.Min(json.Length, 512)) + }; + } + + if (bytes > remainingResultBytes) + { + // Aggregate budget exhausted: the op executed normally, only its echoed result is + // elided so the whole batch reply stays bounded ($refs still resolve — they read + // the captured token, not this projection). + opResult.ResultTruncated = true; + return new JObject + { + ["resultTruncated"] = true, + ["length"] = bytes, + ["error"] = $"batch aggregate result budget ({MaxBatchResultBytes} bytes) exhausted; " + + "the operation ran and later references to it still resolve, only this echoed result was elided. " + + "Use result_fields to project results down, or split the batch.", + ["preview"] = json.Substring(0, Math.Min(json.Length, 512)) + }; + } + remainingResultBytes -= bytes; + + return projected; + } + + /// + /// Look up the projection field list for an op in result_fields (keyed by op id, then + /// by index). Returns null when no projection is configured for the op. + /// + private static string[] LookupResultFields(JObject resultFields, BatchOperationInput op, int index) + { + if (resultFields == null) + return null; + + JToken entry = null; + if (!string.IsNullOrEmpty(op.Id)) + entry = resultFields[op.Id]; + if (entry == null) + entry = resultFields[index.ToString()]; + if (entry == null) + return null; + + if (entry.Type == JTokenType.Array) + return entry.ToObject(); + if (entry.Type == JTokenType.String) + return new[] { (string)entry }; + return null; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchCommand.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchCommand.cs.meta new file mode 100644 index 0000000..03ff083 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c33c9efe866346aab0db0dc6fad780a5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchInput.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchInput.cs new file mode 100644 index 0000000..fae8edd --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchInput.cs @@ -0,0 +1,43 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Unity.Pipeline.Commands; + +namespace Unity.Pipeline.Editor.Commands.Batch +{ + /// + /// A single operation in a batch request (AUTHAPI-27): the name of a registered command + /// plus the parameters to invoke it with, and an optional so later operations + /// can reference this one's result. + /// + /// String values anywhere in may reference an earlier operation's result + /// with "$<id-or-index>.<jsonPath>" (e.g. "$0.instanceId" or + /// "$createHead.components[0].instanceId"); "$$" escapes a literal '$'. + /// References are backward-only. Implements so the batch + /// command advertises a nested object schema (via GET /api/commands) rather than a string. + /// + sealed class BatchOperationInput : IStructuredCommandInput + { + /// + /// Optional operation id used to reference this operation's result from a later op + /// ("$<id>.<field>"). Must be unique within the batch when supplied, and + /// must match ^[A-Za-z_][A-Za-z0-9_-]*$ — purely numeric ids would be ambiguous with + /// 0-based index selectors, and '.' collides with the reference path separator. + /// + [CliArg("id", "Optional id for referencing this op's result from a later op (\"$.\"). Unique within the batch; must match ^[A-Za-z_][A-Za-z0-9_-]*$ (not purely numeric, no dots).")] + [JsonProperty("id")] + public string Id { get; set; } + + /// Name of the registered command to run (any command except the excluded list). + [CliArg("command", "Name of the registered command to run.", Required = true)] + [JsonProperty("command")] + public string Command { get; set; } + + /// + /// Parameters for the command, same shape as /api/exec parameters. Any string + /// value may reference a prior op's result ("$<id-or-index>.<jsonPath>"). + /// + [CliArg("params", "Parameters for the command. String values may reference a prior op's result: \"$.\".")] + [JsonProperty("params")] + public JObject Params { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchInput.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchInput.cs.meta new file mode 100644 index 0000000..8832b23 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchInput.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8f7946d807d348c0a98e13ba7d18f714 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchReferenceResolver.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchReferenceResolver.cs new file mode 100644 index 0000000..0f25be3 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchReferenceResolver.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json.Linq; + +namespace Unity.Pipeline.Editor.Commands.Batch +{ + /// + /// Resolves cross-operation result references in a batch operation's parameters (AUTHAPI-27). + /// + /// A string value that begins with a single '$' is a reference of the form + /// "$<selector>" or "$<selector>.<jsonPath>", where + /// <selector> names an earlier operation by its id or its 0-based index and + /// <jsonPath> is a Newtonsoft SelectToken path into that op's result + /// (e.g. "$0.instanceId", "$createHead.components[0].instanceId"). A leading + /// "$$" escapes a literal '$'. References are backward-only: a selector must resolve + /// to an operation strictly before the current one. + /// + /// References are resolved as WHOLE values (the entire string must be the reference), and the + /// substituted JSON token preserves its type — so a numeric instanceId stays a number and + /// deserializes into the target parameter (e.g. an ObjectRef) exactly as a literal would. + /// The walk recurses through nested objects and arrays, so a reference can appear anywhere in the + /// parameter tree. + /// + internal static class BatchReferenceResolver + { + /// + /// Validate the reference topology of without substituting any + /// values (used by dry run). Throws on an unknown selector, + /// a forward/self reference, or a malformed reference. + /// + public static void Validate(JToken parameters, int currentIndex, + IReadOnlyList operations, IReadOnlyDictionary idToIndex) + { + if (parameters == null) + return; + // No DeepClone: in validate mode (null resultsByIndex) TransformString always returns the + // original token, so Walk never reassigns a child — the walk is read-only. + Walk(parameters, currentIndex, operations, idToIndex, null, null); + } + + /// + /// Return a copy of with every reference replaced by the + /// referenced value from . Throws + /// on an unknown selector, a forward/self reference, a + /// reference whose path does not resolve, or a reference into an operation that failed, was + /// skipped, or returned no result (per-op outcomes come from ). + /// The input token is not mutated. + /// + public static JObject Resolve(JObject parameters, int currentIndex, + IReadOnlyList operations, IReadOnlyDictionary idToIndex, + JToken[] resultsByIndex, IReadOnlyList outcomes) + { + if (parameters == null) + return null; + var clone = (JObject)parameters.DeepClone(); + return (JObject)Walk(clone, currentIndex, operations, idToIndex, resultsByIndex, outcomes); + } + + /// + /// Recursively transform a token tree. is null in validate + /// mode (topology check only) and non-null in resolve mode (value substitution). + /// + private static JToken Walk(JToken node, int currentIndex, + IReadOnlyList operations, IReadOnlyDictionary idToIndex, + JToken[] resultsByIndex, IReadOnlyList outcomes) + { + switch (node.Type) + { + case JTokenType.Object: + foreach (var prop in ((JObject)node).Properties().ToList()) + { + var replaced = Walk(prop.Value, currentIndex, operations, idToIndex, resultsByIndex, outcomes); + if (!ReferenceEquals(replaced, prop.Value)) + prop.Value = replaced; + } + return node; + case JTokenType.Array: + var arr = (JArray)node; + for (int i = 0; i < arr.Count; i++) + { + var child = arr[i]; + var replaced = Walk(child, currentIndex, operations, idToIndex, resultsByIndex, outcomes); + if (!ReferenceEquals(replaced, child)) + arr[i] = replaced; + } + return node; + case JTokenType.String: + return TransformString((string)node, node, currentIndex, operations, idToIndex, resultsByIndex, outcomes); + default: + return node; + } + } + + private static JToken TransformString(string s, JToken original, int currentIndex, + IReadOnlyList operations, IReadOnlyDictionary idToIndex, + JToken[] resultsByIndex, IReadOnlyList outcomes) + { + if (string.IsNullOrEmpty(s) || s[0] != '$') + return original; // not a reference + + // "$$..." escapes a literal '$'. Only substitute when actually resolving; validation + // has nothing to check for a literal. + if (s.Length >= 2 && s[1] == '$') + return resultsByIndex == null ? original : (JToken)new JValue(s.Substring(1)); + + var rest = s.Substring(1); + var dot = rest.IndexOf('.'); + var selector = dot < 0 ? rest : rest.Substring(0, dot); + var path = dot < 0 ? null : rest.Substring(dot + 1); + + if (string.IsNullOrEmpty(selector)) + throw new ArgumentException( + $"Invalid reference '{s}': missing operation selector after '$'. " + + "Use \"$.\", or \"$$\" for a literal '$'."); + + var targetIndex = ResolveSelector(selector, operations, idToIndex); + if (targetIndex < 0) + throw new ArgumentException( + $"Reference '{s}' points to unknown operation '{selector}'. " + + "A reference must name an earlier operation by its id or 0-based index."); + if (targetIndex >= currentIndex) + throw new ArgumentException( + $"Reference '{s}' is a forward reference to operation '{selector}' (index {targetIndex}); " + + "only backward references to earlier operations are allowed."); + + // Validate mode: topology is fine, and there is no result to substitute yet. + if (resultsByIndex == null) + return original; + + // A failed or skipped operation has no result to reference — substituting null silently + // would feed a bogus value into this op's parameters. Error explicitly instead. In the + // real Execute() loop only Success=false outcomes are observable here (under + // on_error=continue — earlier failures don't stop the batch); Skipped entries are + // appended AFTER the loop, so the "was skipped" wording is defensive, reachable only + // when the resolver is driven directly (unit tests / future callers). + var outcome = outcomes != null && targetIndex < outcomes.Count ? outcomes[targetIndex] : null; + if (outcome != null && !outcome.Success) + { + var reason = outcome.Skipped == true ? "was skipped" : "failed"; + throw new ArgumentException( + $"Reference '{s}' cannot be resolved: operation '{selector}' {reason}; " + + "its result cannot be referenced."); + } + + // Distinct from failure: the op SUCCEEDED but produced nothing to reference (void/null + // result, or a result that could not be captured as a token). + var opResult = resultsByIndex[targetIndex]; + if (opResult == null || opResult.Type == JTokenType.Null) + throw new ArgumentException( + $"Reference '{s}' cannot be resolved: operation '{selector}' returned no result."); + + var picked = string.IsNullOrEmpty(path) ? opResult : opResult.SelectToken(path); + if (picked == null) + throw new ArgumentException( + $"Reference '{s}' did not resolve: operation '{selector}' result has no field '{path}'."); + + return picked.DeepClone(); + } + + /// + /// Resolve a selector to an operation index: an id match takes precedence over a numeric + /// index. Returns -1 when the selector names no operation. + /// + private static int ResolveSelector(string selector, + IReadOnlyList operations, IReadOnlyDictionary idToIndex) + { + if (idToIndex != null && idToIndex.TryGetValue(selector, out var byId)) + return byId; + if (int.TryParse(selector, out var idx) && idx >= 0 && idx < operations.Count) + return idx; + return -1; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchReferenceResolver.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchReferenceResolver.cs.meta new file mode 100644 index 0000000..b3f916d --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchReferenceResolver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bf4505eeb7b343d1969a2e1b8a9ab350 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchResult.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchResult.cs new file mode 100644 index 0000000..c76994d --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchResult.cs @@ -0,0 +1,101 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Unity.Pipeline.Editor.Commands.Batch +{ + /// + /// Result envelope for the batch command (AUTHAPI-27). Carries a per-operation result in + /// input order, how many ops were applied, whether a transactional rollback occurred, and the + /// Editor Undo group the whole batch collapsed into. + /// + sealed class BatchResult + { + /// Per-operation results, in the same order as the input operations. + [JsonProperty("results")] + public List Results { get; set; } = new List(); + + /// Number of operations that executed successfully (before any rollback). + [JsonProperty("applied")] + public int Applied { get; set; } + + /// True when a transactional rollback undid every applied operation. + [JsonProperty("reverted")] + public bool Reverted { get; set; } + + /// + /// Whether the batch ran transactionally (all ops in one Undo group, revert-on-failure). + /// Forced false when on_error=continue. + /// + [JsonProperty("transactional")] + public bool Transactional { get; set; } + + /// The effective error policy: abort or continue. + [JsonProperty("onError")] + public string OnError { get; set; } + + /// + /// Batch-level abort reason for stops not attributable to a single op's failure: + /// "batch time budget exceeded" (the cooperative time_budget_ms ran out between ops) + /// or "batch canceled" (cooperative job cancellation). Null otherwise. + /// + [JsonProperty("error", NullValueHandling = NullValueHandling.Ignore)] + public string Error { get; set; } + + /// The Editor Undo group index the whole batch collapsed into (execution only). + [JsonProperty("undoGroup", NullValueHandling = NullValueHandling.Ignore)] + public int? UndoGroup { get; set; } + + /// True when this was a dry run (validation only, zero mutation). + [JsonProperty("dryRun", NullValueHandling = NullValueHandling.Ignore)] + public bool? DryRun { get; set; } + + /// Dry run only: whether every operation validated without error. + [JsonProperty("valid", NullValueHandling = NullValueHandling.Ignore)] + public bool? Valid { get; set; } + } + + /// Result of a single operation within a . + sealed class BatchOperationResult + { + /// The operation's id, echoed back when supplied. + [JsonProperty("id", NullValueHandling = NullValueHandling.Ignore)] + public string Id { get; set; } + + /// The command that was (or would be) run. + [JsonProperty("command")] + public string Command { get; set; } + + /// + /// Whether the operation succeeded. On a dry run this is "would run" (validation passed). + /// + [JsonProperty("success")] + public bool Success { get; set; } + + /// + /// The command's result, shaped identically to running it standalone (optionally projected + /// via result_fields, or replaced by a truncation marker for oversized results). + /// + [JsonProperty("result", NullValueHandling = NullValueHandling.Ignore)] + public object Result { get; set; } + + /// Error message when the operation failed (or failed dry-run validation). + [JsonProperty("error", NullValueHandling = NullValueHandling.Ignore)] + public string Error { get; set; } + + /// True for operations not attempted because an earlier op aborted the batch. + [JsonProperty("skipped", NullValueHandling = NullValueHandling.Ignore)] + public bool? Skipped { get; set; } + + /// True when the result was replaced by a truncation marker (payload economy). + [JsonProperty("resultTruncated", NullValueHandling = NullValueHandling.Ignore)] + public bool? ResultTruncated { get; set; } + + /// + /// Whether a transactional rollback can revert this operation's mutations. False for commands + /// that mutate state outside the Editor Undo system (asset/file/settings writes) — those only + /// run with transactional=false. Unset when the command never resolved. + /// + [JsonProperty("revertible", NullValueHandling = NullValueHandling.Ignore)] + public bool? Revertible { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchResult.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchResult.cs.meta new file mode 100644 index 0000000..84ed8a5 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Batch/BatchResult.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f14af31d9bca47ee9536e91221678a86 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Build.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Build.meta new file mode 100644 index 0000000..aff8815 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Build.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bdb8ef5b0513b0d488ac3be1a9a77185 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/BuildCommand.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/BuildCommand.cs new file mode 100644 index 0000000..15cf9be --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/BuildCommand.cs @@ -0,0 +1,596 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor.Authoring; +using UnityEditor; +using UnityEditor.Build; +using UnityEditor.Build.Reporting; +using UnityEngine; +#if UNITY_6000_5_OR_NEWER +using Unity.Scripting.LifecycleManagement; +#endif + +namespace Unity.Pipeline.Editor.Commands.Build +{ + /// + /// Triggers a Player build and reports the full (CLI-204). Fills out the + /// original build/build_status stub (CLI-127) with the complete param contract and the + /// structured report shape so build failures can be diagnosed without the Editor UI. + /// + /// Why this is async (trigger-then-poll, mirroring / + /// ): + /// runs synchronously and freezes the main thread for the whole build (seconds to minutes). If + /// build ran it inline it would block the server's (serial) request loop and the call could + /// never return. Instead build validates + queues and returns queued immediately; an + /// hook runs the build on the next tick. Poll build_status + /// until status == "completed". + /// + /// build_status is deliberately MainThreadRequired = false: while the build holds the + /// main thread, any main-thread command (e.g. editor_status) would hang, but build_status only reads + /// a Temp status file off-thread, so polling keeps working throughout the build. The status file also + /// survives the domain reload a build can incur, so the last report is retained until the next build. + /// + [InitializeOnLoad] +#if UNITY_6000_5_OR_NEWER + [NoAutoStaticsCleanup] +#endif + static class BuildCommand + { + const string StatusFile = "Temp/pipeline_build_status.json"; + + // BuildOptions that callers may pass by name (the supported set from the ticket). Parsed + // case-insensitively; anything outside this set is a validation error rather than silently + // tolerated, so a typo surfaces instead of changing the build shape. + static readonly Dictionary s_SupportedOptions = + new Dictionary(StringComparer.OrdinalIgnoreCase) + { + ["Development"] = BuildOptions.Development, + ["AllowDebugging"] = BuildOptions.AllowDebugging, + ["ConnectWithProfiler"] = BuildOptions.ConnectWithProfiler, + // EnableHeadlessMode is obsolete in Unity 6 (superseded by StandaloneBuildSubtarget.Server) + // but still functions and is part of this command's documented option set (CLI-204), so we + // keep accepting it and suppress only the deprecation warning here. +#pragma warning disable 618 + ["EnableHeadlessMode"] = BuildOptions.EnableHeadlessMode, +#pragma warning restore 618 + ["SymlinkSources"] = BuildOptions.SymlinkSources, + ["BuildAdditionalStreamedScenes"] = BuildOptions.BuildAdditionalStreamedScenes, + ["CleanBuildCache"] = BuildOptions.CleanBuildCache, + ["DetailedBuildReport"] = BuildOptions.DetailedBuildReport, + }; + + static readonly object s_Lock = new object(); + static bool s_Pending; + static bool s_Building; + + // Queued request, captured under s_Lock by build() and consumed by the update pump. + static BuildTarget s_PendingTarget; + static string s_PendingOutput; + static BuildOptions s_PendingOptions; + + /// + /// BuildOptions of the scripted build currently inside BuildPipeline.BuildPlayer, or null + /// when no `build` command is running. Build processors read it because a scripted build + /// with BuildOptions.Development is a development build even when the Build Settings + /// toggle (EditorUserBuildSettings.development) is off. + /// + internal static BuildOptions? ActiveScriptedBuildOptions { get; private set; } + static string[] s_PendingScenes; + static string s_PendingProfile; + static string s_PendingBuildId; + + static BuildCommand() + { + EditorApplication.update += OnUpdate; + } + + [CliCommand("build", + "Trigger an async Player build and report the full BuildReport. Returns immediately (queued); " + + "poll build_status until status is 'completed'. DetailedBuildReport is included by default unless " + + "'options' is supplied. Use dry_run to validate without building.", + MainThreadRequired = false, + Tags = new[] { "build" })] + public static object Build( + [CliArg("target", "BuildTarget name (e.g. StandaloneWindows64). Defaults to the active target. Must be installed.")] string target = "", + [CliArg("outputPath", "Output path (absolute, or relative to the project root). Defaults to the last/auto path.")] string outputPath = "", + [CliArg("profileName", "Build Profile name to activate before building (Unity 6 only; ignored otherwise).")] string profileName = "", + [CliArg("options", "BuildOptions names. Omit to get just DetailedBuildReport; supplying any disables that default.")] string[] options = null, + [CliArg("scenes", "Scene asset paths to build (e.g. Assets/Scenes/Main.unity). Defaults to EditorBuildSettings.")] string[] scenes = null, + [CliArg("confirm", "Acknowledge and run the build; without it the call is refused. Use dry_run to validate only.")] bool confirm = false, + [CliArg("dry_run", "Validate target/outputPath/scenes without building.")] bool dryRun = false) + { + // Validation + queueing both touch Unity APIs, so run them on the main thread. When invoked + // off-thread (the normal HTTP path) this marshals through the server dispatcher; in-process + // (tests, no server) it runs inline. + return RunOnMain(() => ValidateAndQueue(target, outputPath, profileName, options, scenes, confirm, dryRun)); + } + + static object ValidateAndQueue(string targetArg, string outputArg, string profileName, + string[] optionArgs, string[] sceneArgs, bool confirm, bool dryRun) + { + lock (s_Lock) + { + if (!dryRun && (s_Building || s_Pending)) + return new { status = "busy", success = false, message = "A build is already queued or in progress. Poll build_status." }; + } + + var errors = new List(); + + // ---- target ---- + var target = EditorUserBuildSettings.activeBuildTarget; + if (!string.IsNullOrWhiteSpace(targetArg)) + { + if (!TryParseTarget(targetArg, out target)) + errors.Add(Invalid("target", $"Unknown BuildTarget '{targetArg}'. Use a name from list_build_targets.")); + else if (!BuildPipeline.IsBuildTargetSupported(BuildPipeline.GetBuildTargetGroup(target), target)) + errors.Add(Invalid("target", $"Build target '{target}' is not installed (isInstalled=false in list_build_targets).")); + } + + // ---- options ---- + var options = BuildOptions.None; + if (optionArgs != null && optionArgs.Length > 0) + { + foreach (var name in optionArgs) + { + if (string.IsNullOrWhiteSpace(name)) + continue; + if (s_SupportedOptions.TryGetValue(name.Trim(), out var opt)) + options |= opt; + else + errors.Add(Invalid("options", $"Unsupported BuildOptions value '{name}'.")); + } + } + else + { + // Strongly recommended: without it BuildReport.packedAssets is empty. + options = BuildOptions.DetailedBuildReport; + } + + // ---- scenes ---- + var scenes = (sceneArgs != null && sceneArgs.Length > 0) + ? sceneArgs + : EditorBuildSettings.scenes.Where(s => s.enabled).Select(s => s.path).ToArray(); + + if (sceneArgs != null) + { + foreach (var scene in sceneArgs) + { + if (string.IsNullOrWhiteSpace(scene) || string.IsNullOrEmpty(AssetDatabase.AssetPathToGUID(scene))) + errors.Add(Invalid("scenes", $"No scene asset at '{scene}'.")); + } + } + + // ---- output path ---- + // Non-mutating writability check: resolve the path and confirm an existing ancestor + // directory exists (so the build's output folder can be created). BuildPipeline.BuildPlayer + // creates the leaf directory itself, so we never create anything here — a dry run stays pure. + string outputPath = null; + try + { + outputPath = ResolveOutput(outputArg, target); + if (!HasExistingAncestor(outputPath)) + errors.Add(Invalid("outputPath", $"No existing parent directory for '{outputPath}'.")); + } + catch (Exception ex) + { + errors.Add(Invalid("outputPath", $"Output path is invalid: {ex.Message}")); + } + + if (dryRun) + { + return new + { + status = "dry_run", + valid = errors.Count == 0, + validationErrors = errors + }; + } + + if (errors.Count > 0) + { + // Fail immediately — do not queue (acceptance criteria 5). + return new { status = "error", success = false, validationErrors = errors, message = "Build configuration is invalid; nothing was queued." }; + } + + if (!confirm) + return new + { + status = "error", + success = false, + message = "Refused: this triggers a player build. Pass confirm=true to build, or dry_run=true to validate without building." + }; + + var buildId = NewBuildId(); + + lock (s_Lock) + { + s_PendingTarget = target; + s_PendingOutput = outputPath; + s_PendingOptions = options; + s_PendingScenes = scenes; + s_PendingProfile = profileName; + s_PendingBuildId = buildId; + s_Pending = true; + } + + WriteStatusJson(new { status = "queued", buildId, message = "Build queued. Poll build_status until status is 'completed'." }); + + return new { status = "queued", buildId }; + } + + [CliCommand("build_status", + "Status of the current/most recent build: idle | queued | building | completed, with the full " + + "BuildReport (files, packedAssets, buildSteps, errors, warnings) once completed. Retained until the next build.", + MainThreadRequired = false, + Tags = new[] { "build" })] + public static string BuildStatus() + { + if (!File.Exists(StatusFile)) + return "{\"status\":\"idle\"}"; + + var text = File.ReadAllText(StatusFile); + + // While building, recompute elapsedMs at read time so polling shows live progress. + try + { + var doc = JObject.Parse(text); + if ((string)doc["status"] == "building") + { + long elapsed = 0; + var startedStr = (string)doc["buildStartedAt"]; + if (!string.IsNullOrEmpty(startedStr) && + DateTime.TryParse(startedStr, null, System.Globalization.DateTimeStyles.RoundtripKind, out var started)) + { + elapsed = (long)Math.Max(0, (DateTime.UtcNow - started.ToUniversalTime()).TotalMilliseconds); + } + + return JsonConvert.SerializeObject(new + { + status = "building", + buildId = (string)doc["buildId"], + elapsedMs = elapsed + }); + } + } + catch + { + // Malformed file — fall through and return it verbatim. + } + + return text; + } + + /// + /// Main-thread pump: picks up a queued request and runs the (blocking) build. Guarded so a build + /// runs at most once at a time. + /// + static void OnUpdate() + { + BuildTarget target; + string output; + BuildOptions options; + string[] scenes; + string profile; + string buildId; + + lock (s_Lock) + { + if (!s_Pending || s_Building) + return; + s_Pending = false; + s_Building = true; + target = s_PendingTarget; + output = s_PendingOutput; + options = s_PendingOptions; + scenes = s_PendingScenes; + profile = s_PendingProfile; + buildId = s_PendingBuildId; + } + + try + { + RunBuild(buildId, target, output, options, scenes, profile); + } + catch (Exception ex) + { + WriteStatusJson(new + { + status = "completed", + buildId, + result = "Failed", + totalSizeBytes = 0, + errors = new[] { new { message = $"Build failed to start: {ex.Message}" } }, + warnings = Array.Empty() + }); + } + finally + { + lock (s_Lock) { s_Building = false; } + } + } + + static void RunBuild(string buildId, BuildTarget target, string outputPath, BuildOptions options, + string[] scenes, string profileName) + { + var startedAt = DateTime.UtcNow; + WriteStatusJson(new + { + status = "building", + buildId, + buildStartedAt = startedAt.ToString("o"), + platform = target.ToString(), + outputPath + }); + + // Best-effort Build Profile activation (Unity 6 only). Never fails the build. + if (!string.IsNullOrWhiteSpace(profileName)) + TryActivateBuildProfile(profileName); + + var buildOptions = new BuildPlayerOptions + { + scenes = scenes, + locationPathName = outputPath, + target = target, + targetGroup = BuildPipeline.GetBuildTargetGroup(target), + options = options + }; + + ActiveScriptedBuildOptions = options; + BuildReport report; + try { report = BuildPipeline.BuildPlayer(buildOptions); } + finally { ActiveScriptedBuildOptions = null; } + WriteStatusJson(Project(buildId, report)); + } + + // ---- BuildReport projection ------------------------------------------------------------ + + static BuildReportResult Project(string buildId, BuildReport report) + { + var summary = report.summary; + var success = summary.result == BuildResult.Succeeded; + var started = summary.buildStartedAt; + var ended = started + summary.totalTime; + + var result = new BuildReportResult + { + Status = "completed", + BuildId = buildId, + Result = summary.result.ToString(), + Platform = summary.platform.ToString(), + OutputPath = summary.outputPath, + TotalSizeBytes = (long)summary.totalSize, + BuildTimeMs = (long)summary.totalTime.TotalMilliseconds, + BuildStartedAt = started.ToUniversalTime().ToString("o"), + BuildEndedAt = ended.ToUniversalTime().ToString("o"), + TotalWarnings = summary.totalWarnings, + TotalErrors = summary.totalErrors, + BuildSteps = ProjectSteps(report, out var errors, out var warnings), + Errors = errors, + Warnings = warnings + }; + + // Files / packed assets are only meaningful on success (and packedAssets needs DetailedBuildReport). + if (success) + { + result.Files = ProjectFiles(report); + result.PackedAssets = ProjectPackedAssets(report); + } + + return result; + } + + static List ProjectFiles(BuildReport report) + { + var files = new List(); + try + { + foreach (var f in report.GetFiles()) + files.Add(new BuildFileEntry { Path = f.path, Role = f.role, SizeBytes = (long)f.size }); + } + catch (Exception ex) + { + Debug.LogWarning($"[pipeline] build file projection failed: {ex.Message}"); + } + return files; + } + + static List ProjectPackedAssets(BuildReport report) + { + var packed = new List(); + if (report.packedAssets == null) + return packed; + + foreach (var bundle in report.packedAssets) + { + var entry = new PackedAssetEntry + { + BundlePath = bundle.shortPath, + OverheadBytes = (long)bundle.overhead, + Contents = new List() + }; + + if (bundle.contents != null) + { + foreach (var c in bundle.contents) + { + entry.Contents.Add(new PackedAssetContent + { + AssetPath = c.sourceAssetPath, + Type = c.type != null ? c.type.Name : null, + Guid = c.sourceAssetGUID.ToString(), + SizeBytes = (long)c.packedSize + }); + } + } + + packed.Add(entry); + } + return packed; + } + + static List ProjectSteps(BuildReport report, + out List errors, out List warnings) + { + errors = new List(); + warnings = new List(); + + var steps = new List(); + if (report.steps == null) + return steps; + + foreach (var step in report.steps) + { + var entry = new BuildStepEntry + { + Name = step.name, + DurationMs = (long)step.duration.TotalMilliseconds, + Depth = (int)step.depth, + Messages = new List() + }; + + if (step.messages != null) + { + foreach (var m in step.messages) + { + entry.Messages.Add(new BuildStepMessageEntry { Type = MapLogType(m.type), Content = m.content }); + + if (m.type == LogType.Error || m.type == LogType.Assert || m.type == LogType.Exception) + errors.Add(BuildIssue.From(m.content)); + else if (m.type == LogType.Warning) + warnings.Add(BuildIssue.From(m.content)); + } + } + + steps.Add(entry); + } + return steps; + } + + static string MapLogType(LogType type) + { + switch (type) + { + case LogType.Warning: return "Warning"; + case LogType.Error: + case LogType.Assert: + case LogType.Exception: return "Error"; + default: return "Log"; + } + } + + // ---- Helpers --------------------------------------------------------------------------- + + /// Case-insensitive parse of a enum name. + static bool TryParseTarget(string name, out BuildTarget target) + { + try + { + target = (BuildTarget)Enum.Parse(typeof(BuildTarget), name.Trim(), ignoreCase: true); + return Enum.IsDefined(typeof(BuildTarget), target); + } + catch + { + target = EditorUserBuildSettings.activeBuildTarget; + return false; + } + } + + static object Invalid(string field, string message) => new { field, message }; + + static string NewBuildId() => "build_" + Guid.NewGuid().ToString("N").Substring(0, 12); + + static string ResolveOutput(string output, BuildTarget target) + { + var projectRoot = ProjectPaths.ProjectRoot; + + if (!string.IsNullOrWhiteSpace(output)) + return Path.IsPathRooted(output) ? output : Path.GetFullPath(Path.Combine(projectRoot, output)); + + var product = string.IsNullOrEmpty(PlayerSettings.productName) ? "Player" : PlayerSettings.productName; + return Path.Combine(projectRoot, "Builds", target.ToString(), product + ExtensionFor(target)); + } + + /// True if some ancestor directory of already exists — a cheap, + /// non-mutating check that the build output folder is creatable. + static bool HasExistingAncestor(string path) + { + var dir = Path.GetDirectoryName(path); + while (!string.IsNullOrEmpty(dir)) + { + if (Directory.Exists(dir)) + return true; + dir = Path.GetDirectoryName(dir); + } + return false; + } + + static string ExtensionFor(BuildTarget target) + { + switch (target) + { + case BuildTarget.StandaloneWindows: + case BuildTarget.StandaloneWindows64: + return ".exe"; + case BuildTarget.StandaloneOSX: + return ".app"; + case BuildTarget.Android: + return ".apk"; + default: + return string.Empty; // Linux standalone, dedicated server, etc. + } + } + + /// + /// Best-effort: activate a Build Profile by name via reflection so the assembly still compiles on + /// Unity versions without the Build Profile API. Any failure is logged and ignored — the build + /// proceeds with the current configuration. + /// + static void TryActivateBuildProfile(string profileName) + { + try + { + var info = BuildProfiles.FindByName(profileName); + if (info == null) + { + Debug.LogWarning($"[pipeline] build: profile '{profileName}' not found; building with current settings."); + return; + } + if (!BuildProfiles.TrySetActive(info)) + Debug.LogWarning($"[pipeline] build: could not activate profile '{profileName}'; building with current settings."); + } + catch (Exception ex) + { + Debug.LogWarning($"[pipeline] build: profile activation failed ({ex.Message}); building with current settings."); + } + } + + /// + /// Run on the Unity main thread. Off-thread (the HTTP path) it marshals + /// through the live server's dispatcher; on the main thread (a direct in-process/test call, or no + /// server running) it runs inline. Mirrors . + /// + static T RunOnMain(Func fn) + { + var dispatcher = PipelineServerStartup.Server?.Dispatcher; + if (dispatcher != null && dispatcher.IsInitialized && !dispatcher.IsMainThread()) + return dispatcher.Invoke(fn); + return fn(); + } + + static void WriteStatusJson(object status) + { + try + { + File.WriteAllText(StatusFile, JsonConvert.SerializeObject(status)); + } + catch (Exception ex) + { + Debug.LogError($"[Build] Failed to write status file: {ex.Message}"); + } + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/BuildCommand.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/BuildCommand.cs.meta new file mode 100644 index 0000000..39abf76 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/BuildCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6e718f193c77f724ea4de47fe8a2a3cb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/BuildConfigCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/BuildConfigCommands.cs new file mode 100644 index 0000000..d135d20 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/BuildConfigCommands.cs @@ -0,0 +1,347 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Unity.Pipeline.Commands; +using UnityEditor; +using UnityEditor.Build; +using UnityEngine; +#if UNITY_6000_5_OR_NEWER +using Unity.Scripting.LifecycleManagement; +#endif + +namespace Unity.Pipeline.Editor.Commands.Build +{ + /// + /// Read/inspect build configuration for agents (CLI-204): enumerate targets, read/write the mutable + /// EditorUserBuildSettings fields, and list Build Profile assets. Scene-list management and + /// target switching are intentionally elsewhere (add_scene_to_build/remove_scene_from_build + /// from CLI-189, and switch_build_target). + /// +#if UNITY_6000_5_OR_NEWER + [NoAutoStaticsCleanup] +#endif + static class BuildConfigCommands + { + [CliCommand("list_build_targets", + "List the known BuildTarget values with their group and whether build support is installed.", + MainThreadRequired = true, + Tags = new[] { "build/targets" })] + public static object ListBuildTargets() + { + var targets = new List(); + var seen = new HashSet(); + + foreach (BuildTarget value in Enum.GetValues(typeof(BuildTarget))) + { + // Exclude NoTarget / internal sentinels (negative) and deprecated/obsolete values. + if ((int)value <= 0) + continue; + + var name = value.ToString(); + if (!seen.Add(name)) + continue; + + var field = typeof(BuildTarget).GetField(name); + if (field != null && field.GetCustomAttribute() != null) + continue; + + BuildTargetGroup group; + try { group = BuildPipeline.GetBuildTargetGroup(value); } + catch { continue; } + + bool installed; + try { installed = BuildPipeline.IsBuildTargetSupported(group, value); } + catch { installed = false; } + + targets.Add(new BuildTargetInfo + { + Name = name, + DisplayName = DisplayNameFor(value), + TargetGroup = group.ToString(), + IsInstalled = installed + }); + } + + return targets.OrderBy(t => t.TargetGroup).ThenBy(t => t.Name).ToList(); + } + + [CliCommand("get_build_settings", + "Read the current build configuration from EditorUserBuildSettings / EditorBuildSettings.", + MainThreadRequired = true, + Tags = new[] { "build/settings" })] + public static object GetBuildSettings() + { + var target = EditorUserBuildSettings.activeBuildTarget; + var group = BuildPipeline.GetBuildTargetGroup(target); + + return new BuildSettingsResult + { + ActiveBuildTarget = target.ToString(), + ActiveBuildTargetGroup = group.ToString(), + DevelopmentBuild = EditorUserBuildSettings.development, + AllowDebugging = EditorUserBuildSettings.allowDebugging, + ConnectWithProfiler = EditorUserBuildSettings.connectProfiler, + BuildScriptsOnly = EditorUserBuildSettings.buildScriptsOnly, + SymlinkSources = EditorUserBuildSettings.symlinkSources, + Il2CppCodeGeneration = ReadIl2CppCodeGeneration(group), + Scenes = EditorBuildSettings.scenes.Select(s => new BuildSceneEntry + { + Path = s.path, + Guid = s.guid.ToString(), + Enabled = s.enabled + }).ToList() + }; + } + + [CliCommand("set_build_settings", + "Set mutable EditorUserBuildSettings fields. Does NOT manage scenes (use add_scene_to_build / " + + "remove_scene_from_build) or switch target (use switch_build_target). Use dry_run to preview.", + MainThreadRequired = true, + Tags = new[] { "build/settings" })] + public static object SetBuildSettings( + [CliArg("settings", "Fields to change; omitted fields are left unchanged.")] SetBuildSettingsInput settings = null, + [CliArg("confirm", "Apply the changes. Without it the call is refused.")] bool confirm = false, + [CliArg("dry_run", "Preview the change without applying it.")] bool dryRun = false) + { + if (settings == null) + return SetBuildSettingsResult.Fail("No 'settings' object provided."); + + if (!dryRun && !confirm) + return SetBuildSettingsResult.Fail( + "Refused: this operation mutates the project. Re-run with confirm=true to apply, or dry_run=true to preview the change."); + var result = new SetBuildSettingsResult { DryRun = dryRun, Success = true }; + var group = BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget); + + // For each supplied field: change it (recording in Applied) only if it differs from the + // current value; otherwise record it in Skipped as a no-op. + Plan(result, "developmentBuild", settings.DevelopmentBuild, EditorUserBuildSettings.development, + v => EditorUserBuildSettings.development = v, dryRun); + Plan(result, "allowDebugging", settings.AllowDebugging, EditorUserBuildSettings.allowDebugging, + v => EditorUserBuildSettings.allowDebugging = v, dryRun); + Plan(result, "connectWithProfiler", settings.ConnectWithProfiler, EditorUserBuildSettings.connectProfiler, + v => EditorUserBuildSettings.connectProfiler = v, dryRun); + Plan(result, "buildScriptsOnly", settings.BuildScriptsOnly, EditorUserBuildSettings.buildScriptsOnly, + v => EditorUserBuildSettings.buildScriptsOnly = v, dryRun); + Plan(result, "symlinkSources", settings.SymlinkSources, EditorUserBuildSettings.symlinkSources, + v => EditorUserBuildSettings.symlinkSources = v, dryRun); + + if (!string.IsNullOrWhiteSpace(settings.Il2CppCodeGeneration)) + { + if (!TryParseIl2Cpp(settings.Il2CppCodeGeneration, out var requested)) + return SetBuildSettingsResult.Fail($"Invalid il2CppCodeGeneration '{settings.Il2CppCodeGeneration}'. Use OptimizeSpeed | OptimizeSize."); + + var current = ReadIl2CppCodeGeneration(group); + if (!string.Equals(current, requested.ToString(), StringComparison.Ordinal)) + { + if (!dryRun) + PlayerSettings.SetIl2CppCodeGeneration(NamedBuildTarget.FromBuildTargetGroup(group), requested); + result.Applied["il2CppCodeGeneration"] = requested.ToString(); + } + else + { + result.Skipped["il2CppCodeGeneration"] = current; + } + } + + result.Message = dryRun + ? $"Dry run — {result.Applied.Count} field(s) would change, {result.Skipped.Count} unchanged." + : $"Applied {result.Applied.Count} field(s); {result.Skipped.Count} unchanged."; + return result; + } + + [CliCommand("list_build_profiles", + "List Build Profile assets in the project (Unity 6 only). Returns feature_unavailable on earlier versions.", + MainThreadRequired = true, + Tags = new[] { "build/settings" })] + public static object ListBuildProfiles() + { + if (!BuildProfiles.IsSupported) + return new { error = "Build Profiles require Unity 6 (6000.0) or later", code = "feature_unavailable" }; + + return BuildProfiles.List(); + } + + // ---- Helpers --------------------------------------------------------------------------- + + static void Plan(SetBuildSettingsResult result, string name, bool? requested, bool current, + Action set, bool dryRun) + { + if (!requested.HasValue) + return; + + if (requested.Value != current) + { + if (!dryRun) + set(requested.Value); + result.Applied[name] = requested.Value; + } + else + { + result.Skipped[name] = current; + } + } + + static string ReadIl2CppCodeGeneration(BuildTargetGroup group) + { + try + { + return PlayerSettings.GetIl2CppCodeGeneration(NamedBuildTarget.FromBuildTargetGroup(group)).ToString(); + } + catch + { + return Il2CppCodeGeneration.OptimizeSpeed.ToString(); + } + } + + static bool TryParseIl2Cpp(string value, out Il2CppCodeGeneration parsed) + { + return Enum.TryParse(value.Trim(), ignoreCase: true, out parsed) + && Enum.IsDefined(typeof(Il2CppCodeGeneration), parsed); + } + + /// Friendly label for common targets; falls back to the enum name. + static string DisplayNameFor(BuildTarget target) + { + switch (target) + { + case BuildTarget.StandaloneWindows: return "Windows (32-bit)"; + case BuildTarget.StandaloneWindows64: return "Windows 64-bit"; + case BuildTarget.StandaloneOSX: return "macOS"; + case BuildTarget.StandaloneLinux64: return "Linux 64-bit"; + case BuildTarget.Android: return "Android"; + case BuildTarget.iOS: return "iOS"; + case BuildTarget.tvOS: return "tvOS"; + case BuildTarget.WebGL: return "WebGL"; + case BuildTarget.WSAPlayer: return "Universal Windows Platform"; + case BuildTarget.PS4: return "PlayStation 4"; + case BuildTarget.PS5: return "PlayStation 5"; + case BuildTarget.XboxOne: return "Xbox One"; + case BuildTarget.Switch: return "Nintendo Switch"; + default: return target.ToString(); + } + } + } + + /// + /// Reflection shim over the Unity 6 Build Profile API (UnityEditor.Build.Profile.BuildProfile), + /// so this assembly compiles and runs on older editors without the type. Used by + /// list_build_profiles and by build's optional profileName activation. + /// + internal static class BuildProfiles + { + const string TypeName = "UnityEditor.Build.Profile.BuildProfile, UnityEditor.CoreModule"; + + static readonly Type s_Type = ResolveType(); + + public static bool IsSupported => s_Type != null; + + static Type ResolveType() + { + var t = Type.GetType(TypeName); + if (t != null) + return t; + + // Fall back to a full-assembly scan — the assembly-qualified name can vary across versions. + foreach (var asm in PipelineUtils.GetLoadedAssemblies()) + { + t = asm.GetType("UnityEditor.Build.Profile.BuildProfile"); + if (t != null) + return t; + } + return null; + } + + public static List List() + { + var list = new List(); + if (s_Type == null) + return list; + + var active = GetActive(); + foreach (var guid in AssetDatabase.FindAssets("t:BuildProfile")) + { + var path = AssetDatabase.GUIDToAssetPath(guid); + var asset = AssetDatabase.LoadAssetAtPath(path, s_Type); + if (asset == null) + continue; + + list.Add(new BuildProfileInfo + { + Name = System.IO.Path.GetFileNameWithoutExtension(path), + Guid = guid, + Platform = ReadPlatform(asset), + IsActive = active != null && ReferenceEquals(active, asset) + }); + } + return list; + } + + public static BuildProfileInfo FindByName(string name) + { + return List().FirstOrDefault(p => string.Equals(p.Name, name, StringComparison.OrdinalIgnoreCase)); + } + + /// Activate the named profile via the API's static setter; returns false if unavailable. + public static bool TrySetActive(BuildProfileInfo info) + { + if (s_Type == null || info == null) + return false; + + var path = AssetDatabase.GUIDToAssetPath(info.Guid); + var asset = AssetDatabase.LoadAssetAtPath(path, s_Type); + if (asset == null) + return false; + + // Unity 6 exposes a static settable 'activeProfile' (and/or a SetActiveBuildProfile method). + var prop = s_Type.GetProperty("activeProfile", BindingFlags.Public | BindingFlags.Static); + if (prop != null && prop.CanWrite) + { + prop.SetValue(null, asset); + return true; + } + + var method = s_Type.GetMethod("SetActiveBuildProfile", BindingFlags.Public | BindingFlags.Static); + if (method != null) + { + method.Invoke(null, new[] { asset }); + return true; + } + + return false; + } + + static UnityEngine.Object GetActive() + { + try + { + var prop = s_Type.GetProperty("activeProfile", BindingFlags.Public | BindingFlags.Static); + if (prop != null) + return prop.GetValue(null) as UnityEngine.Object; + + var method = s_Type.GetMethod("GetActiveBuildProfile", BindingFlags.Public | BindingFlags.Static); + if (method != null) + return method.Invoke(null, null) as UnityEngine.Object; + } + catch { /* best effort */ } + return null; + } + + static string ReadPlatform(UnityEngine.Object asset) + { + try + { + // Public property first, then the serialized backing field. + var prop = s_Type.GetProperty("buildTarget", BindingFlags.Public | BindingFlags.Instance); + if (prop != null) + return prop.GetValue(asset)?.ToString() ?? string.Empty; + + var field = s_Type.GetField("m_BuildTarget", BindingFlags.NonPublic | BindingFlags.Instance); + if (field != null) + return field.GetValue(asset)?.ToString() ?? string.Empty; + } + catch { /* best effort */ } + return string.Empty; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/BuildConfigCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/BuildConfigCommands.cs.meta new file mode 100644 index 0000000..e144578 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/BuildConfigCommands.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e65c0b78842b492d8f9363ec749bc370 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/BuildModels.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/BuildModels.cs new file mode 100644 index 0000000..a1bab61 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/BuildModels.cs @@ -0,0 +1,271 @@ +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using Newtonsoft.Json; +using Unity.Pipeline.Commands; + +namespace Unity.Pipeline.Editor.Commands.Build +{ + /// + /// One entry of list_build_targets (CLI-204): a BuildTarget enum value with the + /// information an agent needs to choose a valid target without guessing — its group and whether the + /// platform's build support is actually installed in this editor. + /// + [Serializable] + class BuildTargetInfo + { + /// BuildTarget enum name, e.g. "StandaloneWindows64". + [JsonProperty("name")] public string Name { get; set; } + + /// Friendly label, e.g. "Windows 64-bit". + [JsonProperty("displayName")] public string DisplayName { get; set; } + + /// BuildTargetGroup enum name, e.g. "Standalone". + [JsonProperty("targetGroup")] public string TargetGroup { get; set; } + + /// BuildPipeline.IsBuildTargetSupported(group, target) — module installed and usable. + [JsonProperty("isInstalled")] public bool IsInstalled { get; set; } + } + + /// One scene in the Build Settings scene list, projected for get_build_settings. + [Serializable] + class BuildSceneEntry + { + [JsonProperty("path")] public string Path { get; set; } + [JsonProperty("guid")] public string Guid { get; set; } + [JsonProperty("enabled")] public bool Enabled { get; set; } + } + + /// + /// Result of get_build_settings (CLI-204): the current build configuration read from + /// EditorUserBuildSettings / EditorBuildSettings plus the active target's IL2CPP code + /// generation mode. Scene-list management lives in add_scene_to_build / + /// remove_scene_from_build (CLI-189); this only reports the list. + /// + [Serializable] + class BuildSettingsResult + { + [JsonProperty("activeBuildTarget")] public string ActiveBuildTarget { get; set; } + [JsonProperty("activeBuildTargetGroup")] public string ActiveBuildTargetGroup { get; set; } + [JsonProperty("developmentBuild")] public bool DevelopmentBuild { get; set; } + [JsonProperty("allowDebugging")] public bool AllowDebugging { get; set; } + [JsonProperty("connectWithProfiler")] public bool ConnectWithProfiler { get; set; } + [JsonProperty("buildScriptsOnly")] public bool BuildScriptsOnly { get; set; } + [JsonProperty("symlinkSources")] public bool SymlinkSources { get; set; } + + /// "OptimizeSpeed" | "OptimizeSize" for the active build target. + [JsonProperty("il2CppCodeGeneration")] public string Il2CppCodeGeneration { get; set; } + + [JsonProperty("scenes")] public List Scenes { get; set; } + } + + /// + /// Mutable build-settings fields for set_build_settings (CLI-204). Every field is nullable; + /// only the ones the caller supplies are changed. Note that and + /// only take effect when is also on. + /// + class SetBuildSettingsInput : IStructuredCommandInput + { + [CliArg("developmentBuild", "Build a Development Player (enables the debugger/profiler).")] + public bool? DevelopmentBuild { get; set; } + + [CliArg("allowDebugging", "Allow script debugging (only effective with developmentBuild=true).")] + public bool? AllowDebugging { get; set; } + + [CliArg("connectWithProfiler", "Auto-connect the Profiler (only effective with developmentBuild=true).")] + public bool? ConnectWithProfiler { get; set; } + + [CliArg("buildScriptsOnly", "Build only the scripts (skip data) for faster iteration.")] + public bool? BuildScriptsOnly { get; set; } + + [CliArg("symlinkSources", "Symlink runtime/plugin sources instead of copying (where supported).")] + public bool? SymlinkSources { get; set; } + + [CliArg("il2CppCodeGeneration", "IL2CPP code generation for the active target: OptimizeSpeed | OptimizeSize.")] + public string Il2CppCodeGeneration { get; set; } + } + + /// + /// Result of set_build_settings (CLI-204): the fields that were actually changed + /// () versus the supplied fields that already had the requested value + /// (). A dry run reports the same set it would + /// write, without changing anything. + /// + [Serializable] + class SetBuildSettingsResult + { + [JsonProperty("success")] public bool Success { get; set; } + [JsonProperty("dryRun")] public bool DryRun { get; set; } + + /// Field name → new value, for each field that changed (or would change on a dry run). + [JsonProperty("applied")] public Dictionary Applied { get; set; } = new Dictionary(); + + /// Field name → current value, for supplied fields that already matched (no-ops). + [JsonProperty("skipped")] public Dictionary Skipped { get; set; } = new Dictionary(); + + [JsonProperty("message")] public string Message { get; set; } + + public static SetBuildSettingsResult Fail(string message) => + new SetBuildSettingsResult { Success = false, Message = message }; + } + + /// One Build Profile asset, projected for list_build_profiles (Unity 6 only). + [Serializable] + class BuildProfileInfo + { + [JsonProperty("name")] public string Name { get; set; } + [JsonProperty("guid")] public string Guid { get; set; } + + /// The profile's build target name (best-effort; may be empty if unreadable). + [JsonProperty("platform")] public string Platform { get; set; } + + [JsonProperty("isActive")] public bool IsActive { get; set; } + } + + /// One output file produced by the build (a row of BuildReport.GetFiles()). + [Serializable] + class BuildFileEntry + { + [JsonProperty("path")] public string Path { get; set; } + + /// BuildFile.role verbatim, e.g. "MainData", "AssetBundle", "BootConfig". + [JsonProperty("role")] public string Role { get; set; } + + [JsonProperty("sizeBytes")] public long SizeBytes { get; set; } + } + + /// One asset packed into a build bundle/file (a row of a PackedAssets entry). + [Serializable] + class PackedAssetContent + { + [JsonProperty("assetPath")] public string AssetPath { get; set; } + [JsonProperty("type")] public string Type { get; set; } + [JsonProperty("guid")] public string Guid { get; set; } + [JsonProperty("sizeBytes")] public long SizeBytes { get; set; } + } + + /// A packed bundle/file with its per-asset size breakdown (requires DetailedBuildReport). + [Serializable] + class PackedAssetEntry + { + [JsonProperty("bundlePath")] public string BundlePath { get; set; } + [JsonProperty("overheadBytes")] public long OverheadBytes { get; set; } + [JsonProperty("contents")] public List Contents { get; set; } + } + + /// One message emitted during a build step. + [Serializable] + class BuildStepMessageEntry + { + /// "Log" | "Warning" | "Error" (mapped from LogType). + [JsonProperty("type")] public string Type { get; set; } + [JsonProperty("content")] public string Content { get; set; } + } + + /// One step of the build (a row of BuildReport.steps). + [Serializable] + class BuildStepEntry + { + [JsonProperty("name")] public string Name { get; set; } + [JsonProperty("durationMs")] public long DurationMs { get; set; } + [JsonProperty("depth")] public int Depth { get; set; } + [JsonProperty("messages")] public List Messages { get; set; } + } + + /// A build error/warning surfaced in build_status, with best-effort source file. + [Serializable] + class BuildIssue + { + [JsonProperty("message")] public string Message { get; set; } + + /// Source file when the message carries a "File.cs(line,col): ..." prefix; omitted otherwise. + [JsonProperty("file", NullValueHandling = NullValueHandling.Ignore)] public string File { get; set; } + + /// Build a , reusing for file extraction. + public static BuildIssue From(string content) + { + var parsed = BuildMessage.Parse("info", content); + return new BuildIssue + { + Message = parsed.Message, + File = string.IsNullOrEmpty(parsed.File) ? null : parsed.File + }; + } + } + + /// + /// Full build_status result for a finished build (CLI-204) — a JSON-friendly projection of + /// UnityEditor.Build.Reporting.BuildReport. Optional collections are omitted when null + /// (), so a failed build can carry errors/steps without empty + /// file/asset arrays. Transient states (queued/building/idle/dry_run) are reported as small, + /// purpose-built payloads, not this type. + /// + [Serializable] + class BuildReportResult + { + [JsonProperty("status")] public string Status { get; set; } + [JsonProperty("buildId")] public string BuildId { get; set; } + + /// "Succeeded" | "Failed" | "Cancelled" | "Unknown". + [JsonProperty("result")] public string Result { get; set; } + + [JsonProperty("platform")] public string Platform { get; set; } + [JsonProperty("outputPath")] public string OutputPath { get; set; } + [JsonProperty("totalSizeBytes")] public long TotalSizeBytes { get; set; } + [JsonProperty("buildTimeMs")] public long BuildTimeMs { get; set; } + + [JsonProperty("buildStartedAt", NullValueHandling = NullValueHandling.Ignore)] public string BuildStartedAt { get; set; } + [JsonProperty("buildEndedAt", NullValueHandling = NullValueHandling.Ignore)] public string BuildEndedAt { get; set; } + + [JsonProperty("totalWarnings")] public int TotalWarnings { get; set; } + [JsonProperty("totalErrors")] public int TotalErrors { get; set; } + + [JsonProperty("files", NullValueHandling = NullValueHandling.Ignore)] public List Files { get; set; } + [JsonProperty("packedAssets", NullValueHandling = NullValueHandling.Ignore)] public List PackedAssets { get; set; } + [JsonProperty("buildSteps", NullValueHandling = NullValueHandling.Ignore)] public List BuildSteps { get; set; } + + [JsonProperty("errors")] public List Errors { get; set; } = new List(); + [JsonProperty("warnings")] public List Warnings { get; set; } = new List(); + } + + /// + /// A single build error/warning with best-effort file/line parsed from the message content. + /// Retained from the original build stub (CLI-127): it is the shared parser used to extract a + /// source location from a raw build-step message and is exercised directly by the test suite. + /// + [Serializable] + class BuildMessage + { + [JsonProperty("severity")] public string Severity { get; set; } + [JsonProperty("file")] public string File { get; set; } + [JsonProperty("line")] public int Line { get; set; } + [JsonProperty("message")] public string Message { get; set; } + + // Matches the standard compiler/build message prefix "Path/To/File.cs(line,col): rest". + static readonly Regex s_LocationPattern = new Regex(@"^(?.*?)\((?\d+),\d+\):\s*(?.*)$", RegexOptions.Singleline); + + /// + /// Build a from a raw build-step message, extracting file/line when + /// the content carries the standard "File.cs(line,col): ..." prefix; otherwise the whole content + /// is kept as the message with no file/line. + /// + public static BuildMessage Parse(string severity, string content) + { + var msg = new BuildMessage { Severity = severity, Message = content ?? string.Empty }; + + if (!string.IsNullOrEmpty(content)) + { + var match = s_LocationPattern.Match(content); + if (match.Success) + { + msg.File = match.Groups["file"].Value.Trim(); + if (int.TryParse(match.Groups["line"].Value, out var line)) + msg.Line = line; + msg.Message = match.Groups["rest"].Value.Trim(); + } + } + + return msg; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/BuildModels.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/BuildModels.cs.meta new file mode 100644 index 0000000..46f8606 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/BuildModels.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 37afada24be667e489d7e90a62f2ca1d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/SwitchBuildTargetCommand.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/SwitchBuildTargetCommand.cs new file mode 100644 index 0000000..a3f293a --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/SwitchBuildTargetCommand.cs @@ -0,0 +1,245 @@ +using System; +using System.IO; +using Newtonsoft.Json; +using Unity.Pipeline.Commands; +using UnityEditor; +using UnityEngine; +#if UNITY_6000_5_OR_NEWER +using Unity.Scripting.LifecycleManagement; +#endif + +namespace Unity.Pipeline.Editor.Commands.Build +{ + /// + /// Switches the active build target (CLI-204). is + /// synchronous, blocks the main thread, and triggers a full asset reimport + domain reload for the new + /// platform — minutes on a large project. So this follows the trigger-then-poll pattern: the command + /// validates and queues the switch, returns switching immediately, and an + /// tick performs the switch. The switch is confirm-gated + /// (destructive and long-running) and is not part of Unity's Undo. + /// + /// The status is persisted to a Temp file that survives the domain reload the switch causes; on the + /// next load reconciles a left-over switching record + /// against the now-active target. switch_build_target_status reads the file off the main thread, + /// so it keeps answering while the switch holds the main thread. + /// + [InitializeOnLoad] +#if UNITY_6000_5_OR_NEWER + [NoAutoStaticsCleanup] +#endif + static class SwitchBuildTargetCommand + { + const string StatusFile = "Temp/pipeline_switch_target_status.json"; + + static readonly object s_Lock = new object(); + static bool s_Pending; + static bool s_Switching; + static BuildTarget s_PendingTarget; + static BuildTarget s_FromTarget; + + static SwitchBuildTargetCommand() + { + EditorApplication.update += OnUpdate; + RecoverInterruptedOperation(); + } + + [CliCommand("switch_build_target", + "Switch the active build target (destructive, long-running: triggers a full reimport + domain " + + "reload). Requires confirm=true. Returns immediately; poll switch_build_target_status.", + MainThreadRequired = false, + Tags = new[] { "build/targets" })] + public static object SwitchBuildTarget( + [CliArg("target", "BuildTarget name to switch to (must be installed; see list_build_targets).", Required = true)] string target = "", + [CliArg("confirm", "Apply the switch. Without it the call is refused.")] bool confirm = false) + { + return RunOnMain(() => ValidateAndQueue(target, confirm)); + } + + static object ValidateAndQueue(string targetArg, bool confirm) + { + if (string.IsNullOrWhiteSpace(targetArg)) + return new { status = "error", success = false, message = "A 'target' is required." }; + + if (!TryParseTarget(targetArg, out var target)) + return new { status = "error", success = false, message = $"Unknown BuildTarget '{targetArg}'. Use a name from list_build_targets." }; + + var group = BuildPipeline.GetBuildTargetGroup(target); + if (!BuildPipeline.IsBuildTargetSupported(group, target)) + return new { status = "error", success = false, message = $"Build target '{target}' is not installed (isInstalled=false in list_build_targets)." }; + + var from = EditorUserBuildSettings.activeBuildTarget; + if (target == from) + return new { status = "completed", success = true, activeBuildTarget = from.ToString(), message = $"Already on build target '{from}'." }; + + lock (s_Lock) + { + if (s_Pending || s_Switching) + return new { status = "busy", success = false, message = "A target switch is already queued or in progress. Poll switch_build_target_status." }; + } + + // Confirm gate. The queue below only sets pending state; the switch runs on the next tick. + if (!confirm) + return new + { + status = "error", + success = false, + message = "Refused: switching the build target triggers a full reimport + domain reload. Pass confirm=true to apply." + }; + + lock (s_Lock) + { + s_FromTarget = from; + s_PendingTarget = target; + s_Pending = true; + } + WriteStatusJson(new + { + status = "switching", + fromTarget = from.ToString(), + toTarget = target.ToString(), + startedAt = DateTime.UtcNow.ToString("o") + }); + + return new { status = "switching", fromTarget = from.ToString(), toTarget = target.ToString() }; + } + + [CliCommand("switch_build_target_status", + "Status of the last target switch: idle | switching | completed (with success + activeBuildTarget).", + MainThreadRequired = false, + Tags = new[] { "build/targets" })] + public static string SwitchBuildTargetStatus() + { + if (File.Exists(StatusFile)) + return File.ReadAllText(StatusFile); + return "{\"status\":\"idle\"}"; + } + + /// Main-thread pump: performs the queued switch. Blocks the main thread until it returns. + static void OnUpdate() + { + BuildTarget target; + BuildTarget from; + lock (s_Lock) + { + if (!s_Pending || s_Switching) + return; + s_Pending = false; + s_Switching = true; + target = s_PendingTarget; + from = s_FromTarget; + } + + try + { + var group = BuildPipeline.GetBuildTargetGroup(target); + + // Synchronous and may trigger a domain reload on success — in which case the code below + // never runs and RecoverInterruptedOperation finalizes the status after the reload. + // (SwitchActiveBuildTarget moved from BuildPipeline to EditorUserBuildSettings in Unity 6.) + var ok = EditorUserBuildSettings.SwitchActiveBuildTarget(group, target); + + if (ok) + WriteStatusJson(new + { + status = "completed", + success = true, + activeBuildTarget = EditorUserBuildSettings.activeBuildTarget.ToString() + }); + else + WriteStatusJson(new + { + status = "completed", + success = false, + target = target.ToString(), + errors = new[] { new { message = $"Failed to switch build target to '{target}'." } } + }); + } + catch (Exception ex) + { + WriteStatusJson(new + { + status = "completed", + success = false, + target = target.ToString(), + errors = new[] { new { message = $"Switch to '{target}' threw: {ex.Message}" } } + }); + } + finally + { + lock (s_Lock) { s_Switching = false; } + } + } + + /// + /// On load, settle a status file left at "switching" by the domain reload a successful switch + /// causes: if the active target now matches the requested one, the switch completed; otherwise it + /// did not take effect. + /// + static void RecoverInterruptedOperation() + { + try + { + if (!File.Exists(StatusFile)) + return; + + var doc = Newtonsoft.Json.Linq.JObject.Parse(File.ReadAllText(StatusFile)); + if ((string)doc["status"] != "switching") + return; + + var toTarget = (string)doc["toTarget"]; + var active = EditorUserBuildSettings.activeBuildTarget.ToString(); + + if (string.Equals(active, toTarget, StringComparison.Ordinal)) + WriteStatusJson(new { status = "completed", success = true, activeBuildTarget = active }); + else + WriteStatusJson(new + { + status = "completed", + success = false, + target = toTarget, + errors = new[] { new { message = $"Switch did not take effect; active build target is '{active}'." } } + }); + } + catch (Exception ex) + { + Debug.LogWarning($"[pipeline] switch_build_target status recovery failed: {ex.Message}"); + } + } + + // ---- Helpers --------------------------------------------------------------------------- + + static bool TryParseTarget(string name, out BuildTarget target) + { + try + { + target = (BuildTarget)Enum.Parse(typeof(BuildTarget), name.Trim(), ignoreCase: true); + return Enum.IsDefined(typeof(BuildTarget), target); + } + catch + { + target = EditorUserBuildSettings.activeBuildTarget; + return false; + } + } + + static T RunOnMain(Func fn) + { + var dispatcher = PipelineServerStartup.Server?.Dispatcher; + if (dispatcher != null && dispatcher.IsInitialized && !dispatcher.IsMainThread()) + return dispatcher.Invoke(fn); + return fn(); + } + + static void WriteStatusJson(object status) + { + try + { + File.WriteAllText(StatusFile, JsonConvert.SerializeObject(status)); + } + catch (Exception ex) + { + Debug.LogError($"[SwitchBuildTarget] Failed to write status file: {ex.Message}"); + } + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/SwitchBuildTargetCommand.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/SwitchBuildTargetCommand.cs.meta new file mode 100644 index 0000000..ccb7ec1 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Build/SwitchBuildTargetCommand.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 5b3d3b7a26bf4a5c8f5522cbfdd0574b diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Capture.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Capture.meta new file mode 100644 index 0000000..34a04a3 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Capture.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 87f4434ff2c6ed6419e6982345ffe0ef +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Capture/CaptureCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Capture/CaptureCommands.cs new file mode 100644 index 0000000..7c8e85c --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Capture/CaptureCommands.cs @@ -0,0 +1,428 @@ +using System; +using System.IO; +using System.Linq; +using System.Reflection; +using Newtonsoft.Json; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor.Authoring; +using UnityEditor; +using UnityEngine; +using UnityEngine.Rendering; +using Object = UnityEngine.Object; + +namespace Unity.Pipeline.Editor.Commands.Capture +{ + /// + /// Visual-feedback commands (CLI-199): render a camera, the Scene View, or the composited game view + /// screen to a PNG and return it base64-encoded, so an agent can "see" the editor without a display. + /// The screen source (AUTHAPI-10) also captures Screen Space - Overlay UI (HUDs) that never renders + /// through a camera. Optionally writes the PNG under the project (sandboxed via + /// ) and refreshes the AssetDatabase. + /// + /// Captures require a GPU; in batchmode/headless the device type is + /// and the commands throw so callers get a clear message + /// instead of an empty image. + /// + static class CaptureCommands + { + private const int MaxDimension = 4096; + + [CliCommand("capture_game_view", "Render the game view to a PNG. source=camera (default) renders a camera and misses Screen Space - Overlay UI; source=screen captures the composited backbuffer incl. overlay canvases (Play Mode only). Returns it inline as base64, unless save_path is set (path-only result; pass include_inline_image=true to get both).", Tags = new[] { "capture" })] + public static CaptureResult CaptureGameView( + [CliArg("width", "Output width in px (default 1280; capped 4096).")] int width = 1280, + [CliArg("height", "Output height in px (default 720; capped 4096).")] int height = 720, + [CliArg("camera", "Optional camera name (source=camera only); defaults to Camera.main, else the first enabled camera.")] string camera = null, + [CliArg("save_path", "Optional project-relative path to write the PNG (e.g. Screenshots/foo.png). When set, the result omits the inline base64 image unless include_inline_image=true.")] string savePath = null, + [CliArg("include_inline_image", "Also return the image inline as base64 when save_path is set (default false: path-only result). Only meaningful together with save_path.")] bool includeInlineImage = false, + [CliArg("max_resolution", "Cap on the inline image's longest edge (e.g. 512). Only applies when an inline image is returned (no save_path, or save_path + include_inline_image=true); the save_path file keeps the requested resolution.")] int maxResolution = 0, + [CliArg("source", "What to capture: 'camera' (default) renders a camera (misses Screen Space - Overlay UI); 'screen' captures the composited game view incl. overlay canvases (HUDs), Play Mode only.")] string source = "camera") + { + var src = (source ?? "camera").Trim().ToLowerInvariant(); + switch (src) + { + case "camera": + { + GuardHasGpu(); + + var cam = ResolveCamera(camera); + if (cam == null) + throw new ArgumentException("No camera found to capture."); + + return Capture((w, h) => EncodeCameraToPng(cam, w, h), $"camera:{cam.name}", + width, height, savePath, includeInlineImage, maxResolution); + } + case "screen": + { + // Overlay UI only composites to the backbuffer at runtime, so screen capture is a + // Play-Mode operation; guard before touching the GPU so the message is deterministic. + if (!Application.isPlaying) + throw new InvalidOperationException( + "capture_game_view with source=\"screen\" requires Play Mode: Screen Space - Overlay UI only composites to the backbuffer at runtime. Use source=\"camera\" in Edit Mode."); + + GuardHasGpu(); + + return Capture(EncodeScreenToPng, "screen", + width, height, savePath, includeInlineImage, maxResolution); + } + default: + throw new ArgumentException($"Unknown source '{source}'. Use 'camera' or 'screen'."); + } + } + + [CliCommand("capture_scene_view", "Render the active Scene View to a PNG. Returns it inline as base64, unless save_path is set (path-only result; pass include_inline_image=true to get both).", Tags = new[] { "capture" })] + public static CaptureResult CaptureSceneView( + [CliArg("width", "Output width in px (default 1280; capped 4096).")] int width = 1280, + [CliArg("height", "Output height in px (default 720; capped 4096).")] int height = 720, + [CliArg("save_path", "Optional project-relative path to write the PNG (e.g. Screenshots/foo.png). When set, the result omits the inline base64 image unless include_inline_image=true.")] string savePath = null, + [CliArg("include_inline_image", "Also return the image inline as base64 when save_path is set (default false: path-only result). Only meaningful together with save_path.")] bool includeInlineImage = false, + [CliArg("max_resolution", "Cap on the inline image's longest edge (e.g. 512). Only applies when an inline image is returned (no save_path, or save_path + include_inline_image=true); the save_path file keeps the requested resolution.")] int maxResolution = 0) + { + GuardHasGpu(); + + var sv = SceneView.lastActiveSceneView; + if (sv == null || sv.camera == null) + throw new ArgumentException("No active Scene View to capture."); + + var cam = sv.camera; + return Capture((w, h) => EncodeCameraToPng(cam, w, h), "sceneView", + width, height, savePath, includeInlineImage, maxResolution); + } + + /// + /// Shared capture core. Renders at the requested (clamped) size via + /// and writes the file when is set. The image is inlined as base64 + /// only when there is no file, or on — a save_path result + /// is otherwise path-only, so agent tool results stay small (AUTHAPI-8). + /// caps the inline image's longest edge (no-op when no inline + /// image is returned); the saved file keeps the requested resolution. + /// is the source-specific encoder — camera render (source=camera / scene view) or screen + /// backbuffer (source=screen, incl. overlay canvases, AUTHAPI-10). + /// + private static CaptureResult Capture(Func renderPng, string source, + int width, int height, string savePath, bool includeInlineImage, int maxResolution) + { + var w = Mathf.Clamp(width, 1, MaxDimension); + var h = Mathf.Clamp(height, 1, MaxDimension); + + var wantsFile = !string.IsNullOrEmpty(savePath); + var wantsInline = !wantsFile || includeInlineImage; + + // Without a file the inline image is the only artifact: the cap applies to the render itself. + if (!wantsFile && maxResolution > 0) + (w, h) = ClampToLongEdge(w, h, maxResolution); + + var png = renderPng(w, h); + var savedPath = WriteIfRequested(png, savePath); + + string base64 = null; + int? inlineW = null, inlineH = null; + if (wantsInline) + { + var inlinePng = png; + if (wantsFile && maxResolution > 0 && maxResolution < Mathf.Max(w, h)) + { + // Re-render small for the inline copy; the file already has the full resolution. + var (iw, ih) = ClampToLongEdge(w, h, maxResolution); + inlinePng = renderPng(iw, ih); + inlineW = iw; + inlineH = ih; + } + base64 = Convert.ToBase64String(inlinePng); + } + + return new CaptureResult + { + Width = w, + Height = h, + Encoding = "png", + Base64 = base64, + Bytes = png.Length, + Source = source, + SavedPath = savedPath, + InlineWidth = inlineW, + InlineHeight = inlineH + }; + } + + /// Scale (w, h) down so the longest edge is at most , preserving aspect. + private static (int w, int h) ClampToLongEdge(int w, int h, int maxEdge) + { + var longest = Mathf.Max(w, h); + if (maxEdge <= 0 || longest <= maxEdge) + return (w, h); + + var scale = (float)maxEdge / longest; + return (Mathf.Max(1, Mathf.RoundToInt(w * scale)), Mathf.Max(1, Mathf.RoundToInt(h * scale))); + } + + /// Throw when no GPU is available (batchmode/headless), where a render would be blank. + private static void GuardHasGpu() + { + if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.Null) + throw new InvalidOperationException("No GPU available (batchmode/headless); cannot capture."); + } + + /// + /// Resolve the camera to capture: by name (if provided), else , + /// else the first enabled camera. Returns null when nothing matches. + /// + private static Camera ResolveCamera(string name) + { + if (!string.IsNullOrEmpty(name)) + { + // Camera.allCameras only includes enabled cameras; also scan all loaded cameras so a + // disabled-but-named camera can still be targeted explicitly. + var byName = Camera.allCameras.FirstOrDefault(c => c.name == name) + ?? PipelineUtils.FindObjectsByType().FirstOrDefault(c => c.name == name); + return byName; + } + + if (Camera.main != null) + return Camera.main; + + return Camera.allCameras.FirstOrDefault(); + } + + /// + /// Render off-screen into a temporary RenderTexture and encode the + /// result to PNG bytes. The camera's target texture and the active RenderTexture are restored + /// in a finally block so capturing never leaves global render state dirty. + /// + private static byte[] EncodeCameraToPng(Camera cam, int w, int h) + { + var rt = RenderTexture.GetTemporary(w, h, 24); + var prevTarget = cam.targetTexture; + var prevActive = RenderTexture.active; + try + { + cam.targetTexture = rt; + cam.Render(); + RenderTexture.active = rt; + + var tex = new Texture2D(w, h, TextureFormat.RGB24, false); + try + { + tex.ReadPixels(new Rect(0, 0, w, h), 0, 0); + tex.Apply(); + return ImageConversion.EncodeToPNG(tex); + } + finally + { + Object.DestroyImmediate(tex); + } + } + finally + { + cam.targetTexture = prevTarget; + RenderTexture.active = prevActive; + RenderTexture.ReleaseTemporary(rt); + } + } + + /// + /// Capture the composited game view — including Screen Space - Overlay canvases and other + /// screen-space UI that never render through a camera (AUTHAPI-10) — and encode it to PNG, + /// scaled to the requested size. + /// + /// The primary source is the game view's own render target (see + /// ): the most recently rendered game frame at its true + /// pixel resolution, independent of window focus and OS display scaling. The old + /// path had two field-reported bugs: + /// it reads a Screen-sized rect in GUI points from a backbuffer sized in physical + /// pixels, cropping the frame on scaled displays (e.g. 150% OS scaling), and its + /// result texture round-trips gamma twice in Linear projects, washing out every capture. + /// + private static byte[] EncodeScreenToPng(int w, int h) + { + var outRt = RenderTexture.GetTemporary(w, h, 0, RenderTextureFormat.ARGB32); + var prevActive = RenderTexture.active; + RenderTexture fallbackRt = null; + try + { + var source = GetGameViewTargetTexture(); + if (source == null) + { + // Fallback when the internal PlayModeView API is unavailable: ask ScreenCapture for + // the composited view. Less deterministic — when the editor runs unfocused it can + // capture whichever editor view renders next — but keeps the command functional. + var (screenW, screenH) = GetGameViewTargetSize(); + fallbackRt = RenderTexture.GetTemporary(screenW, screenH, 0, RenderTextureFormat.ARGB32); + + // GetTemporary pools RTs: clear before capturing so a skipped/partial capture can + // never leak a stale frame from an earlier capture. + RenderTexture.active = fallbackRt; + GL.Clear(true, true, Color.black); + + // Unbind before capturing: CaptureScreenshotIntoRenderTexture silently writes + // nothing while its destination is the currently-active RenderTexture (verified + // empirically — the capture comes back all black). + RenderTexture.active = prevActive; + ScreenCapture.CaptureScreenshotIntoRenderTexture(fallbackRt); + source = fallbackRt; + } + + // Scale to the requested output size. Default read/write semantics keep the blit + // conversion-neutral, so the display-ready values reach the PNG unchanged (no double + // gamma). The source holds GPU-UV-oriented content: on APIs where UV(0,0) is the top + // (D3D, Metal, Vulkan) it arrives vertically flipped, so un-flip in the blit. + if (SystemInfo.graphicsUVStartsAtTop) + Graphics.Blit(source, outRt, new Vector2(1f, -1f), new Vector2(0f, 1f)); + else + Graphics.Blit(source, outRt); + RenderTexture.active = outRt; + + var tex = new Texture2D(w, h, TextureFormat.RGB24, false); + try + { + tex.ReadPixels(new Rect(0, 0, w, h), 0, 0); + tex.Apply(); + return ImageConversion.EncodeToPNG(tex); + } + finally + { + Object.DestroyImmediate(tex); + } + } + finally + { + RenderTexture.active = prevActive; + RenderTexture.ReleaseTemporary(outRt); + if (fallbackRt != null) + RenderTexture.ReleaseTemporary(fallbackRt); + } + } + + /// + /// The game view's own render target (via the internal PlayModeView API), or null when + /// unavailable. This is the most reliable "what the game view shows" source: the + /// ScreenCapture APIs capture whichever editor view happens to render, which is + /// focus-dependent — an unfocused/background editor (the normal state for an agent-driven + /// editor) can hand back an editor panel (Hierarchy, Inspector) instead of the game. The + /// target texture holds the game view's most recently rendered frame — overlay canvases + /// included — at its true pixel resolution, independent of focus and display scaling. + /// + private static RenderTexture GetGameViewTargetTexture() + { + try + { + var playModeView = Type.GetType("UnityEditor.PlayModeView,UnityEditor"); + var getMain = playModeView?.GetMethod("GetMainPlayModeView", + BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); + var view = getMain?.Invoke(null, null); + if (view == null) + return null; + + var field = playModeView.GetField("m_TargetTexture", + BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); + var rt = field?.GetValue(view) as RenderTexture; + return rt != null && rt.IsCreated() ? rt : null; + } + catch + { + // Internal API changed — callers fall back to the ScreenCapture path. + return null; + } + } + + /// + /// Size of the game view's actual render target, in pixels. Screen.width/height in + /// editor main-thread code report the CURRENT GUI view — which is focus-dependent and can be + /// the main editor window rather than the game view (observed as black bars / truncated + /// captures). The internal PlayModeView API reports the true target size regardless of focus + /// and display scaling; fall back to Screen when the internal API is unavailable. + /// + private static (int w, int h) GetGameViewTargetSize() + { + try + { + var playModeView = Type.GetType("UnityEditor.PlayModeView,UnityEditor"); + var method = playModeView?.GetMethod("GetMainPlayModeViewTargetSize", + BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); + if (method != null) + { + var size = (Vector2)method.Invoke(null, null); + if (size.x >= 1f && size.y >= 1f) + return ((int)size.x, (int)size.y); + } + } + catch + { + // Internal API changed/unavailable — the Screen fallback below still works whenever + // the game view is the current context. + } + + return (Screen.width, Screen.height); + } + + /// + /// When is set, validate it through the project-path sandbox, + /// write the PNG to its absolute filesystem location, refresh the AssetDatabase, and return + /// the resolved project-relative asset path. Returns null when no path was requested. + /// + private static string WriteIfRequested(byte[] png, string savePath) + { + if (string.IsNullOrEmpty(savePath)) + return null; + + var resolved = ProjectPaths.Resolve(savePath, out var err); + if (resolved == null) + throw new ArgumentException(err); + + // ProjectPaths.Resolve returns a project-relative path; combine it with the project root + // (the folder that contains Assets/) to get the absolute file to write. + var absolute = Path.Combine(ProjectPaths.ProjectRoot, resolved); + var directory = Path.GetDirectoryName(absolute); + if (!string.IsNullOrEmpty(directory)) + Directory.CreateDirectory(directory); + + File.WriteAllBytes(absolute, png); + AssetDatabase.Refresh(); + return resolved; + } + } + + /// + /// Result of a capture command: the rendered dimensions, the source, the project-relative path + /// the PNG was written to (null when not saved), and the base64 payload — omitted from the JSON + /// when a save_path result is path-only (AUTHAPI-8). + /// + [Serializable] + class CaptureResult + { + /// Rendered width in pixels (after clamping). + [JsonProperty("width")] + public int Width { get; set; } + + /// Rendered height in pixels (after clamping). + [JsonProperty("height")] + public int Height { get; set; } + + /// Image encoding; always "png". + [JsonProperty("encoding")] + public string Encoding { get; set; } + + /// Base64-encoded PNG bytes; null (omitted) when save_path is set without include_inline_image. + [JsonProperty("base64", NullValueHandling = NullValueHandling.Ignore)] + public string Base64 { get; set; } + + /// Length of the raw PNG byte array. + [JsonProperty("bytes")] + public int Bytes { get; set; } + + /// What was captured, e.g. "camera:Main Camera" or "sceneView". + [JsonProperty("source")] + public string Source { get; set; } + + /// Project-relative path the PNG was also written to, or null. + [JsonProperty("savedPath")] + public string SavedPath { get; set; } + + /// Inline image width when max_resolution downscaled it below the saved file's; omitted otherwise. + [JsonProperty("inlineWidth", NullValueHandling = NullValueHandling.Ignore)] + public int? InlineWidth { get; set; } + + /// Inline image height when max_resolution downscaled it below the saved file's; omitted otherwise. + [JsonProperty("inlineHeight", NullValueHandling = NullValueHandling.Ignore)] + public int? InlineHeight { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Capture/CaptureCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Capture/CaptureCommands.cs.meta new file mode 100644 index 0000000..bb1dd0e --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Capture/CaptureCommands.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3247a78c799021c4094dd3f7e3717aeb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/CaptureEditorElementCommand.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/CaptureEditorElementCommand.cs new file mode 100644 index 0000000..20c3022 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/CaptureEditorElementCommand.cs @@ -0,0 +1,78 @@ +#if UNITY_6000_7_OR_NEWER +using System.IO; +using System.Linq; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Runtime.Commands; +using UnityEditor; +using UnityEngine; +using UnityEngine.UIElements; + +namespace Unity.Pipeline.Editor.Commands +{ + /// + /// Captures a UI Toolkit from an to a PNG + /// and returns it base64-encoded (and writes it to disk). The element is located by a USS-like + /// selector within the window's . + /// + /// Selection, capture, and encoding are shared with the runtime command via + /// ; this command only resolves the target window. + /// + static class CaptureEditorElementCommand + { + [CliCommand("capture_editor_element", + "Capture a UI Toolkit VisualElement (by selector) from an EditorWindow to a PNG; returns path + base64.", + MainThreadRequired = true, + Tags = new[] { "capture", "ui" })] + public static CaptureElementResponse CaptureEditorElement( + [CliArg("window", "EditorWindow type name (e.g. InspectorWindow) or window title to capture from.", Required = true)] string window = "", + [CliArg("selector", "Element selector: '#name', '.class', a type name (e.g. Button), descendant (space) / child ('>') chains, optional pseudo-states (:checked,:hover,:focus,:active,:enabled,:disabled,:not(...)).", Required = true)] string selector = "", + [CliArg("output", "Output PNG path (absolute, or relative to the project root). Defaults to a timestamped file under /Temp/pipeline-screenshots/.")] string output = "") + { + if (string.IsNullOrWhiteSpace(window)) + return CaptureElementResponse.Fail("A 'window' (EditorWindow type name or title) is required."); + if (string.IsNullOrWhiteSpace(selector)) + return CaptureElementResponse.Fail("A 'selector' is required."); + + var target = ResolveWindow(window); + if (target == null) + return CaptureElementResponse.Fail( + $"No open EditorWindow matched '{window}' (by type name or title). Open the window first."); + + var root = target.rootVisualElement; + if (root == null) + return CaptureElementResponse.Fail($"EditorWindow '{window}' has no rootVisualElement."); + + var element = VisualElementCaptureSupport.ResolveElement(root, selector); + if (element == null) + return CaptureElementResponse.Fail( + $"No element matched selector '{selector}' in window '{window}'."); + + var projectRoot = Path.GetDirectoryName(Application.dataPath); + var defaultDir = Path.Combine(projectRoot, "Temp", "pipeline-screenshots"); + return VisualElementCaptureSupport.CaptureAndRespond( + element, selector, $"window:{window}", output, + relativeBaseDir: projectRoot, defaultDir: defaultDir, prefix: "element"); + } + + /// + /// Find an open EditorWindow whose runtime type name or title matches . + /// Uses Resources.FindObjectsOfTypeAll so hidden/utility windows are included too, but + /// prefers a match whose root is actually attached to a panel — FindObjectsOfTypeAll can + /// also return stale/backup window instances whose rootVisualElement has no panel (and + /// therefore cannot be captured). + /// + static EditorWindow ResolveWindow(string window) + { + var windows = Resources.FindObjectsOfTypeAll(); + + bool Matches(EditorWindow w) => + w.GetType().Name == window || + (w.titleContent != null && w.titleContent.text == window); + + return windows.FirstOrDefault(w => Matches(w) + && w.rootVisualElement != null && w.rootVisualElement.panel != null) + ?? windows.FirstOrDefault(Matches); + } + } +} +#endif diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/CaptureEditorElementCommand.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/CaptureEditorElementCommand.cs.meta new file mode 100644 index 0000000..1b875f3 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/CaptureEditorElementCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d09a03ff1d920b24080d933c3191e192 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/EditorStatusCommand.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/EditorStatusCommand.cs new file mode 100644 index 0000000..2035d81 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/EditorStatusCommand.cs @@ -0,0 +1,63 @@ +using System; +using System.IO; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Models; +using UnityEditor; +using UnityEngine; + +namespace Unity.Pipeline.Editor.Commands +{ + /// + /// Command to get detailed Editor status information. + /// Returns rich Editor state including compilation, play mode, and project details. + /// Accessible via "unity request editor_status" and "/api/editor_status" endpoint. + /// + static class EditorStatusCommand + { + [CliCommand("editor_status", "Get detailed Unity Editor status and state information", Tags = new[] { "editor" })] + public static StatusResponse GetEditorStatus() + { + return new StatusResponse + { + Status = GetOverallStatus(), + Compiling = EditorApplication.isCompiling, + DomainReloadInProgress = EditorApplication.isUpdating, + PlayMode = GetPlayModeStatus(), + LastHeartbeat = DateTime.UtcNow, + ProjectPath = Path.GetDirectoryName(Application.dataPath), + UnityVersion = Application.unityVersion + }; + } + + /// + /// Get overall Editor status based on current state. + /// + private static string GetOverallStatus() + { + if (EditorApplication.isCompiling) + return "compiling"; + + if (EditorApplication.isUpdating) + return "reloading"; + + if (EditorApplication.isPlaying || EditorApplication.isPaused) + return "playing"; + + return "ready"; + } + + /// + /// Get current play mode status. + /// + private static string GetPlayModeStatus() + { + if (EditorApplication.isPaused) + return "paused"; + + if (EditorApplication.isPlaying) + return "playing"; + + return "stopped"; + } + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/EditorStatusCommand.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/EditorStatusCommand.cs.meta new file mode 100644 index 0000000..5699589 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/EditorStatusCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 953fb97ec3dd48e4aa2ed9607c412f44 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/FocusEditorCommand.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/FocusEditorCommand.cs new file mode 100644 index 0000000..c330464 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/FocusEditorCommand.cs @@ -0,0 +1,124 @@ +using System; +using System.Reflection; +using Unity.Pipeline.Commands; +using UnityEditor; +using UnityEngine; +#if UNITY_6000_5_OR_NEWER +using Unity.Scripting.LifecycleManagement; +#endif + +namespace Unity.Pipeline.Editor.Commands +{ + /// + /// Brings the Unity Editor application to the foreground (and restores it if minimized) by + /// focusing the main window's HostView. + /// + /// ContainerWindow / HostView / GUIView are internal, so this uses reflection. GUIView.Focus() + /// maps to the native MonoGUIView::Focus, which activates the OS window. Useful for headless + /// automation: the editor throttles/defers some work (notably script compilation) while + /// unfocused, so a client can call this to bring it forward first. + /// +#if UNITY_6000_5_OR_NEWER + [NoAutoStaticsCleanup] +#endif + static class FocusEditorCommand + { + const BindingFlags k_All = BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; + + static Type s_ContainerWindowType; + static Type s_HostViewType; + static MethodInfo s_IsMainWindow; + static MethodInfo s_GuiViewFocus; + static bool s_Resolved; + + [CliCommand("editor_focus", "Bring the Unity Editor window to the foreground", MainThreadRequired = true, Tags = new[] { "editor" })] + public static string FocusEditor() + { + if (!ResolveReflection(out var error)) + return error; + + try + { + object mainWindow = null; + foreach (var w in Resources.FindObjectsOfTypeAll(s_ContainerWindowType)) + { + if ((bool)s_IsMainWindow.Invoke(w, null)) { mainWindow = w; break; } + } + if (mainWindow == null) + return "Error: main editor window not found"; + + var rootView = GetRootView(mainWindow); + if (rootView == null) + return "Error: main window has no root view"; + + var host = FindHostView(rootView); + if (host == null) + return "Error: no HostView found in main window"; + + s_GuiViewFocus.Invoke(host, null); + return $"Editor focused via {host.GetType().Name}"; + } + catch (Exception ex) + { + return $"Error: failed to focus editor: {ex.Message}"; + } + } + + static bool ResolveReflection(out string error) + { + error = null; + if (s_Resolved) return true; + + var asm = typeof(EditorWindow).Assembly; + s_ContainerWindowType = asm.GetType("UnityEditor.ContainerWindow"); + s_HostViewType = asm.GetType("UnityEditor.HostView"); + var guiViewType = asm.GetType("UnityEditor.GUIView"); + + if (s_ContainerWindowType == null || s_HostViewType == null || guiViewType == null) + { + error = "Error: internal editor window types not found (Unity version mismatch?)"; + return false; + } + + s_IsMainWindow = s_ContainerWindowType.GetMethod("IsMainWindow", k_All); + s_GuiViewFocus = guiViewType.GetMethod("Focus", k_All, null, Type.EmptyTypes, null); + + if (s_IsMainWindow == null || s_GuiViewFocus == null) + { + error = "Error: ContainerWindow.IsMainWindow or GUIView.Focus not found (internal API changed?)"; + return false; + } + + s_Resolved = true; + return true; + } + + static object GetRootView(object mainWindow) + { + var prop = s_ContainerWindowType.GetProperty("rootView", k_All); + if (prop != null) + return prop.GetValue(mainWindow); + return s_ContainerWindowType.GetField("m_RootView", k_All)?.GetValue(mainWindow); + } + + static object FindHostView(object rootView) + { + if (s_HostViewType.IsInstanceOfType(rootView)) + return rootView; + + if (!(rootView.GetType().GetProperty("allChildren", k_All)?.GetValue(rootView) is Array allChildren)) + return null; + + // Prefer a DockArea (an actual docked panel) over the Toolbar, but any HostView works + // to bring the main window — and thus the application — to the foreground. + object firstHost = null; + foreach (var c in allChildren) + { + if (c == null || !s_HostViewType.IsInstanceOfType(c)) continue; + if (firstHost == null) firstHost = c; + if (c.GetType().Name == "DockArea") return c; + } + return firstHost; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/FocusEditorCommand.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/FocusEditorCommand.cs.meta new file mode 100644 index 0000000..77c9f41 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/FocusEditorCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f146c518ed01a1b4a9be8a546cdfbde5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects.meta new file mode 100644 index 0000000..ccc362e --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c2281ed89e8a4db9a14ec523905221f9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/ComponentCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/ComponentCommands.cs new file mode 100644 index 0000000..c38bb70 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/ComponentCommands.cs @@ -0,0 +1,214 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json.Linq; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Models; +using UnityEditor; +using UnityEngine; + +namespace Unity.Pipeline.Editor.Commands.GameObjects +{ + /// + /// Component authoring commands (CLI-192): add/remove a component on a GameObject and get/set its + /// serialized properties. + /// + /// WHY property get/set goes exclusively through / + /// : it is the only mutation path that dirties the object, records + /// prefab overrides, and registers a single Undo step (via + + /// ) the way the Inspector does. Direct + /// reflection on backing fields would silently desync the Editor. Component types are resolved by + /// name across all loaded assemblies () so agents can use short or + /// fully-qualified names. + /// + static class ComponentCommands + { + /// + /// Add a component (resolved by type name) to a GameObject. Registered with + /// via the non-generic overload so the addition + /// is reversible. Returns the new component's identity so its properties can be set next. + /// + [CliCommand("add_component", "Add a component (by type name) to a GameObject.", Tags = new[] { "gameobjects/components" })] + public static AuthoringResult AddComponent( + [CliArg("target", "Handle of the GameObject.", Required = true)] ObjectRef target, + [CliArg("type", "Component type name (e.g. 'Rigidbody' or 'UnityEngine.Camera').", Required = true)] string type) + { + var go = GameObjectCommands.ResolveGameObject(target, "target"); + var componentType = TypeResolver.ResolveComponentType(type); + if (componentType == null) + throw new ArgumentException($"Could not resolve component type '{type}'."); + + using (new AuthoringUndoScope("Add Component")) + { + var component = Undo.AddComponent(go, componentType); + if (component == null) + throw new InvalidOperationException( + $"Failed to add component '{componentType.Name}' to '{go.name}' (it may be disallowed on this GameObject)."); + + GameObjectCommands.MarkDirty(go); + return ObjectResolver.Describe(component); + } + } + + /// + /// Remove a component from a GameObject. The component is addressed directly by handle (an + /// resolving to a Component), or by GameObject handle plus a type name. + /// Uses so the removal is reversible. + /// + [CliCommand("remove_component", + "Remove a component from a GameObject. Provide either a component handle (target) or a GameObject handle (target) plus a type name.", + Tags = new[] { "gameobjects/components" })] + public static AuthoringResult RemoveComponent( + [CliArg("target", "Handle of the component to remove, OR of the GameObject when 'type' is given.", Required = true)] ObjectRef target, + [CliArg("type", "Component type name to remove from the target GameObject (omit when 'target' already points at a component).")] string type = null) + { + var component = ResolveComponent(target, type); + var go = component.gameObject; + var described = ObjectResolver.Describe(component); + + using (new AuthoringUndoScope("Remove Component")) + { + Undo.DestroyObjectImmediate(component); + GameObjectCommands.MarkDirty(go); + } + + return described; + } + + /// + /// Read the serialized properties of a component as a JSON map. Iterates the visible serialized + /// surface (skipping the script reference) and converts each property with + /// . + /// + [CliCommand("get_component_properties", + "Get a component's serialized properties as a JSON map. Address the component by handle, or by GameObject handle + type.", + Tags = new[] { "gameobjects/components" })] + public static ComponentPropertiesResult GetComponentProperties( + [CliArg("target", "Handle of the component, OR of the GameObject when 'type' is given.", Required = true)] ObjectRef target, + [CliArg("type", "Component type name on the target GameObject (omit when 'target' is a component handle).")] string type = null) + { + var component = ResolveComponent(target, type); + var so = new SerializedObject(component); + + var properties = new Dictionary(); + var iterator = so.GetIterator(); + var enterChildren = true; + while (iterator.NextVisible(enterChildren)) + { + enterChildren = false; // only iterate top-level visible properties + if (iterator.name == "m_Script") + continue; + + try + { + properties[iterator.name] = SerializedPropertyConverter.Read(iterator.Copy()); + } + catch (Exception ex) + { + properties[iterator.name] = new JValue($""); + } + } + + return new ComponentPropertiesResult + { + Component = ObjectResolver.Describe(component), + Properties = properties + }; + } + + /// + /// Set one or more serialized properties on a component. Each entry in + /// maps a property path (e.g. "m_Mass" or "myField") to a JSON value. The whole batch is one + /// Undo step: snapshots the component, every property is written + /// through , and + /// commits + dirties as one operation. + /// An unknown property name fails the whole batch with a clear error (no partial apply). + /// + [CliCommand("set_component_properties", + "Set serialized properties on a component (one Undo step). 'properties' maps property name -> value; object references accept an ObjectRef handle.", + Tags = new[] { "gameobjects/components" })] + public static ComponentPropertiesResult SetComponentProperties( + [CliArg("target", "Handle of the component, OR of the GameObject when 'type' is given.", Required = true)] ObjectRef target, + [CliArg("properties", "Map of serialized property name to value. Vectors/colors are arrays; object refs are handle objects.", Required = true)] JObject properties, + [CliArg("type", "Component type name on the target GameObject (omit when 'target' is a component handle).")] string type = null) + { + if (properties == null || properties.Count == 0) + throw new ArgumentException("'properties' must contain at least one property to set."); + + var component = ResolveComponent(target, type); + + using (new AuthoringUndoScope("Set Component Properties")) + { + Undo.RecordObject(component, "Set Component Properties"); + var so = new SerializedObject(component); + + foreach (var pair in properties) + { + var property = so.FindProperty(pair.Key); + if (property == null) + throw new ArgumentException( + $"Component '{component.GetType().Name}' has no serialized property '{pair.Key}'."); + + SerializedPropertyConverter.Write(property, pair.Value); + } + + // Applies the changes, registers Undo, and dirties the object/scene. + so.ApplyModifiedProperties(); + GameObjectCommands.MarkDirty(component.gameObject); + } + + // Re-read so the caller sees the committed values. + return GetComponentProperties(target, type); + } + + #region Helpers + + /// + /// Resolve a component either directly (the handle points at a Component) or by GameObject + /// handle + type name. Throws a descriptive error when neither resolves. + /// + private static Component ResolveComponent(ObjectRef handle, string type) + { + if (!ObjectResolver.TryResolve(handle, out var obj, out var error)) + throw new ArgumentException($"Could not resolve 'target': {error}"); + + // The handle already points at a specific Component: honour it directly so we never + // mutate/remove the wrong instance when the GameObject has several components of the same + // type. A 'type' here is only a constraint to validate against, NOT a reason to re-fetch + // GetComponent(type) (which returns the first match and would ignore the handle). + if (obj is Component directComponent) + { + if (!string.IsNullOrEmpty(type)) + { + var requestedType = TypeResolver.ResolveComponentType(type); + if (requestedType == null) + throw new ArgumentException($"Could not resolve component type '{type}'."); + if (!requestedType.IsInstanceOfType(directComponent)) + throw new ArgumentException( + $"'target' resolves to a {directComponent.GetType().Name}, which is not a '{requestedType.Name}'."); + } + + return directComponent; + } + + var go = obj as GameObject; + if (go == null) + throw new ArgumentException($"'target' did not resolve to a GameObject or Component (got {obj.GetType().Name})."); + + if (string.IsNullOrEmpty(type)) + throw new ArgumentException("'type' is required when 'target' is a GameObject."); + + var componentType = TypeResolver.ResolveComponentType(type); + if (componentType == null) + throw new ArgumentException($"Could not resolve component type '{type}'."); + + var component = go.GetComponent(componentType); + if (component == null) + throw new ArgumentException($"GameObject '{go.name}' has no component of type '{componentType.Name}'."); + + return component; + } + + #endregion + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/ComponentCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/ComponentCommands.cs.meta new file mode 100644 index 0000000..37d0ba6 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/ComponentCommands.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 1a7470ef26f8497595bcbdb84ceb96dc diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/ComponentPropertiesResult.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/ComponentPropertiesResult.cs new file mode 100644 index 0000000..942ffd8 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/ComponentPropertiesResult.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Unity.Pipeline.Models; + +namespace Unity.Pipeline.Editor.Commands.GameObjects +{ + /// + /// Structured result for get_component_properties / set_component_properties. + /// WHY it pairs the component identity with the property map: the caller gets back both the + /// canonical handle (to reference the component again) and the + /// current serialized values in one round trip, which also makes set return the committed state + /// for a read-after-write check. + /// + sealed class ComponentPropertiesResult + { + /// Canonical identity of the component the properties belong to. + [JsonProperty("component")] + public AuthoringResult Component { get; set; } + + /// Map of serialized property name to its JSON value. + [JsonProperty("properties")] + public Dictionary Properties { get; set; } = new Dictionary(); + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/ComponentPropertiesResult.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/ComponentPropertiesResult.cs.meta new file mode 100644 index 0000000..9a9f83c --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/ComponentPropertiesResult.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: e87b3f2873ff4bac9229a28242917ac0 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/CreateGameObjectsResult.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/CreateGameObjectsResult.cs new file mode 100644 index 0000000..4ebd0bd --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/CreateGameObjectsResult.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Unity.Pipeline.Models; + +namespace Unity.Pipeline.Editor.Commands.GameObjects +{ + /// + /// Structured result for the batch create_gameobjects command (CLI-223). WHY a dedicated + /// envelope rather than a bare array: it carries the created alongside the + /// list so an agent can confirm the whole batch landed in one round-trip without inspecting array + /// length, and mirrors so the GameObject command surface stays + /// consistent. Each entry is the same canonical identity returned by + /// the single-object create_gameobject, so any created object can be fed straight back as an + /// in a follow-up call. + /// + sealed class CreateGameObjectsResult + { + /// Number of GameObjects created in the batch. + [JsonProperty("count")] + public int Count { get; set; } + + /// Canonical identities of the created GameObjects, in creation order. + [JsonProperty("gameObjects")] + public List GameObjects { get; set; } = new List(); + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/CreateGameObjectsResult.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/CreateGameObjectsResult.cs.meta new file mode 100644 index 0000000..d78945b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/CreateGameObjectsResult.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 671f5065c22d6474b80053b6da5a84ef +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/FindGameObjectsResult.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/FindGameObjectsResult.cs new file mode 100644 index 0000000..eedbd7a --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/FindGameObjectsResult.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Unity.Pipeline.Models; + +namespace Unity.Pipeline.Editor.Commands.GameObjects +{ + /// + /// Structured result for find_gameobjects. WHY a dedicated envelope rather than a bare + /// array: it carries the match alongside the list so an agent can branch on + /// "found / not found / ambiguous" without inspecting array length, and leaves room to add query + /// metadata later without breaking the shape. Each entry is the same canonical + /// identity returned by the single-object commands, so a result can + /// be fed straight back as an in a follow-up call. + /// + sealed class FindGameObjectsResult + { + /// Number of GameObjects that matched the query. + [JsonProperty("count")] + public int Count { get; set; } + + /// Canonical identities of the matching GameObjects. + [JsonProperty("gameObjects")] + public List GameObjects { get; set; } = new List(); + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/FindGameObjectsResult.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/FindGameObjectsResult.cs.meta new file mode 100644 index 0000000..23d924c --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/FindGameObjectsResult.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 1d12bf4a53c14a839c26a91e8ec68292 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/GameObjectCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/GameObjectCommands.cs new file mode 100644 index 0000000..1388faa --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/GameObjectCommands.cs @@ -0,0 +1,538 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Models; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; +using UnityEngine.SceneManagement; +using Object = UnityEngine.Object; + +namespace Unity.Pipeline.Editor.Commands.GameObjects +{ + /// + /// GameObject authoring commands (CLI-192): creating GameObjects, querying the scene hierarchy, + /// and mutating the core GameObject/Transform surface (parenting, transform, active state, tag, + /// layer, name, deletion). + /// + /// WHY these go through the same conventions as the rest of the authoring foundation: + /// every mutation is wrapped in an and registered with Unity's + /// Undo system so an agent's multi-step action reverts as a single collapsible step. Each + /// mutated object is marked dirty (and its scene flagged dirty) so the change survives a Save and + /// is visible to the rest of the Editor. Results come back as the canonical + /// envelope (via ) so the + /// agent can address the same object in a follow-up call. + /// + static class GameObjectCommands + { + /// + /// Create an empty GameObject or a built-in primitive in the active scene. + /// + /// Creation goes through for primitives (so the + /// matching mesh + collider are attached exactly as the Editor would) and a plain + /// new GameObject for the empty case. The object is registered with + /// so it can be reverted, and an optional parent + /// is resolved by handle so a whole hierarchy can be built in one sequence of calls. + /// + [CliCommand("create_gameobject", + "Create an empty GameObject or a built-in primitive (cube/sphere/capsule/cylinder/plane/quad) in the active scene.", + Tags = new[] { "gameobjects" })] + public static AuthoringResult CreateGameObject( + [CliArg("name", "Name for the new GameObject. Defaults to 'GameObject' (or the primitive name).")] string name = null, + [CliArg("primitive", "Optional primitive type: cube, sphere, capsule, cylinder, plane, quad. Omit for an empty GameObject.")] string primitive = null, + [CliArg("parent", "Optional parent handle (globalId/path/guid/instanceId/hierarchyPath). The new object becomes a child of it.")] ObjectRef parent = null) + { + // Resolve the parent once, outside the scope, so a bad handle fails before any creation. + var parentTransform = ResolveParentTransform(parent); + + using (new AuthoringUndoScope("Create GameObject")) + { + var go = CreateOne(primitive, name, parentTransform); + MarkDirty(go); + return ObjectResolver.Describe(go); + } + } + + /// + /// Create N GameObjects (empty or a primitive) in one server round-trip (CLI-223). + /// + /// WHY a separate plural command rather than overloading : the + /// single command's contract — one call returns one — is relied + /// on by existing callers and tests, so it is left untouched. This plural command is the batch + /// surface and returns a envelope (count + per-item + /// identities). When > 1 and no explicit name array is supplied, + /// each object is suffixed Name1..NameN so they remain individually addressable. + /// + /// Per-index // + /// are arrays of [x,y,z] vectors. When a vectors array is supplied its length MUST equal + /// (a mismatch is a validation error). Omitted channels leave the + /// object at its creation default (origin / identity / unit scale). The whole batch is wrapped + /// in ONE so it reverts as a single Undo step. + /// + [CliCommand("create_gameobjects", + "Batch-create N empty GameObjects or primitives in one call. Optional positions/rotations/scales are arrays of [x,y,z] (length must equal count). Returns the created identities.", + Tags = new[] { "gameobjects" })] + public static CreateGameObjectsResult CreateGameObjects( + [CliArg("name", "Base name. With count>1 and no explicit names, objects are suffixed Name1..NameN.")] string name = null, + [CliArg("primitive", "Optional primitive type: cube, sphere, capsule, cylinder, plane, quad. Omit for empty GameObjects.")] string primitive = null, + [CliArg("parent", "Optional parent handle. Every created object becomes a child of it.")] ObjectRef parent = null, + [CliArg("count", "How many GameObjects to create. Default 1.")] int count = 1, + [CliArg("positions", "Local positions, one [x,y,z] per object. Length must equal count when supplied.")] float[][] positions = null, + [CliArg("rotations", "Local Euler rotations (degrees), one [x,y,z] per object. Length must equal count when supplied.")] float[][] rotations = null, + [CliArg("scales", "Local scales, one [x,y,z] per object. Length must equal count when supplied.")] float[][] scales = null) + { + if (count < 1) + throw new ArgumentException($"'count' must be at least 1, got {count}."); + + ValidateVectorArray(positions, count, "positions"); + ValidateVectorArray(rotations, count, "rotations"); + ValidateVectorArray(scales, count, "scales"); + + // Resolve the parent once, outside the scope, so a bad handle fails before any creation. + var parentTransform = ResolveParentTransform(parent); + + var result = new CreateGameObjectsResult(); + using (new AuthoringUndoScope("Create GameObjects")) + { + for (int i = 0; i < count; i++) + { + // count==1 keeps the bare name (no "1" suffix) so a single-item batch reads + // naturally; count>1 suffixes 1..N for individual addressability. + var itemName = count > 1 && !string.IsNullOrEmpty(name) ? name + (i + 1) : name; + var go = CreateOne(primitive, itemName, parentTransform); + + // Index the arg name so a null/mis-shaped entry names the offending element + // (a JSON array may contain a null entry even when its length matches count). + if (positions != null) + go.transform.localPosition = ToVector3(positions[i], $"positions[{i}]"); + if (rotations != null) + go.transform.localEulerAngles = ToVector3(rotations[i], $"rotations[{i}]"); + if (scales != null) + go.transform.localScale = ToVector3(scales[i], $"scales[{i}]"); + + MarkDirty(go); + result.GameObjects.Add(ObjectResolver.Describe(go)); + } + } + + result.Count = result.GameObjects.Count; + return result; + } + + /// + /// Find GameObjects in the loaded scenes by name, tag, component type, and/or hierarchy path. + /// All supplied filters are combined (AND). Returns the canonical identity of each match so an + /// agent can act on the results without a second lookup. + /// + /// This is intentionally a structured query rather than a single-object resolve: agents need + /// to discover what exists before they can reference it, and the result set carries the same + /// identities used everywhere else. + /// + [CliCommand("find_gameobjects", + "Find GameObjects in loaded scenes by name, tag, component type, and/or hierarchy path (filters are combined). Returns structured identities.", + Tags = new[] { "gameobjects" })] + public static FindGameObjectsResult FindGameObjects( + [CliArg("name", "Exact name to match.")] string name = null, + [CliArg("tag", "Tag to match (e.g. 'Player').")] string tag = null, + [CliArg("type", "Component type name to match (e.g. 'Rigidbody', 'UnityEngine.Camera').")] string type = null, + [CliArg("hierarchy_path", "Exact hierarchy path to match (e.g. '/Root/Child').")] string hierarchyPath = null, + [CliArg("include_inactive", "Include inactive GameObjects. Default true.")] bool includeInactive = true) + { + Type componentType = null; + if (!string.IsNullOrEmpty(type)) + { + componentType = TypeResolver.ResolveComponentType(type); + if (componentType == null) + throw new ArgumentException($"Could not resolve component type '{type}'."); + } + + // Resolve the hierarchy filter once so it is comparable to each object's computed path. + var hierarchyFilter = string.IsNullOrEmpty(hierarchyPath) ? null : NormalizeHierarchyPath(hierarchyPath); + + // Validate the tag up front: comparing against an undefined tag (CompareTag / .tag) would + // log a Unity error per object. An unknown tag simply yields no matches. + if (!string.IsNullOrEmpty(tag) && !InternalEditorTagExists(tag)) + return new FindGameObjectsResult { Count = 0, GameObjects = new List() }; + + var matches = new List(); + foreach (var go in EnumerateSceneGameObjects(includeInactive)) + { + if (!string.IsNullOrEmpty(name) && go.name != name) + continue; + + if (!string.IsNullOrEmpty(tag) && go.tag != tag) + continue; + + if (componentType != null && go.GetComponent(componentType) == null) + continue; + + if (hierarchyFilter != null && GetHierarchyPath(go) != hierarchyFilter) + continue; + + var described = ObjectResolver.Describe(go); + if (described != null) + matches.Add(described); + } + + return new FindGameObjectsResult { Count = matches.Count, GameObjects = matches }; + } + + /// + /// Set the local transform (position, rotation in Euler degrees, scale) of a GameObject. + /// Any omitted channel is left unchanged. Goes through + /// on the Transform so the change is reversible and recorded as a prefab override where relevant. + /// + [CliCommand("set_transform", + "Set a GameObject's local position/rotation(euler)/scale. Omitted channels are left unchanged.", + Tags = new[] { "gameobjects" })] + public static AuthoringResult SetTransform( + [CliArg("target", "Handle of the GameObject to modify.", Required = true)] ObjectRef target, + [CliArg("position", "Local position as [x,y,z].")] float[] position = null, + [CliArg("rotation", "Local rotation as Euler angles [x,y,z] in degrees.")] float[] rotation = null, + [CliArg("scale", "Local scale as [x,y,z].")] float[] scale = null) + { + var go = ResolveGameObject(target, "target"); + using (new AuthoringUndoScope("Set Transform")) + { + var transform = go.transform; + Undo.RegisterCompleteObjectUndo(transform, "Set Transform"); + + if (position != null) + transform.localPosition = ToVector3(position, "position"); + if (rotation != null) + transform.localEulerAngles = ToVector3(rotation, "rotation"); + if (scale != null) + transform.localScale = ToVector3(scale, "scale"); + + MarkDirty(go); + return ObjectResolver.Describe(go); + } + } + + /// + /// Reparent a GameObject (or clear its parent so it becomes a scene root). Uses + /// so the reparent — including the sibling-index change — + /// is a single undoable operation. World position is preserved by default to match the + /// Editor's drag-to-reparent behavior. + /// + [CliCommand("set_parent", + "Reparent a GameObject under a new parent, or detach it to scene root when no parent is given.", + Tags = new[] { "gameobjects" })] + public static AuthoringResult SetParent( + [CliArg("target", "Handle of the GameObject to reparent.", Required = true)] ObjectRef target, + [CliArg("parent", "Handle of the new parent. Omit (or empty) to move the object to the scene root.")] ObjectRef parent = null, + [CliArg("world_position_stays", "Keep the object's world position when reparenting. Default true.")] bool worldPositionStays = true) + { + var go = ResolveGameObject(target, "target"); + Transform parentTransform = null; + if (parent != null && !parent.IsEmpty) + parentTransform = ResolveGameObject(parent, "parent").transform; + + using (new AuthoringUndoScope("Set Parent")) + { + Undo.SetTransformParent(go.transform, parentTransform, worldPositionStays, "Set Parent"); + MarkDirty(go); + return ObjectResolver.Describe(go); + } + } + + /// Set a GameObject's active self-state. + [CliCommand("set_active", "Set a GameObject's active self-state (activeSelf).", Tags = new[] { "gameobjects" })] + public static AuthoringResult SetActive( + [CliArg("target", "Handle of the GameObject.", Required = true)] ObjectRef target, + [CliArg("active", "Desired active state.", Required = true)] bool active) + { + var go = ResolveGameObject(target, "target"); + using (new AuthoringUndoScope("Set Active")) + { + Undo.RegisterCompleteObjectUndo(go, "Set Active"); + go.SetActive(active); + MarkDirty(go); + return ObjectResolver.Describe(go); + } + } + + /// + /// Set a GameObject's tag. The tag must already exist in the project's Tag Manager; an unknown + /// tag surfaces a clear error rather than silently creating one (tag creation is a project + /// settings mutation outside this command's scope). + /// + [CliCommand("set_tag", "Set a GameObject's tag (the tag must already exist in the project).", Tags = new[] { "gameobjects" })] + public static AuthoringResult SetTag( + [CliArg("target", "Handle of the GameObject.", Required = true)] ObjectRef target, + [CliArg("tag", "Tag to assign (must exist in the Tag Manager).", Required = true)] string tag) + { + var go = ResolveGameObject(target, "target"); + if (!InternalEditorTagExists(tag)) + throw new ArgumentException($"Tag '{tag}' does not exist in the project. Add it via the Tag Manager first."); + + using (new AuthoringUndoScope("Set Tag")) + { + Undo.RegisterCompleteObjectUndo(go, "Set Tag"); + go.tag = tag; + MarkDirty(go); + return ObjectResolver.Describe(go); + } + } + + /// + /// Set a GameObject's layer by name or numeric index. A name is resolved via + /// ; an out-of-range index or unknown name is rejected. + /// + [CliCommand("set_layer", "Set a GameObject's layer by name or numeric index (0-31).", Tags = new[] { "gameobjects" })] + public static AuthoringResult SetLayer( + [CliArg("target", "Handle of the GameObject.", Required = true)] ObjectRef target, + [CliArg("layer", "Layer name (e.g. 'UI') or numeric index 0-31.", Required = true)] string layer) + { + var go = ResolveGameObject(target, "target"); + var layerIndex = ResolveLayer(layer); + + using (new AuthoringUndoScope("Set Layer")) + { + Undo.RegisterCompleteObjectUndo(go, "Set Layer"); + go.layer = layerIndex; + MarkDirty(go); + return ObjectResolver.Describe(go); + } + } + + /// Rename a GameObject. + [CliCommand("rename_gameobject", "Rename a GameObject.", Tags = new[] { "gameobjects" })] + public static AuthoringResult RenameGameObject( + [CliArg("target", "Handle of the GameObject.", Required = true)] ObjectRef target, + [CliArg("name", "New name.", Required = true)] string name) + { + if (string.IsNullOrEmpty(name)) + throw new ArgumentException("New name must not be empty."); + + var go = ResolveGameObject(target, "target"); + using (new AuthoringUndoScope("Rename GameObject")) + { + Undo.RegisterCompleteObjectUndo(go, "Rename GameObject"); + go.name = name; + MarkDirty(go); + return ObjectResolver.Describe(go); + } + } + + /// + /// Delete a GameObject from the scene. Uses so the + /// deletion is reversible. The result describes the object's identity captured *before* + /// destruction (the live object is gone afterwards). + /// + [CliCommand("delete_gameobject", "Delete a GameObject from the scene (reversible via Undo).", Tags = new[] { "gameobjects" })] + public static AuthoringResult DeleteGameObject( + [CliArg("target", "Handle of the GameObject to delete.", Required = true)] ObjectRef target) + { + var go = ResolveGameObject(target, "target"); + // Capture identity before destruction; the live object is invalid afterwards. + var described = ObjectResolver.Describe(go); + var scene = go.scene; + + using (new AuthoringUndoScope("Delete GameObject")) + { + Undo.DestroyObjectImmediate(go); + if (scene.IsValid()) + EditorSceneManager.MarkSceneDirty(scene); + } + + return described; + } + + #region Helpers + + /// + /// Resolve an to a GameObject. Accepts either a GameObject handle or a + /// Component handle (in which case its owning GameObject is used), matching how agents tend to + /// hold references. Throws a descriptive error rather than returning null so the command + /// surfaces a clear message to the caller. + /// + internal static GameObject ResolveGameObject(ObjectRef handle, string argName) + { + if (!ObjectResolver.TryResolve(handle, out var obj, out var error)) + throw new ArgumentException($"Could not resolve '{argName}': {error}"); + + var go = obj as GameObject ?? (obj as Component)?.gameObject; + if (go == null) + throw new ArgumentException($"'{argName}' did not resolve to a GameObject (got {obj.GetType().Name})."); + + return go; + } + + /// Mark a GameObject and its scene dirty so changes persist and the Editor refreshes. + internal static void MarkDirty(GameObject go) + { + EditorUtility.SetDirty(go); + if (go.scene.IsValid()) + EditorSceneManager.MarkSceneDirty(go.scene); + } + + /// + /// Create a single GameObject (empty or a primitive), apply an optional name, register it for + /// Undo, and parent it under when given. Shared by the + /// single and the batch so both + /// build objects identically. MUST be called inside an . + /// + private static GameObject CreateOne(string primitive, string name, Transform parentTransform) + { + GameObject go; + if (!string.IsNullOrEmpty(primitive)) + { + if (!TryParsePrimitive(primitive, out var primitiveType)) + throw new ArgumentException( + $"Unknown primitive '{primitive}'. Expected one of: cube, sphere, capsule, cylinder, plane, quad."); + + go = GameObject.CreatePrimitive(primitiveType); + } + else + { + go = new GameObject(); + } + + if (!string.IsNullOrEmpty(name)) + go.name = name; + + Undo.RegisterCreatedObjectUndo(go, "Create GameObject"); + + if (parentTransform != null) + Undo.SetTransformParent(go.transform, parentTransform, "Create GameObject"); + + return go; + } + + /// + /// Resolve an optional parent handle to its Transform, or null when no parent is supplied. + /// Resolved before any creation so an invalid handle fails fast (and a batch creates nothing). + /// + private static Transform ResolveParentTransform(ObjectRef parent) + { + if (parent == null || parent.IsEmpty) + return null; + return ResolveGameObject(parent, "parent").transform; + } + + /// + /// Validate a per-item vectors array (positions/rotations/scales) up front, before any object is + /// created. When supplied it must have exactly one entry per object, and every entry must be a + /// non-null [x,y,z] triple (a JSON array can carry a null element even when its length matches + /// count). A bad array is an agent error surfaced as an naming + /// the offending index, so a batch applies fully or creates nothing rather than throwing an + /// NRE part-way through. + /// + private static void ValidateVectorArray(float[][] vectors, int count, string argName) + { + if (vectors == null) + return; + + if (vectors.Length != count) + throw new ArgumentException( + $"'{argName}' has {vectors.Length} entries but count is {count}; they must match."); + + for (int i = 0; i < vectors.Length; i++) + { + if (vectors[i] == null) + throw new ArgumentException($"'{argName}[{i}]' must be an [x,y,z] array but was null."); + if (vectors[i].Length != 3) + throw new ArgumentException( + $"'{argName}[{i}]' must have exactly 3 components [x,y,z], got {vectors[i].Length}."); + } + } + + private static bool TryParsePrimitive(string value, out PrimitiveType primitiveType) + { + switch (value.Trim().ToLowerInvariant()) + { + case "cube": primitiveType = PrimitiveType.Cube; return true; + case "sphere": primitiveType = PrimitiveType.Sphere; return true; + case "capsule": primitiveType = PrimitiveType.Capsule; return true; + case "cylinder": primitiveType = PrimitiveType.Cylinder; return true; + case "plane": primitiveType = PrimitiveType.Plane; return true; + case "quad": primitiveType = PrimitiveType.Quad; return true; + default: primitiveType = default; return false; + } + } + + private static Vector3 ToVector3(float[] values, string argName) + { + if (values == null) + throw new ArgumentException($"'{argName}' must be an [x,y,z] array but was null."); + if (values.Length != 3) + throw new ArgumentException($"'{argName}' must have exactly 3 components [x,y,z], got {values.Length}."); + return new Vector3(values[0], values[1], values[2]); + } + + private static int ResolveLayer(string layer) + { + if (int.TryParse(layer, out var index)) + { + if (index < 0 || index > 31) + throw new ArgumentException($"Layer index {index} is out of range (0-31)."); + return index; + } + + var named = LayerMask.NameToLayer(layer); + if (named < 0) + throw new ArgumentException($"Layer '{layer}' does not exist in the project."); + return named; + } + + private static bool InternalEditorTagExists(string tag) + { + return UnityEditorInternal.InternalEditorUtility.tags.Contains(tag); + } + + private static IEnumerable EnumerateSceneGameObjects(bool includeInactive) + { + for (int s = 0; s < SceneManager.sceneCount; s++) + { + var scene = SceneManager.GetSceneAt(s); + if (!scene.isLoaded) + continue; + + foreach (var root in scene.GetRootGameObjects()) + { + foreach (var go in EnumerateRecursive(root, includeInactive)) + yield return go; + } + } + } + + private static IEnumerable EnumerateRecursive(GameObject go, bool includeInactive) + { + if (!includeInactive && !go.activeInHierarchy) + yield break; + + yield return go; + + var transform = go.transform; + for (int i = 0; i < transform.childCount; i++) + { + foreach (var child in EnumerateRecursive(transform.GetChild(i).gameObject, includeInactive)) + yield return child; + } + } + + private static string GetHierarchyPath(GameObject go) + { + var sb = new System.Text.StringBuilder(go.name); + var parent = go.transform.parent; + while (parent != null) + { + sb.Insert(0, parent.name + "/"); + parent = parent.parent; + } + + return "/" + sb; + } + + private static string NormalizeHierarchyPath(string path) + { + var trimmed = "/" + path.Trim().Trim('/'); + return trimmed; + } + + #endregion + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/GameObjectCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/GameObjectCommands.cs.meta new file mode 100644 index 0000000..eb0a58b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/GameObjectCommands.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a1aac051d9234c78b4918a8dd366514a diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/SerializedPropertyConverter.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/SerializedPropertyConverter.cs new file mode 100644 index 0000000..5225659 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/SerializedPropertyConverter.cs @@ -0,0 +1,224 @@ +using System; +using Newtonsoft.Json.Linq; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Models; +using UnityEditor; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace Unity.Pipeline.Editor.Commands.GameObjects +{ + /// + /// Reads and writes a single from/to a JSON value. + /// + /// WHY everything goes through SerializedProperty rather than reflection on the C# field: it is + /// the only path that correctly participates in dirtying, prefab override tracking, and Undo + /// (when the change is applied via ). + /// Reflection would bypass all three and leave the Editor's view stale. + /// + /// Supported surface: primitives (bool/int/long/float/double/string), enums (by name or index), + /// //, , and + /// object references (assigned from an handle resolved by + /// ). + /// + internal static class SerializedPropertyConverter + { + /// + /// Read a property into a JSON-friendly value (primitive, string, or small array/object for + /// vector/color types). Unsupported property kinds return a short type descriptor string so a + /// get_component_properties dump never throws on an exotic field. + /// + public static JToken Read(SerializedProperty property) + { + // Array/list fields surface as Generic with isArray=true; return their elements as a JSON + // array so a get/set round-trips. (String also reports isArray, hence the exclusion.) + if (property.isArray && property.propertyType != SerializedPropertyType.String) + { + var elements = new JArray(); + for (int i = 0; i < property.arraySize; i++) + elements.Add(Read(property.GetArrayElementAtIndex(i))); + return elements; + } + + switch (property.propertyType) + { + case SerializedPropertyType.Boolean: + return new JValue(property.boolValue); + case SerializedPropertyType.Integer: + return new JValue(property.longValue); + case SerializedPropertyType.Float: + return new JValue(property.doubleValue); + case SerializedPropertyType.String: + return new JValue(property.stringValue); + case SerializedPropertyType.Enum: + // enumValueIndex indexes enumNames; guard against -1 (mixed/unknown). + return property.enumValueIndex >= 0 && property.enumValueIndex < property.enumNames.Length + ? new JValue(property.enumNames[property.enumValueIndex]) + : new JValue(property.intValue); + case SerializedPropertyType.Vector2: + return ToArray(property.vector2Value.x, property.vector2Value.y); + case SerializedPropertyType.Vector3: + return ToArray(property.vector3Value.x, property.vector3Value.y, property.vector3Value.z); + case SerializedPropertyType.Vector4: + return ToArray(property.vector4Value.x, property.vector4Value.y, property.vector4Value.z, property.vector4Value.w); + case SerializedPropertyType.Color: + var c = property.colorValue; + return ToArray(c.r, c.g, c.b, c.a); + case SerializedPropertyType.ObjectReference: + return property.objectReferenceValue != null + ? JToken.FromObject(ObjectResolver.Describe(property.objectReferenceValue)) + : JValue.CreateNull(); + default: + // Bounds, Quaternion, AnimationCurve, etc. are out of MVP scope: surface a hint. + return new JValue($""); + } + } + + /// + /// Write a JSON value into a property. Throws with a clear + /// message on a type mismatch so set_component_properties reports exactly which field/value + /// failed. Object references are resolved from an -shaped JSON object + /// (or a bare string treated as an asset path / globalId). + /// + public static void Write(SerializedProperty property, JToken value) + { + // Array/list fields (Generic + isArray) are written from a JSON array: resize, then recurse + // per element so arrays of primitives AND object references (e.g. MeshRenderer.m_Materials) + // both work. (String also reports isArray, hence the exclusion.) + if (property.isArray && property.propertyType != SerializedPropertyType.String) + { + if (!(value is JArray array)) + throw new ArgumentException( + $"Property '{property.name}' is an array; provide a JSON array of elements."); + + property.arraySize = array.Count; + for (int i = 0; i < array.Count; i++) + Write(property.GetArrayElementAtIndex(i), array[i]); + return; + } + + switch (property.propertyType) + { + case SerializedPropertyType.Boolean: + property.boolValue = value.ToObject(); + break; + case SerializedPropertyType.Integer: + property.longValue = value.ToObject(); + break; + case SerializedPropertyType.Float: + property.doubleValue = value.ToObject(); + break; + case SerializedPropertyType.String: + property.stringValue = value.Type == JTokenType.Null ? string.Empty : value.ToObject(); + break; + case SerializedPropertyType.Enum: + WriteEnum(property, value); + break; + case SerializedPropertyType.Vector2: + { + var a = ToFloats(value, 2, property.name); + property.vector2Value = new Vector2(a[0], a[1]); + break; + } + case SerializedPropertyType.Vector3: + { + var a = ToFloats(value, 3, property.name); + property.vector3Value = new Vector3(a[0], a[1], a[2]); + break; + } + case SerializedPropertyType.Vector4: + { + var a = ToFloats(value, 4, property.name); + property.vector4Value = new Vector4(a[0], a[1], a[2], a[3]); + break; + } + case SerializedPropertyType.Color: + { + var a = ToFloats(value, 4, property.name); + property.colorValue = new Color(a[0], a[1], a[2], a[3]); + break; + } + case SerializedPropertyType.ObjectReference: + property.objectReferenceValue = ResolveObjectReference(value, property.name); + break; + default: + throw new ArgumentException( + $"Property '{property.name}' has unsupported type '{property.propertyType}' for set."); + } + } + + private static void WriteEnum(SerializedProperty property, JToken value) + { + // Accept either the enum constant name or its index/value. + if (value.Type == JTokenType.String) + { + var name = value.ToObject(); + var index = Array.IndexOf(property.enumNames, name); + if (index < 0) + { + // Fall back to display names (Editor humanized form), then error. + index = Array.IndexOf(property.enumDisplayNames, name); + if (index < 0) + throw new ArgumentException( + $"Enum value '{name}' is not valid for property '{property.name}'. Valid: [{string.Join(", ", property.enumNames)}]."); + } + + property.enumValueIndex = index; + } + else + { + // A numeric value is the enum's underlying integer, NOT an index into enumNames: + // those only coincide when declaration order matches the constant values. Mirror Read, + // which falls back to property.intValue, so round-tripping a numeric enum is stable. + property.intValue = value.ToObject(); + } + } + + private static Object ResolveObjectReference(JToken value, string propertyName) + { + // An explicit null clears the reference; anything else MUST resolve — never silently no-op + // (a handle that doesn't resolve used to be dropped, so the command reported success while + // assigning nothing). + if (value == null || value.Type == JTokenType.Null) + return null; + + // Route every shape (string handle, handle object, or bare-integer instanceId) through + // ObjectRefConverter so path / guid / globalId / instanceId forms all parse identically. + var handle = value.ToObject(); + if (handle == null || handle.IsEmpty) + throw new ArgumentException( + $"Property '{propertyName}': '{value}' is not a recognized object reference handle. " + + "Provide a path, guid, globalId, or instanceId (or null to clear)."); + + if (!ObjectResolver.TryResolve(handle, out var obj, out var error)) + throw new ArgumentException($"Could not resolve object reference for '{propertyName}': {error}"); + + return obj; + } + + private static float[] ToFloats(JToken value, int expected, string propertyName) + { + if (value is JArray array) + { + if (array.Count != expected) + throw new ArgumentException( + $"Property '{propertyName}' expects {expected} components, got {array.Count}."); + var result = new float[expected]; + for (int i = 0; i < expected; i++) + result[i] = array[i].ToObject(); + return result; + } + + throw new ArgumentException( + $"Property '{propertyName}' expects an array of {expected} numbers."); + } + + private static JArray ToArray(params float[] values) + { + var array = new JArray(); + foreach (var v in values) + array.Add(v); + return array; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/SerializedPropertyConverter.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/SerializedPropertyConverter.cs.meta new file mode 100644 index 0000000..b42d407 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/SerializedPropertyConverter.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 85f605c1109e40898fe47ff1e2a8a4d0 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/TypeResolver.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/TypeResolver.cs new file mode 100644 index 0000000..2785d67 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/TypeResolver.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace Unity.Pipeline.Editor.Commands.GameObjects +{ + /// + /// Resolves a -derived from an + /// agent-supplied name. WHY this is non-trivial: agents pass either a short name ("Rigidbody") + /// or a fully-qualified one ("UnityEngine.Camera"), and the type may live in any loaded assembly + /// (UnityEngine modules, user assemblies, packages). We therefore try, in order: an exact + /// fully-qualified , then a scan of all loaded assemblies for a + /// full-name match, then a short-name match. Only subclasses are accepted + /// so the result is always valid for AddComponent/GetComponent. + /// + static class TypeResolver + { + /// + /// Resolve a component type by name, or return null if no unambiguous + /// subclass matches. A short name that matches multiple types in different namespaces is + /// treated as ambiguous and returns null (the caller should ask for a fully-qualified name). + /// + public static Type ResolveComponentType(string typeName) + { + if (string.IsNullOrWhiteSpace(typeName)) + return null; + + typeName = typeName.Trim(); + + // 1. Exact, assembly-qualified or fully-qualified lookup. + var direct = Type.GetType(typeName, throwOnError: false, ignoreCase: false); + if (IsComponent(direct)) + return direct; + + var assemblies = PipelineUtils.GetLoadedAssemblies(); + + // 2. Full-name match across loaded assemblies. + var fullNameMatches = new List(); + // 3. Short-name match (collected in the same pass) as a fallback. + var shortNameMatches = new List(); + + foreach (var assembly in assemblies) + { + Type[] types; + try + { + types = assembly.GetTypes(); + } + catch (System.Reflection.ReflectionTypeLoadException ex) + { + types = ex.Types.Where(t => t != null).ToArray(); + } + + foreach (var type in types) + { + if (!IsComponent(type)) + continue; + + if (string.Equals(type.FullName, typeName, StringComparison.Ordinal)) + fullNameMatches.Add(type); + else if (string.Equals(type.Name, typeName, StringComparison.Ordinal)) + shortNameMatches.Add(type); + } + } + + if (fullNameMatches.Count == 1) + return fullNameMatches[0]; + if (fullNameMatches.Count > 1) + return null; // genuinely ambiguous full names (rare) — caller must disambiguate. + + // Distinct in case the same type is reachable through multiple assembly references. + var distinctShort = shortNameMatches.Distinct().ToList(); + return distinctShort.Count == 1 ? distinctShort[0] : null; + } + + private static bool IsComponent(Type type) + { + return type != null && typeof(Component).IsAssignableFrom(type) && !type.IsAbstract; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/TypeResolver.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/TypeResolver.cs.meta new file mode 100644 index 0000000..5779266 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/GameObjects/TypeResolver.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f033287d429f4957bfcfd6795f731b48 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials.meta new file mode 100644 index 0000000..64b6857 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4841c84bba2a471eb3fb429f79e3b118 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/MaterialCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/MaterialCommands.cs new file mode 100644 index 0000000..bd17666 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/MaterialCommands.cs @@ -0,0 +1,405 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json.Linq; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Models; +using UnityEditor; +using UnityEngine; +using UnityEngine.Rendering; +using Object = UnityEngine.Object; + +namespace Unity.Pipeline.Editor.Commands.Materials +{ + /// + /// Materials authoring commands (CLI-213): read and write a material's shader, shader properties + /// (floats, colors, vectors, textures, ints), keywords, and render queue. + /// + /// These sit on the CLI-190 authoring foundation: + /// - the material is addressed with an resolved by + /// and confined to the authoring root (a GUID/globalId handle can't edit a material outside the sandbox), + /// - texture property values are s likewise confined to the root, + /// - writes are wrapped in an with + /// (material property changes ARE covered by Undo.RecordObject, unlike AssetDatabase ops), then + /// + persist them, + /// - unknown property names and type mismatches are reported in unknown[] rather than failing + /// the whole call (as long as at least one input applied). + /// + /// Material CREATION already exists in create_asset (CLI-221); this command set is the + /// read/write surface on top of an existing material. + /// + static class MaterialCommands + { + [CliCommand("get_material_properties", + "Read a material's shader, render queue, enabled keywords, and all shader properties with their current values (Color as [r,g,b,a], Vector as [x,y,z,w], Texture as an object reference).", + Tags = new[] { "materials" })] + public static MaterialPropertiesResult GetMaterialProperties( + [CliArg("material", "Reference to the .mat asset (or a loaded material) to read (path / guid / globalId / instanceId).", Required = true)] ObjectRef material) + { + var mat = ResolveMaterial(material, out var assetPath); + + var result = new MaterialPropertiesResult + { + AssetPath = assetPath, + Shader = mat.shader != null ? mat.shader.name : null, + // rawRenderQueue is -1 when the material inherits from the shader and a positive + // integer when explicitly overridden — returning the raw value preserves the + // round-trip contract with set_material_properties renderQueue:-1 (inherit). + // Unity 2022 lacks rawRenderQueue; fall back to the effective renderQueue. +#if UNITY_6000_0_OR_NEWER + RenderQueue = mat.rawRenderQueue, +#else + RenderQueue = mat.renderQueue, +#endif + EnabledKeywords = GetEnabledKeywords(mat), + }; + + var shader = mat.shader; + if (shader != null) + { + // Enumerate the shader's declared properties via the Shader instance APIs (single index + // space, matching get_shader_properties), so name/type/range-limits always line up. + int count = shader.GetPropertyCount(); + for (int i = 0; i < count; i++) + { + var name = shader.GetPropertyName(i); + var propType = shader.GetPropertyType(i); + + var entry = new MaterialPropertyValue + { + Name = name, + Type = PublicValueType(propType), + Value = MaterialValueConverter.ReadValue(mat, name, propType), + }; + + if (propType == ShaderPropertyType.Range) + { + var limits = shader.GetPropertyRangeLimits(i); + entry.Range = new MaterialRange + { + Min = limits.x, + Max = limits.y, + }; + } + + result.Properties.Add(entry); + } + } + + return result; + } + + [CliCommand("set_material_properties", + "Set shader properties on a material (Float/Range/Int=number; Color=[r,g,b,a] or \"#RRGGBBAA\" hex; Vector=[x,y,z,w]; Texture=an object reference or null to clear), optionally reassign the shader, set the render queue, and toggle keywords. Unknown names / type mismatches are reported in unknown[].", + Tags = new[] { "materials" })] + public static SetMaterialPropertiesResult SetMaterialProperties( + [CliArg("material", "Reference to the .mat asset (or a loaded material) to edit (path / guid / globalId / instanceId).", Required = true)] ObjectRef material, + [CliArg("shader", "Reassign the material's shader by name (e.g. \"Standard\", \"Universal Render Pipeline/Lit\", or a Shader Graph shader name). Applied before properties so new property names resolve against the new shader.")] string shader = null, + [CliArg("properties", "JSON object of shader property name -> value. Names must include the leading underscore (e.g. _BaseColor). Float/Range/Int=number; Color=[r,g,b,a] or hex string; Vector=[x,y,z,w]; Texture=an object reference {guid/path} or null.")] JObject properties = null, + [CliArg("renderQueue", "Explicit render queue, or -1 to inherit from the shader. Omit to leave unchanged.")] int? renderQueue = null, + [CliArg("enableKeywords", "Shader keywords to enable (e.g. _NORMALMAP, _EMISSION).")] string[] enableKeywords = null, + [CliArg("disableKeywords", "Shader keywords to disable.")] string[] disableKeywords = null, + [CliArg("confirm", "Reserved for parity; editing an existing material is non-destructive and undoable, so it is not required.")] bool confirm = false, + [CliArg("dry_run", "If true, validate the shader, resolve property names and texture refs, and report applied[]/unknown[] without writing anything.")] bool dryRun = false) + { + var mat = ResolveMaterial(material, out var assetPath); + + // Resolve the (optional) replacement shader UP FRONT so dry_run validates it too, and a + // shader_not_found writes nothing (acceptance #9). Shader.Find only finds compiled/included + // shaders — surface that in the hint. + Shader newShader = null; + if (shader != null) + { + newShader = Shader.Find(shader); + if (newShader == null) + throw new ShaderNotFoundException( + $"Shader '{shader}' not found. Shader.Find only resolves shaders that are compiled/included in the build (or referenced by a material/scene). Use list_shaders to discover valid names."); + } + + var result = new SetMaterialPropertiesResult(); + + // ---- dry_run: validate against the would-be shader, never mutate ---------------------- + if (dryRun) + { + var effectiveShader = newShader ?? mat.shader; + ValidateProperties(effectiveShader, properties, result); + if (renderQueue.HasValue) + result.Applied.Add("renderQueue"); + AddKeywordTokens(result.Applied, enableKeywords, disableKeywords); + + GuardAtLeastOneApplied(result, shaderReassigned: newShader != null); + + CopyIdentity(mat, assetPath, result); + result.Shader = effectiveShader != null ? effectiveShader.name : null; + return result; + } + + // ---- apply -------------------------------------------------------------------------- + using (new AuthoringUndoScope("Set Material Properties")) + { + // Material property/shader/keyword/renderQueue changes are all covered by Undo.RecordObject. + Undo.RecordObject(mat, "Set Material Properties"); + + if (newShader != null) + mat.shader = newShader; + + if (properties != null) + { + foreach (var pair in properties) + { + if (pair.Key == "token") // injected by the server; never a material property. + continue; + + var name = pair.Key; + if (!mat.HasProperty(name)) + { + result.Unknown.Add($"{name}: unknown property (not declared by shader '{(mat.shader != null ? mat.shader.name : "")}')"); + continue; + } + + var propType = GetPropertyType(mat.shader, name); + if (propType == null) + { + // HasProperty was true but the type couldn't be read off the shader (e.g. a + // built-in property like unity_Lightmaps not declared in the shader's list). + result.Unknown.Add($"{name}: property is not a settable shader property on '{(mat.shader != null ? mat.shader.name : "")}'"); + continue; + } + + try + { + MaterialValueConverter.ApplyValue(mat, name, propType.Value, pair.Value); + result.Applied.Add(name); + } + catch (MaterialPropertyTypeMismatch mismatch) + { + result.Unknown.Add(mismatch.Message); + } + } + } + + if (renderQueue.HasValue) + { + mat.renderQueue = renderQueue.Value; + result.Applied.Add("renderQueue"); + } + + ApplyKeywords(mat, enableKeywords, disableKeywords, result.Applied); + + GuardAtLeastOneApplied(result, shaderReassigned: newShader != null); + + EditorUtility.SetDirty(mat); + if (!string.IsNullOrEmpty(assetPath)) + AssetDatabase.SaveAssetIfDirty(mat); + } + + CopyIdentity(mat, assetPath, result); + result.Shader = mat.shader != null ? mat.shader.name : null; + return result; + } + + /// + /// Resolve an to a , confining any on-disk asset to + /// the authoring root. Returns the project-relative asset path (null for a non-asset/in-memory + /// material). Throws a clear on miss / wrong type / out-of-root. + /// + internal static Material ResolveMaterial(ObjectRef material, out string assetPath) + { + if (material == null || material.IsEmpty) + throw new ArgumentException("'material' is required."); + + if (!ObjectResolver.TryResolve(material, out var obj, out var error)) + throw new ArgumentException($"Could not resolve material: {error}"); + + if (!(obj is Material mat)) + throw new ArgumentException($"Reference '{material}' resolved to a {obj.GetType().Name}, not a Material."); + + assetPath = AssetDatabase.GetAssetPath(mat); + if (!string.IsNullOrEmpty(assetPath)) + { + var confined = ProjectPaths.Resolve(assetPath, out var confineError); + if (confined == null) + throw new ArgumentException( + $"Material '{assetPath}' is outside the authoring root '{ProjectPaths.AuthoringRoot}': {confineError}"); + assetPath = confined; + } + + return mat; + } + + /// + /// Read the material's enabled keyword set. Uses + /// (LocalKeyword[]) which is the supported API on the package's min Unity version (Unity 6 / + /// 6000.0); the legacy shaderKeywords string[] is deprecated. + /// + private static List GetEnabledKeywords(Material mat) + { + var keywords = new List(); + foreach (var keyword in mat.enabledKeywords) + keywords.Add(keyword.name); + keywords.Sort(StringComparer.Ordinal); + return keywords; + } + + private static void ApplyKeywords(Material mat, string[] enable, string[] disable, List applied) + { + // Use the LocalKeyword API (Unity 2022.1+) so that Enable/Disable and the + // enabledKeywords reader are talking to the same keyword table. The legacy + // string-based EnableKeyword(string) affects global keywords, whereas + // mat.enabledKeywords returns LocalKeyword[], so they would disagree on round-trip. + if (enable != null) + { + foreach (var keyword in enable) + { + if (string.IsNullOrWhiteSpace(keyword) || mat.shader == null) + continue; + mat.EnableKeyword(new LocalKeyword(mat.shader, keyword)); + applied.Add($"+keyword:{keyword}"); + } + } + + if (disable != null) + { + foreach (var keyword in disable) + { + if (string.IsNullOrWhiteSpace(keyword) || mat.shader == null) + continue; + mat.DisableKeyword(new LocalKeyword(mat.shader, keyword)); + applied.Add($"-keyword:{keyword}"); + } + } + } + + private static void AddKeywordTokens(List applied, string[] enable, string[] disable) + { + if (enable != null) + foreach (var keyword in enable.Where(k => !string.IsNullOrWhiteSpace(k))) + applied.Add($"+keyword:{keyword}"); + if (disable != null) + foreach (var keyword in disable.Where(k => !string.IsNullOrWhiteSpace(k))) + applied.Add($"-keyword:{keyword}"); + } + + /// + /// dry_run validation: classify each supplied property as applicable (name resolves AND value + /// shape matches the declared type) or unknown, WITHOUT mutating the material. + /// + private static void ValidateProperties(Shader shader, JObject properties, SetMaterialPropertiesResult result) + { + if (properties == null) + return; + + foreach (var pair in properties) + { + if (pair.Key == "token") + continue; + + var name = pair.Key; + var propType = shader != null ? GetPropertyType(shader, name) : null; + if (propType == null) + { + result.Unknown.Add($"{name}: unknown property (not declared by shader '{(shader != null ? shader.name : "")}')"); + continue; + } + + // Validate the value shape against the type by attempting a conversion on a throwaway + // material instance — never the caller's material (dry_run must leave no trace). + Material probe = null; + try + { + probe = new Material(shader); + MaterialValueConverter.ApplyValue(probe, name, propType.Value, pair.Value); + result.Applied.Add(name); + } + catch (MaterialPropertyTypeMismatch mismatch) + { + result.Unknown.Add(mismatch.Message); + } + finally + { + if (probe != null) + Object.DestroyImmediate(probe); + } + } + } + + /// + /// Look up a property's by name on a shader. + /// Returns null when the shader has no property with that exact name (case-sensitive; names include + /// the leading underscore). + /// + internal static ShaderPropertyType? GetPropertyType(Shader shader, string name) + { + if (shader == null) + return null; + int count = shader.GetPropertyCount(); + for (int i = 0; i < count; i++) + { + if (shader.GetPropertyName(i) == name) + return shader.GetPropertyType(i); + } + return null; + } + + private static void GuardAtLeastOneApplied(SetMaterialPropertiesResult result, bool shaderReassigned) + { + // A shader reassignment is itself a successful change, so it satisfies the "at least one + // thing applied" guard even when every supplied property is unknown for the new shader. + if (!shaderReassigned && result.Applied.Count == 0 && result.Unknown.Count > 0) + throw new ArgumentException( + $"None of the supplied inputs could be applied (unknown property name or type mismatch): {string.Join("; ", result.Unknown)}."); + } + + private static void CopyIdentity(Material mat, string assetPath, SetMaterialPropertiesResult result) + { + var identity = ObjectResolver.Describe(mat); + if (identity != null) + { + result.GlobalId = identity.GlobalId; + result.Guid = identity.Guid; + result.FileId = identity.FileId; + result.InstanceId = identity.InstanceId; + result.HierarchyPath = identity.HierarchyPath; + result.Type = identity.Type; + } + else + { + result.Type = nameof(Material); + } + + // Prefer the confined asset path computed by ResolveMaterial. + if (!string.IsNullOrEmpty(assetPath)) + result.AssetPath = assetPath; + } + + /// Map a to the value-shape label used by get_material_properties. + private static string PublicValueType(ShaderPropertyType type) + { + switch (type) + { + case ShaderPropertyType.Color: return "Color"; + case ShaderPropertyType.Vector: return "Vector"; + case ShaderPropertyType.Float: return "Float"; + case ShaderPropertyType.Range: return "Range"; + case ShaderPropertyType.Texture: return "Texture"; + case ShaderPropertyType.Int: return "Int"; + default: return type.ToString(); + } + } + } + + /// + /// Thrown when a requested shader name does not resolve via . Carries the + /// stable shader_not_found code (also prefixed onto the message, since the server propagates + /// only the exception message over the wire) so a client can distinguish it from other failures. + /// + sealed class ShaderNotFoundException : Exception + { + public const string CodeValue = "shader_not_found"; + + public string Code => CodeValue; + + public ShaderNotFoundException(string message) : base($"[{CodeValue}] {message}") { } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/MaterialCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/MaterialCommands.cs.meta new file mode 100644 index 0000000..b68b4f0 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/MaterialCommands.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a14c4a97ac9e4d61b904de30d1016d92 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/MaterialResults.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/MaterialResults.cs new file mode 100644 index 0000000..4978078 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/MaterialResults.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using Unity.Pipeline.Models; + +namespace Unity.Pipeline.Editor.Commands.Materials +{ + /// + /// Result of get_material_properties (CLI-213): the material's shader, render queue, enabled + /// keywords, and the full list of shader properties with their current values. + /// + [Serializable] + class MaterialPropertiesResult + { + [JsonProperty("assetPath")] + public string AssetPath { get; set; } + + /// Shader name, e.g. "Universal Render Pipeline/Lit". + [JsonProperty("shader")] + public string Shader { get; set; } + + /// Render queue; -1 means "inherit from shader". + [JsonProperty("renderQueue")] + public int RenderQueue { get; set; } + + [JsonProperty("enabledKeywords")] + public List EnabledKeywords { get; set; } = new List(); + + [JsonProperty("properties")] + public List Properties { get; set; } = new List(); + } + + /// A single shader property of a material with its current value. + [Serializable] + class MaterialPropertyValue + { + [JsonProperty("name")] + public string Name { get; set; } + + /// "Float" | "Range" | "Color" | "Vector" | "Texture" | "Int". + [JsonProperty("type")] + public string Type { get; set; } + + /// + /// number | [r,g,b,a] | [x,y,z,w] | { texture: ObjectRef } | null, per the property type. + /// + [JsonProperty("value")] + public object Value { get; set; } + + /// Min/max for a Range property; null otherwise. + [JsonProperty("range", NullValueHandling = NullValueHandling.Ignore)] + public MaterialRange Range { get; set; } + } + + /// Inclusive min/max bounds of a Range shader property. + [Serializable] + class MaterialRange + { + [JsonProperty("min")] + public float Min { get; set; } + + [JsonProperty("max")] + public float Max { get; set; } + } + + /// + /// Result of set_material_properties (CLI-213): the canonical + /// identity of the edited material, extended with which properties applied vs. were unknown (with a + /// reason), and the material's (possibly reassigned) shader name. + /// + [Serializable] + class SetMaterialPropertiesResult : AuthoringResult + { + /// Shader name after any reassignment. + [JsonProperty("shader")] + public string Shader { get; set; } + + /// Property names (and keyword/renderQueue tokens) that were applied. + [JsonProperty("applied")] + public List Applied { get; set; } = new List(); + + /// + /// Inputs that could not be applied, each as "name: reason" (unknown property name, or a type + /// mismatch like "_Metallic: expected Float, got array"). + /// + [JsonProperty("unknown")] + public List Unknown { get; set; } = new List(); + } + + /// A single discovered shader entry from list_shaders. + [Serializable] + class ShaderInfo + { + [JsonProperty("name")] + public string Name { get; set; } + + /// Project asset path for a project shader; null for a built-in/engine shader. + [JsonProperty("assetPath")] + public string AssetPath { get; set; } + + [JsonProperty("isBuiltin")] + public bool IsBuiltin { get; set; } + + /// Reflects Shader.isSupported for the active render pipeline. + [JsonProperty("isSupported")] + public bool IsSupported { get; set; } + } + + /// Result of get_shader_properties (CLI-213): a shader's declared property list. + [Serializable] + class ShaderPropertiesResult + { + [JsonProperty("shader")] + public string Shader { get; set; } + + [JsonProperty("properties")] + public List Properties { get; set; } = new List(); + } + + /// A single declared shader property, introspected via ShaderUtil. + [Serializable] + class ShaderPropertyInfo + { + [JsonProperty("name")] + public string Name { get; set; } + + /// ShaderUtil property description (the UI label). + [JsonProperty("description")] + public string Description { get; set; } + + /// "Color" | "Vector" | "Float" | "Range" | "TexEnv" | "Int". + [JsonProperty("type")] + public string Type { get; set; } + + /// Min/max for a Range property; null otherwise. + [JsonProperty("range", NullValueHandling = NullValueHandling.Ignore)] + public MaterialRange Range { get; set; } + + /// "Tex2D" | "Cube" | "Tex3D" | "Tex2DArray" for a TexEnv property; null otherwise. + [JsonProperty("textureDimension", NullValueHandling = NullValueHandling.Ignore)] + public string TextureDimension { get; set; } + + /// Property flags, e.g. "HideInInspector", "Normal", "HDR", "NoScaleOffset". + [JsonProperty("flags")] + public List Flags { get; set; } = new List(); + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/MaterialResults.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/MaterialResults.cs.meta new file mode 100644 index 0000000..db85ad6 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/MaterialResults.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 52b9d1506e9b4a95982ff554d70179b3 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/MaterialValueConverter.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/MaterialValueConverter.cs new file mode 100644 index 0000000..ae4d5f2 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/MaterialValueConverter.cs @@ -0,0 +1,310 @@ +using System; +using System.Globalization; +using Newtonsoft.Json.Linq; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Models; +using UnityEditor; +using UnityEngine; +using UnityEngine.Rendering; +using Object = UnityEngine.Object; + +namespace Unity.Pipeline.Editor.Commands.Materials +{ + /// + /// Bridges agent-supplied JSON values and a 's shader properties for the + /// get_material_properties / set_material_properties commands (CLI-213). + /// + /// Value encoding by shader property type: + /// - Float / Range / Int : a JSON number + /// - Color : [r, g, b, a] (floats 0–1) or a "#RRGGBB"/"#RRGGBBAA" hex string + /// - Vector : [x, y, z, w] + /// - Texture (TexEnv) : an object (resolved + confined to the authoring + /// root), or null to clear + /// + /// Reads return the same shapes (Color as [r,g,b,a], Vector as [x,y,z,w], Texture as + /// { texture: ObjectRef } or null) so a read round-trips back through a write. + /// + internal static class MaterialValueConverter + { + /// + /// Read a single shader property's current value off the material into a plain object suitable + /// for JSON serialization. The shape matches the . + /// + public static object ReadValue(Material material, string propertyName, ShaderPropertyType type) + { + switch (type) + { + case ShaderPropertyType.Color: + { + var c = material.GetColor(propertyName); + return new[] { c.r, c.g, c.b, c.a }; + } + case ShaderPropertyType.Vector: + { + var v = material.GetVector(propertyName); + return new[] { v.x, v.y, v.z, v.w }; + } + case ShaderPropertyType.Float: + case ShaderPropertyType.Range: + return material.GetFloat(propertyName); + case ShaderPropertyType.Int: + return material.GetInteger(propertyName); + case ShaderPropertyType.Texture: + { + var tex = material.GetTexture(propertyName); + // A re-usable handle for the assigned texture, or null when no texture is bound. + var handle = ObjectResolver.Describe(tex); + return handle == null ? null : new { texture = handle }; + } + default: + return null; + } + } + + /// + /// Apply a JSON value to a single shader property on the material, converting by the shader's + /// declared property type. Throws when the supplied + /// JSON shape does not match the property's type (so the caller can record it in + /// unknown[] with a reason). Texture refs are resolved via + /// and confined to the authoring root; an out-of-root or unresolved ref throws + /// (a hard failure — never silently dropped). + /// + public static void ApplyValue(Material material, string propertyName, ShaderPropertyType type, JToken value) + { + switch (type) + { + case ShaderPropertyType.Float: + material.SetFloat(propertyName, ToFloat(propertyName, "Float", value)); + break; + + case ShaderPropertyType.Range: + material.SetFloat(propertyName, ToFloat(propertyName, "Range", value)); + break; + + case ShaderPropertyType.Int: + // Unity 6: Material.SetInteger is the typed setter for an Int shader property. + material.SetInteger(propertyName, ToInt(propertyName, value)); + break; + + case ShaderPropertyType.Color: + material.SetColor(propertyName, ToColor(propertyName, value)); + break; + + case ShaderPropertyType.Vector: + material.SetVector(propertyName, ToVector4(propertyName, value)); + break; + + case ShaderPropertyType.Texture: + material.SetTexture(propertyName, ToTexture(propertyName, value)); + break; + + default: + throw new MaterialPropertyTypeMismatch( + $"{propertyName}: unsupported shader property type '{type}'."); + } + } + + private static float ToFloat(string property, string typeLabel, JToken value) + { + if (value == null || value.Type == JTokenType.Null) + throw new MaterialPropertyTypeMismatch($"{property}: expected {typeLabel}, got null."); + if (value.Type != JTokenType.Integer && value.Type != JTokenType.Float) + throw new MaterialPropertyTypeMismatch( + $"{property}: expected {typeLabel} (a number), got {Describe(value)}."); + return value.ToObject(); + } + + private static int ToInt(string property, JToken value) + { + if (value == null || value.Type == JTokenType.Null) + throw new MaterialPropertyTypeMismatch($"{property}: expected Int, got null."); + if (value.Type != JTokenType.Integer && value.Type != JTokenType.Float) + throw new MaterialPropertyTypeMismatch( + $"{property}: expected Int (a number), got {Describe(value)}."); + // Reject fractional JSON numbers (e.g. 1.5) rather than silently rounding/truncating. + // An Int shader property must receive a whole number. + var asDouble = value.ToObject(); + if (asDouble != Math.Truncate(asDouble)) + throw new MaterialPropertyTypeMismatch( + $"{property}: expected Int (a whole number), got the non-integer value {value}."); + return value.ToObject(); + } + + /// + /// Parse a Color from either [r,g,b,a] (3 or 4 floats) or a hex string + /// ("#RRGGBB" / "#RRGGBBAA", leading '#' optional). Default alpha is 1.0. + /// + private static Color ToColor(string property, JToken value) + { + if (value is JArray arr) + { + if (arr.Count != 3 && arr.Count != 4) + throw new MaterialPropertyTypeMismatch( + $"{property}: expected Color as [r,g,b,a] (or [r,g,b]), got an array of length {arr.Count}."); + // Route each component through ToFloat so non-numeric/null elements surface as a clean + // MaterialPropertyTypeMismatch rather than throwing and failing the whole command. + float r = ToFloat(property, "Color", arr[0]); + float g = ToFloat(property, "Color", arr[1]); + float b = ToFloat(property, "Color", arr[2]); + float a = arr.Count == 4 ? ToFloat(property, "Color", arr[3]) : 1f; + return new Color(r, g, b, a); + } + + if (value != null && value.Type == JTokenType.String) + { + if (TryParseHexColor(value.ToObject(), out var color)) + return color; + throw new MaterialPropertyTypeMismatch( + $"{property}: expected Color as [r,g,b,a] or a '#RRGGBB'/'#RRGGBBAA' hex string, got '{value}'."); + } + + throw new MaterialPropertyTypeMismatch( + $"{property}: expected Color as [r,g,b,a] or a hex string, got {Describe(value)}."); + } + + private static Vector4 ToVector4(string property, JToken value) + { + if (!(value is JArray arr)) + throw new MaterialPropertyTypeMismatch( + $"{property}: expected Vector as [x,y,z,w], got {Describe(value)}."); + if (arr.Count == 0 || arr.Count > 4) + throw new MaterialPropertyTypeMismatch( + $"{property}: expected Vector as [x,y,z,w] (1–4 numbers), got an array of length {arr.Count}."); + + // Missing trailing components default to 0 (matches Unity's Vector4 component default), + // so [x,y,z] and [x,y] are accepted as shorthand for a 4-component vector. + // Route each present component through ToFloat so non-numeric/null elements surface as a + // clean MaterialPropertyTypeMismatch rather than throwing and failing the whole command. + float x = arr.Count > 0 ? ToFloat(property, "Vector", arr[0]) : 0f; + float y = arr.Count > 1 ? ToFloat(property, "Vector", arr[1]) : 0f; + float z = arr.Count > 2 ? ToFloat(property, "Vector", arr[2]) : 0f; + float w = arr.Count > 3 ? ToFloat(property, "Vector", arr[3]) : 0f; + return new Vector4(x, y, z, w); + } + + /// + /// Resolve a texture property value: an explicit null clears it, otherwise the value must + /// be an that resolves to a confined to the + /// authoring root. A non-texture object, an out-of-root asset, or an unresolved handle is a hard + /// failure (never silently dropped). + /// + private static Texture ToTexture(string property, JToken value) + { + if (value == null || value.Type == JTokenType.Null) + return null; + + // ReadValue returns textures as { "texture": } so a get->set round-trip works. + // Accept both that wrapper form and a bare ObjectRef supplied directly by the caller. + JToken refToken = value; + if (value is JObject wrapper && wrapper.ContainsKey("texture")) + refToken = wrapper["texture"]; + + ObjectRef handle; + try + { + handle = refToken.ToObject(); + } + catch (Exception) + { + throw new MaterialPropertyTypeMismatch( + $"{property}: expected Texture as an object reference {{guid/path/...}} or null, got {Describe(value)}."); + } + + if (handle == null || handle.IsEmpty) + throw new MaterialPropertyTypeMismatch( + $"{property}: expected Texture as an object reference {{guid/path/...}} or null, got {Describe(value)}."); + + if (!ObjectResolver.TryResolve(handle, out var obj, out var error)) + throw new ArgumentException($"{property}: could not resolve texture reference: {error}"); + + if (!(obj is Texture texture)) + throw new MaterialPropertyTypeMismatch( + $"{property}: expected Texture, got a {obj.GetType().Name}."); + + // Confine to the authoring root: a GUID/globalId/path handle must bind a texture that lives + // on disk under the sandbox. An in-memory/scene Texture has an empty asset path; allowing it + // would bypass the root confinement, so reject any ref that doesn't resolve to a persisted + // asset. Mirrors AssetCommands.ResolveAssetPath's confinement. + var assetPath = AssetDatabase.GetAssetPath(texture); + if (string.IsNullOrEmpty(assetPath)) + throw new ArgumentException( + $"{property}: texture reference does not resolve to an on-disk asset under the authoring root '{ProjectPaths.AuthoringRoot}'; in-memory or scene textures are not allowed."); + + var confined = ProjectPaths.Resolve(assetPath, out var confineError); + if (confined == null) + throw new ArgumentException( + $"{property}: texture '{assetPath}' is outside the authoring root '{ProjectPaths.AuthoringRoot}': {confineError}"); + + return texture; + } + + /// + /// Parse a hex color string ("#RRGGBB", "#RRGGBBAA", or without the leading '#'). Returns false + /// for any malformed input. Channels are 0–255 mapped to 0–1; default alpha is 1.0. + /// + public static bool TryParseHexColor(string hex, out Color color) + { + color = Color.white; + if (string.IsNullOrWhiteSpace(hex)) + return false; + + var s = hex.Trim(); + if (s.StartsWith("#", StringComparison.Ordinal)) + s = s.Substring(1); + + if (s.Length != 6 && s.Length != 8) + return false; + + if (!byte.TryParse(s.Substring(0, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var r) || + !byte.TryParse(s.Substring(2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var g) || + !byte.TryParse(s.Substring(4, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var b)) + return false; + + byte a = 255; + if (s.Length == 8 && + !byte.TryParse(s.Substring(6, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out a)) + return false; + + color = new Color(r / 255f, g / 255f, b / 255f, a / 255f); + return true; + } + + /// Map a to the public type label used in results. + public static string TypeLabel(ShaderPropertyType type) + { + switch (type) + { + case ShaderPropertyType.Color: return "Color"; + case ShaderPropertyType.Vector: return "Vector"; + case ShaderPropertyType.Float: return "Float"; + case ShaderPropertyType.Range: return "Range"; + case ShaderPropertyType.Texture: return "TexEnv"; + case ShaderPropertyType.Int: return "Int"; + default: return type.ToString(); + } + } + + private static string Describe(JToken value) + { + if (value == null) + return "null"; + switch (value.Type) + { + case JTokenType.Array: return "array"; + case JTokenType.Object: return "object"; + case JTokenType.Null: return "null"; + default: return value.Type.ToString().ToLowerInvariant(); + } + } + } + + /// + /// Thrown when a supplied value's JSON shape does not match the shader property's declared type. + /// The command catches this and records the property in unknown[] with the message as the + /// reason, rather than failing the whole call. + /// + internal sealed class MaterialPropertyTypeMismatch : Exception + { + public MaterialPropertyTypeMismatch(string message) : base(message) { } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/MaterialValueConverter.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/MaterialValueConverter.cs.meta new file mode 100644 index 0000000..4445fb6 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/MaterialValueConverter.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: fc8956be3c264ccb8096787d7146f330 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/ShaderCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/ShaderCommands.cs new file mode 100644 index 0000000..bc67cc1 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/ShaderCommands.cs @@ -0,0 +1,188 @@ +using System; +using System.Collections.Generic; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Models; +using UnityEditor; +using UnityEngine; +using UnityEngine.Rendering; + +namespace Unity.Pipeline.Editor.Commands.Materials +{ + /// + /// Shader discovery / introspection commands (CLI-213): list_shaders so an agent can pick a + /// valid shader name, and get_shader_properties so it knows a shader's settable property + /// names / types / ranges / texture dimensions / flags before authoring a material. + /// + /// Property introspection uses instance APIs exclusively: + /// GetPropertyCount, GetPropertyName, GetPropertyType, + /// GetPropertyDescription, GetPropertyRangeLimits, + /// GetPropertyTextureDimension, and GetPropertyFlags. The reported type set is + /// : Color, Vector, Float, Range, Texture, Int. + /// + static class ShaderCommands + { + [CliCommand("list_shaders", + "Discover available shaders so an agent can pick a valid name for set_material_properties / create_asset. Returns [{ name, assetPath|null, isBuiltin, isSupported }].", + Tags = new[] { "materials/shaders" })] + public static List ListShaders( + [CliArg("filter", "Case-insensitive substring matched against the shader name (e.g. \"URP\", \"Lit\").")] string filter = null, + [CliArg("includeBuiltin", "Include built-in/engine shaders (those with no project asset path). Default true.")] bool includeBuiltin = true, + [CliArg("limit", "Maximum number of shaders to return (default 200).")] int limit = 200) + { + if (limit <= 0) + limit = 200; + + var results = new List(); + var seen = new HashSet(StringComparer.Ordinal); + + // AssetDatabase.FindAssets("t:Shader") enumerates project + package shaders (each with an + // asset path); ShaderUtil.GetAllShaderInfo() additionally surfaces built-in engine shaders + // that have no asset path (e.g. "Standard", "Sprites/Default"). Merge both, dedup by name. + foreach (var guid in AssetDatabase.FindAssets("t:Shader")) + { + var path = AssetDatabase.GUIDToAssetPath(guid); + if (string.IsNullOrEmpty(path)) + continue; + var shader = AssetDatabase.LoadAssetAtPath(path); + if (shader == null) + continue; + + if (!seen.Add(shader.name)) + continue; + + if (!PassesFilter(shader.name, filter)) + continue; + + results.Add(new ShaderInfo + { + Name = shader.name, + AssetPath = path, + IsBuiltin = false, + IsSupported = shader.isSupported, + }); + + if (results.Count >= limit) + return results; + } + + if (includeBuiltin) + { + // GetAllShaderInfo() enumerates every shader the editor knows about, including built-in + // engine shaders that have no project/package asset path. Any name NOT already added by + // the FindAssets("t:Shader") pass above is a built-in (assetPath null). `info.supported` + // already reflects Shader::IsSupported(), so we don't re-run Shader.Find per entry. + foreach (var info in ShaderUtil.GetAllShaderInfo()) + { + if (!seen.Add(info.name)) + continue; + + if (!PassesFilter(info.name, filter)) + continue; + + results.Add(new ShaderInfo + { + Name = info.name, + AssetPath = null, + IsBuiltin = true, + IsSupported = info.supported, + }); + + if (results.Count >= limit) + break; + } + } + + return results; + } + + [CliCommand("get_shader_properties", + "Introspect a shader's declared property list (name, description, type Color|Vector|Float|Range|TexEnv|Int, range, textureDimension, flags). Provide 'shader' (by name) OR 'material' (read the shader off that material).", + Tags = new[] { "materials/shaders" })] + public static ShaderPropertiesResult GetShaderProperties( + [CliArg("shader", "Shader name (e.g. \"Universal Render Pipeline/Lit\"). Provide this OR 'material'.")] string shader = null, + [CliArg("material", "Reference to a material to read the shader from instead of naming it. Provide this OR 'shader'.")] ObjectRef material = null) + { + Shader resolved; + + if (!string.IsNullOrWhiteSpace(shader)) + { + resolved = Shader.Find(shader); + if (resolved == null) + throw new ShaderNotFoundException( + $"Shader '{shader}' not found. Shader.Find only resolves shaders that are compiled/included in the build (or referenced by a material/scene). Use list_shaders to discover valid names."); + } + else if (material != null && !material.IsEmpty) + { + var mat = MaterialCommands.ResolveMaterial(material, out _); + resolved = mat.shader; + if (resolved == null) + throw new ArgumentException($"Material '{material}' has no shader assigned."); + } + else + { + throw new ArgumentException("Provide either 'shader' (a shader name) or 'material' (a material reference)."); + } + + var result = new ShaderPropertiesResult { Shader = resolved.name }; + + int count = resolved.GetPropertyCount(); + for (int i = 0; i < count; i++) + { + var propType = resolved.GetPropertyType(i); + var entry = new ShaderPropertyInfo + { + Name = resolved.GetPropertyName(i), + Description = resolved.GetPropertyDescription(i), + Type = MaterialValueConverter.TypeLabel(propType), + Flags = DescribeFlags(resolved.GetPropertyFlags(i)), + }; + + if (propType == ShaderPropertyType.Range) + { + var limits = resolved.GetPropertyRangeLimits(i); + entry.Range = new MaterialRange + { + Min = limits.x, + Max = limits.y, + }; + } + + if (propType == ShaderPropertyType.Texture) + entry.TextureDimension = resolved.GetPropertyTextureDimension(i).ToString(); + + result.Properties.Add(entry); + } + + return result; + } + + private static bool PassesFilter(string name, string filter) + { + if (string.IsNullOrWhiteSpace(filter)) + return true; + return name.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0; + } + + /// + /// Decompose a bitmask into its individual flag names (the + /// enum is a [Flags] type). None is reported as an empty list rather than ["None"]. + /// + private static List DescribeFlags(ShaderPropertyFlags flags) + { + var list = new List(); + if (flags == ShaderPropertyFlags.None) + return list; + + foreach (ShaderPropertyFlags flag in Enum.GetValues(typeof(ShaderPropertyFlags))) + { + if (flag == ShaderPropertyFlags.None) + continue; + if ((flags & flag) == flag) + list.Add(flag.ToString()); + } + + return list; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/ShaderCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/ShaderCommands.cs.meta new file mode 100644 index 0000000..0c5e23b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Materials/ShaderCommands.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 1007e4472d7b4216a6a866f8aaba76c7 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/MenuItemCommand.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/MenuItemCommand.cs new file mode 100644 index 0000000..472a9e8 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/MenuItemCommand.cs @@ -0,0 +1,249 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Newtonsoft.Json; +using Unity.Pipeline.Commands; +using UnityEditor; +#if UNITY_6000_5_OR_NEWER +using Unity.Scripting.LifecycleManagement; +#endif + +namespace Unity.Pipeline.Editor.Commands +{ + /// + /// Executes an Editor menu item by its path (e.g. "Assets/Reimport All"), or — when called with + /// no path — lists the available menu items. Backs the unity menu CLI command (CLI-110): + /// unity menu lists options, unity menu "<path>" executes one. The CLI only + /// forwards the request; all logic lives here, per the two-commands design. + /// + /// Named MenuItemCommand (not MenuCommand) to avoid colliding with the built-in + /// type, which would make unqualified references ambiguous + /// in any file that also imports UnityEditor. + /// + /// Execution wraps , which returns false + /// when the item could not be invoked — either because the path does not exist or because the + /// item is currently disabled (its validation function returned false). The API does not + /// distinguish those cases, so a failure is reported as "not found or disabled"; the CLI maps a + /// failed result to its "menu item does not exist" exit code. + /// + /// Listing reflects the actual Editor menu via the internal + /// UnityEditor.Menu.GetMenuItems API (accessed by reflection, mirroring + /// ). Unlike scanning [MenuItem] attributes, this also + /// covers menus Unity defines natively (much of GameObject/…, Assets/Create/…, + /// File/…, etc.), which carry no attribute and would otherwise be missed. + /// + /// Note: some menu items are heavy, show a modal confirmation, or trigger a domain reload/quit + /// (which tears the server down before it can reply). That is the nature of the invoked item; + /// such cases are a known limitation of driving arbitrary menus over a request/response call. + /// +#if UNITY_6000_5_OR_NEWER + [NoAutoStaticsCleanup] +#endif + static class MenuItemCommand + { + [CliCommand("menu", "Execute an Editor menu item by path, or list available items when no path is given", MainThreadRequired = true, Tags = new[] { "editor" })] + public static MenuResponse ExecuteMenu( + [CliArg("path", "Menu item path to execute, e.g. \"Assets/Reimport All\". Omit to list available menu items.")] string path = "") + { + // No path → discovery mode: return the available menu items instead of executing. + if (string.IsNullOrWhiteSpace(path)) + { + List items; + try + { + items = DiscoverMenuItems(); + } + catch (Exception ex) + { + return MenuResponse.Fail(null, $"Failed to list menu items: {ex.Message}"); + } + + return new MenuResponse + { + Success = true, + Items = items, + Message = $"{items.Count} menu item(s) available." + }; + } + + bool executed; + try + { + executed = EditorApplication.ExecuteMenuItem(path); + } + catch (Exception ex) + { + return MenuResponse.Fail(path, $"Failed to execute menu item '{path}': {ex.Message}"); + } + + if (!executed) + return MenuResponse.Fail(path, $"Menu item '{path}' was not found or is currently disabled."); + + return new MenuResponse + { + Success = true, + Path = path, + Message = $"Executed menu item '{path}'" + }; + } + + const BindingFlags k_All = BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; + + // Reflection handles for the internal UnityEditor.Menu.GetMenuItems(string, bool, bool) API, + // which returns an array of internal UnityEditor.ScriptingMenuItem. Resolved once and cached; + // we read each item's `path` and `isSeparator` member (property or field, depending on the + // Unity version). See FocusEditorCommand for the same reflect-into-internal-API approach. + static MethodInfo s_GetMenuItems; + static Func s_GetPath; + static Func s_GetIsSeparator; + static bool s_Resolved; + + static void EnsureReflection() + { + if (s_Resolved) + return; + s_Resolved = true; + + var editorAsm = typeof(EditorApplication).Assembly; + + var menuType = editorAsm.GetType("UnityEditor.Menu"); + s_GetMenuItems = menuType?.GetMethod( + "GetMenuItems", k_All, null, new[] { typeof(string), typeof(bool), typeof(bool) }, null); + + var itemType = editorAsm.GetType("UnityEditor.ScriptingMenuItem"); + s_GetPath = BuildAccessor(itemType, "path", "m_Path"); + s_GetIsSeparator = BuildAccessor(itemType, "isSeparator", "m_IsSeparator"); + } + + /// + /// Build a getter for a member that may be exposed as a property or a backing field, so the + /// reflection survives the internal type's shape changing across Unity versions. + /// + static Func BuildAccessor(Type type, string propertyName, string fieldName) + { + var prop = type?.GetProperty(propertyName, k_All); + if (prop != null) + return o => (T)prop.GetValue(o); + + var field = type?.GetField(propertyName, k_All) ?? type?.GetField(fieldName, k_All); + if (field != null) + return o => (T)field.GetValue(o); + + return null; + } + + // Standard top-level Editor menus. Unity defines these natively (no [MenuItem]), so they are + // not discoverable from attributes; we seed them so their native children are enumerated. + static readonly string[] k_NativeRoots = + { + "File", "Edit", "Assets", "GameObject", "Component", "Window", "Help" + }; + + /// + /// Collect the distinct menu paths from the live Editor menu. Menu.GetMenuItems returns + /// the full (recursive) set of items under a given root — including ones Unity defines + /// natively — but it does not enumerate the roots themselves, and no internal API does. So we + /// union the native roots above with the first path segment of every [MenuItem] (which + /// surfaces custom/package roots), then expand each root through the internal API. The items + /// always come from the live menu, so native entries are included. + /// + static List DiscoverMenuItems() + { + EnsureReflection(); + + if (s_GetMenuItems == null || s_GetPath == null) + throw new InvalidOperationException( + "UnityEditor.Menu.GetMenuItems is unavailable in this Unity version."); + + var paths = new SortedSet(StringComparer.Ordinal); + foreach (var root in CollectRoots()) + CollectItemsUnder(root, paths); + + return paths.ToList(); + } + + /// + /// The top-level menu names to expand: the native roots, plus the first segment of every + /// attributed menu item (covering custom/package menus). Component context menus + /// (CONTEXT/…) are excluded, as they are not part of the main menu bar. + /// + static IEnumerable CollectRoots() + { + var roots = new SortedSet(StringComparer.Ordinal); + foreach (var r in k_NativeRoots) + roots.Add(r); + + foreach (var method in TypeCache.GetMethodsWithAttribute()) + { + foreach (var attr in method.GetCustomAttributes(typeof(MenuItem), false).Cast()) + { + if (attr.validate || string.IsNullOrEmpty(attr.menuItem)) + continue; + + var slash = attr.menuItem.IndexOf('/'); + var root = slash > 0 ? attr.menuItem.Substring(0, slash) : attr.menuItem; + if (root.StartsWith("CONTEXT", StringComparison.Ordinal)) + continue; + + roots.Add(root); + } + } + + return roots; + } + + /// + /// Append every non-separator menu path under to + /// . A root that isn't present in this Editor simply contributes + /// nothing (the API returns an empty array). + /// + static void CollectItemsUnder(string root, SortedSet paths) + { + if (!(s_GetMenuItems.Invoke(null, new object[] { root, false, false }) is Array items)) + return; + + foreach (var item in items) + { + if (item == null) + continue; + if (s_GetIsSeparator != null && s_GetIsSeparator(item)) + continue; + + var path = s_GetPath(item); + if (string.IsNullOrEmpty(path)) + continue; + + paths.Add(path); + } + } + } + + /// + /// Result of the menu command. On execution, false means the item + /// could not be invoked (not found or disabled). In list mode, holds the + /// available menu paths. + /// + [Serializable] + class MenuResponse + { + [JsonProperty("success")] + public bool Success { get; set; } + + [JsonProperty("path")] + public string Path { get; set; } + + [JsonProperty("items")] + public List Items { get; set; } + + [JsonProperty("message")] + public string Message { get; set; } + + public static MenuResponse Fail(string path, string message) => new MenuResponse + { + Success = false, + Path = path, + Message = message + }; + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/MenuItemCommand.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/MenuItemCommand.cs.meta new file mode 100644 index 0000000..92571af --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/MenuItemCommand.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f48719fc11d44809a97c890b8317c0d7 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Navigation.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Navigation.meta new file mode 100644 index 0000000..2dcfd0d --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Navigation.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 31cd60e0286e77f4cb5baaaa7a3d6377 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Navigation/NavigationCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Navigation/NavigationCommands.cs new file mode 100644 index 0000000..383fb98 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Navigation/NavigationCommands.cs @@ -0,0 +1,303 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Models; +using UnityEditor; +using UnityEditor.Search; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace Unity.Pipeline.Editor.Commands.Navigation +{ + /// + /// Navigation and targeting commands (CLI-200): read and drive the Editor selection, and run + /// Unity Search queries — both returning the canonical object + /// identity (via ) so an agent can reference results in a + /// follow-up call. All commands are read-only or non-destructive (set_selection only changes the + /// Editor selection, which carries no undo/safety policy), and run on the main thread. + /// + static class NavigationCommands + { + private const int MaxSearchResults = 200; + + [CliCommand("get_selection", "Read the current Editor selection as structured object identities.", Tags = new[] { "navigation" })] + public static SelectionResult GetSelection() + { + return DescribeSelection(null); + } + + /// + /// Set the Editor selection from instance ids and/or asset paths. + /// + /// We accept simple / rather than full + /// [] handles because nested-object parameter schemas (arrays of objects) + /// are pending CAT-2508. Once that lands this can take an [] and route + /// each through for the full handle surface. + /// + /// + [CliCommand("set_selection", "Set the Editor selection to the given assets/scene objects.", Tags = new[] { "navigation" })] + public static SelectionResult SetSelection( + [CliArg("instance_ids", "Scene/loaded object instance IDs to select.")] ObjectId[] instanceIds = null, + [CliArg("paths", "Asset paths to select (e.g. Assets/Foo.prefab).")] string[] paths = null) + { + var resolved = new List(); + var unresolved = new List(); + + if (instanceIds != null) + { + foreach (var id in instanceIds) + { + var obj = PipelineUtils.IdToObject(id); + if (obj != null) + resolved.Add(obj); + else + unresolved.Add($"instanceId:{id}"); + } + } + + if (paths != null) + { + foreach (var path in paths) + { + var obj = string.IsNullOrEmpty(path) ? null : AssetDatabase.LoadMainAssetAtPath(path); + if (obj != null) + resolved.Add(obj); + else if (path == null) + unresolved.Add(""); + else if (path.Length == 0) + unresolved.Add(""); + else + unresolved.Add(path); + } + } + + var hadInputs = (instanceIds != null && instanceIds.Length > 0) || + (paths != null && paths.Length > 0); + + // Inputs were given but none resolved: that's a hard error, not a silent clear. + if (resolved.Count == 0 && hadInputs) + throw new ArgumentException($"No objects resolved from the given inputs. Unresolved: {string.Join(", ", unresolved)}"); + + // No inputs at all is a valid request to clear the selection. + var objects = resolved.ToArray(); + Selection.objects = objects; + Selection.activeObject = resolved.FirstOrDefault(); + + return DescribeSelection(unresolved.ToArray()); + } + + [CliCommand("search", "Run a Unity Search query and return structured results.", Tags = new[] { "navigation" })] + public static SearchResult Search( + [CliArg("query", "Unity Search query string, e.g. 't:Material', 'p: my asset', 'h: Main Camera'.", Required = true)] string query, + [CliArg("limit", "Max results to return (capped 200).")] int limit = 50) + { + if (string.IsNullOrEmpty(query)) + throw new ArgumentException("query must be a non-empty Unity Search query string."); + + var clamped = Mathf.Clamp(limit, 0, MaxSearchResults); + + // A non-positive limit can't return any rows; skip the potentially expensive request. + if (clamped <= 0) + { + return new SearchResult + { + Query = query, + Count = 0, + Results = Array.Empty() + }; + } + + var results = new List(); + + ISearchList list = null; + try + { + // Synchronous request returns the items already resolved on the main thread. + list = SearchService.Request(query, SearchFlags.Synchronous); + + foreach (var item in list) + { + if (results.Count >= clamped) + break; + if (item == null) + continue; + + // One malformed item must not fail the whole call. + try + { + results.Add(MapItem(item)); + } + catch + { + // skip the unmappable item + } + } + } + catch (Exception ex) + { + throw new InvalidOperationException($"Unity Search query '{query}' failed: {ex.Message}", ex); + } + finally + { + // The Synchronous Request overload returns an ISearchList that owns a SearchContext; + // dispose it when present so we don't leak the context. + (list as IDisposable)?.Dispose(); + } + + return new SearchResult + { + Query = query, + Count = results.Count, + Results = results.ToArray() + }; + } + + private static SearchResultItem MapItem(SearchItem item) + { + string label; + try + { + label = item.GetLabel(item.context, true); + } + catch + { + label = null; + } + + if (string.IsNullOrEmpty(label)) + label = item.label ?? item.id; + + string description = null; + try + { + description = item.GetDescription(item.context, true); + } + catch + { + // leave description null + } + + string path = null; + try + { + var obj = item.ToObject(); + if (obj != null) + { + var assetPath = AssetDatabase.GetAssetPath(obj); + if (!string.IsNullOrEmpty(assetPath)) + path = assetPath; + } + } + catch + { + // leave path null + } + + return new SearchResultItem + { + Id = item.id, + Label = label, + Description = description, + Provider = item.provider?.id, + Path = path + }; + } + + /// + /// Snapshot the current as canonical identities, optionally tagging on + /// the list from a set_selection call. + /// + private static SelectionResult DescribeSelection(string[] unresolved) + { + var objects = Selection.objects ?? Array.Empty(); + var described = objects + .Select(ObjectResolver.Describe) + .Where(r => r != null) + .ToArray(); + + return new SelectionResult + { + Count = described.Length, + Active = ObjectResolver.Describe(Selection.activeObject), + Objects = described, + Unresolved = unresolved + }; + } + } + + /// + /// Structured snapshot of the Editor selection: the active object plus every selected object, + /// each as a canonical identity. is only + /// populated by set_selection (inputs that did not resolve to a loaded object/asset). + /// + [Serializable] + class SelectionResult + { + /// Number of selected objects (excludes nulls). + [JsonProperty("count")] + public int Count { get; set; } + + /// The active selection object, or null when the selection is empty. + [JsonProperty("active")] + public AuthoringResult Active { get; set; } + + /// Every selected object as a canonical identity (nulls skipped). + [JsonProperty("objects")] + public AuthoringResult[] Objects { get; set; } + + /// Inputs that did not resolve (set_selection only); null for get_selection. + [JsonProperty("unresolved")] + public string[] Unresolved { get; set; } + } + + /// + /// Structured result of a Unity Search query: the echoed query, the returned count, and the + /// mapped rows (capped at the requested limit). + /// + [Serializable] + class SearchResult + { + /// The query that was executed (echoed back). + [JsonProperty("query")] + public string Query { get; set; } + + /// Number of results returned (after the limit cap). + [JsonProperty("count")] + public int Count { get; set; } + + /// The mapped search result rows. + [JsonProperty("results")] + public SearchResultItem[] Results { get; set; } + } + + /// + /// One Unity Search result, flattened to portable fields. is populated only + /// when the item resolves to an asset object. + /// + [Serializable] + class SearchResultItem + { + /// Provider-specific item id (e.g. an asset path or scene object id). + [JsonProperty("id")] + public string Id { get; set; } + + /// Display label for the item. + [JsonProperty("label")] + public string Label { get; set; } + + /// Longer description, when the provider supplies one (may be null). + [JsonProperty("description")] + public string Description { get; set; } + + /// Id of the search provider that produced this item (e.g. "asset", "scene"). + [JsonProperty("provider")] + public string Provider { get; set; } + + /// Project-relative asset path, when the item resolves to an asset (else null). + [JsonProperty("path")] + public string Path { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Navigation/NavigationCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Navigation/NavigationCommands.cs.meta new file mode 100644 index 0000000..353e826 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Navigation/NavigationCommands.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a16797feca5bc694cac48b892634bb7a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Observability.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Observability.meta new file mode 100644 index 0000000..e92c7b4 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Observability.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7a7cc3922a14b4741a17d985bb6be540 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Observability/PerformanceCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Observability/PerformanceCommands.cs new file mode 100644 index 0000000..7ea0bf3 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Observability/PerformanceCommands.cs @@ -0,0 +1,171 @@ +using System; +using Newtonsoft.Json; +using Unity.Pipeline.Commands; +using UnityEditor; +using UnityEngine; +using UnityEngine.Profiling; + +namespace Unity.Pipeline.Editor.Commands.Observability +{ + /// + /// Render statistics for the most recently rendered Editor frame, read from + /// . These reflect the last frame the Editor drew (Game/Scene view), not + /// an averaged measurement — treat them as a snapshot. + /// + [Serializable] + class RenderStats + { + /// Draw calls issued for the last rendered frame. + [JsonProperty("drawCalls")] + public int DrawCalls { get; set; } + + /// Total batches (dynamic + static + instanced) for the last rendered frame. + [JsonProperty("batches")] + public int Batches { get; set; } + + /// SetPass calls (shader pass switches) for the last rendered frame. + [JsonProperty("setPassCalls")] + public int SetPassCalls { get; set; } + + /// Triangles submitted for the last rendered frame. + [JsonProperty("triangles")] + public int Triangles { get; set; } + + /// Vertices submitted for the last rendered frame. + [JsonProperty("vertices")] + public int Vertices { get; set; } + } + + /// + /// Process memory usage read from . Values are in bytes and are always + /// available at runtime regardless of whether the Profiler window is open. + /// + [Serializable] + class MemoryStats + { + /// Total memory currently allocated by Unity (bytes). + [JsonProperty("totalAllocatedBytes")] + public long TotalAllocatedBytes { get; set; } + + /// Total memory reserved by Unity (bytes). + [JsonProperty("totalReservedBytes")] + public long TotalReservedBytes { get; set; } + + /// Mono managed heap memory in use (bytes). + [JsonProperty("monoUsedBytes")] + public long MonoUsedBytes { get; set; } + + /// Mono managed heap size reserved (bytes). + [JsonProperty("monoHeapBytes")] + public long MonoHeapBytes { get; set; } + } + + /// + /// Latest CPU/GPU frame timing from . The Frame Timing Manager + /// must have a timing captured for to be true; when unavailable the + /// timing fields are left at zero. + /// + [Serializable] + class FrameTimingStats + { + /// True when a frame timing was captured and the milliseconds fields are meaningful. + [JsonProperty("available")] + public bool Available { get; set; } + + /// Total CPU frame time in milliseconds. + [JsonProperty("cpuFrameTimeMs")] + public double CpuFrameTimeMs { get; set; } + + /// Total GPU frame time in milliseconds. + [JsonProperty("gpuFrameTimeMs")] + public double GpuFrameTimeMs { get; set; } + + /// CPU main-thread frame time in milliseconds. + [JsonProperty("cpuMainThreadFrameTimeMs")] + public double CpuMainThreadFrameTimeMs { get; set; } + } + + /// + /// Composite performance snapshot returned by get_performance_stats: render counters, + /// process memory, and the latest frame timing. + /// + [Serializable] + class PerformanceStats + { + /// Render counters for the last rendered Editor frame. + [JsonProperty("render")] + public RenderStats Render { get; set; } + + /// Process memory usage at capture time. + [JsonProperty("memory")] + public MemoryStats Memory { get; set; } + + /// Latest CPU/GPU frame timing, if one was captured. + [JsonProperty("frameTiming")] + public FrameTimingStats FrameTiming { get; set; } + } + + /// + /// Read-only telemetry command (CLI-198) that snapshots render, memory, and frame-timing stats so + /// an agent can reason about Editor performance without opening the Profiler or Stats overlay. + /// + static class PerformanceCommands + { + [CliCommand("get_performance_stats", "Read render, memory, and frame-timing stats (structured, read-only).", Tags = new[] { "observability/performance" })] + public static PerformanceStats GetPerformanceStats() + { + return new PerformanceStats + { + Render = new RenderStats + { + // UnityStats reflects the last frame rendered by the Editor (Game/Scene view). + DrawCalls = UnityStats.drawCalls, + Batches = UnityStats.dynamicBatches + UnityStats.staticBatches + UnityStats.instancedBatches, + SetPassCalls = UnityStats.setPassCalls, + Triangles = UnityStats.triangles, + Vertices = UnityStats.vertices + }, + Memory = new MemoryStats + { + TotalAllocatedBytes = Profiler.GetTotalAllocatedMemoryLong(), + TotalReservedBytes = Profiler.GetTotalReservedMemoryLong(), + MonoUsedBytes = Profiler.GetMonoUsedSizeLong(), + MonoHeapBytes = Profiler.GetMonoHeapSizeLong() + }, + FrameTiming = CaptureFrameTiming() + }; + } + + /// + /// Capture the latest CPU/GPU frame timing. The Frame Timing Manager only yields data once a + /// timing has been captured (and platform support exists), so any failure or empty result is + /// reported as = false rather than throwing. + /// + private static FrameTimingStats CaptureFrameTiming() + { + try + { + FrameTimingManager.CaptureFrameTimings(); + + var timings = new FrameTiming[1]; + uint received = FrameTimingManager.GetLatestTimings(1, timings); + if (received > 0) + { + return new FrameTimingStats + { + Available = true, + CpuFrameTimeMs = timings[0].cpuFrameTime, + GpuFrameTimeMs = timings[0].gpuFrameTime, + CpuMainThreadFrameTimeMs = timings[0].cpuMainThreadFrameTime + }; + } + } + catch + { + // Frame timing is platform-dependent and may be unsupported; report as unavailable. + } + + return new FrameTimingStats { Available = false }; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Observability/PerformanceCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Observability/PerformanceCommands.cs.meta new file mode 100644 index 0000000..1a6dec8 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Observability/PerformanceCommands.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ae9262a38e20733409c3a084cb810bdc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager.meta new file mode 100644 index 0000000..c9a1dc1 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fdbdf731f3ad41fca20634ebcf5f4d7e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageIdentifier.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageIdentifier.cs new file mode 100644 index 0000000..15c35f9 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageIdentifier.cs @@ -0,0 +1,161 @@ +using System; + +namespace Unity.Pipeline.Editor.Commands.PackageManager +{ + /// Where an added package comes from, derived from its identifier string (CLI-203). + enum PackageSourceKind + { + /// Could not be classified (e.g. empty input). + Unknown, + + /// A registry package name, optionally pinned: com.unity.foo or com.unity.foo@1.2.3. + Registry, + + /// A git URL: https://…​.git, git+…, ssh://…, git@host:…, optionally #revision. + Git, + + /// A local package reference: file:../RelativePath or file:/abs/path. + Local + } + + /// A parsed UPM package_add identifier — the normalized string handed to + /// Client.Add plus the pieces extracted for plan/audit text. + sealed class ParsedPackageId + { + /// How the package will be resolved by UPM. + public PackageSourceKind Kind { get; set; } + + /// The identifier passed verbatim to UnityEditor.PackageManager.Client.Add. + public string Identifier { get; set; } + + /// Registry package name (Registry only); null otherwise. + public string Name { get; set; } + + /// Registry version or git revision when given; null otherwise. + public string Version { get; set; } + + /// Human-readable summary for plan/audit text. + public string Description { get; set; } + } + + /// + /// Pure, editor-independent classification of a package_add identifier into a registry name, + /// git URL, or local path (CLI-203). Kept free of any Unity API so the add-path's input handling is + /// unit-testable without a live editor; the command layer feeds the result to + /// UnityEditor.PackageManager.Client.Add. + /// + static class PackageIdentifier + { + /// Classify an identifier without parsing out its parts. + public static PackageSourceKind Classify(string identifier) + { + if (string.IsNullOrWhiteSpace(identifier)) + return PackageSourceKind.Unknown; + + var id = identifier.Trim(); + + if (StartsWith(id, "file:")) + return PackageSourceKind.Local; + + // Explicit git forms and any URL scheme (UPM treats http(s) identifiers as git URLs). + if (StartsWith(id, "git+") || StartsWith(id, "ssh://") || id.StartsWith("git@", StringComparison.Ordinal)) + return PackageSourceKind.Git; + if (StartsWith(id, "http://") || StartsWith(id, "https://") || id.Contains("://")) + return PackageSourceKind.Git; + + // A bare "owner/repo.git" (no scheme) is still a git reference. Strip an optional + // "#revision" before testing the suffix. + var core = id; + var hash = core.IndexOf('#'); + if (hash >= 0) + core = core.Substring(0, hash); + if (core.EndsWith(".git", StringComparison.OrdinalIgnoreCase)) + return PackageSourceKind.Git; + + return PackageSourceKind.Registry; + } + + /// + /// Classify and split . Returns false with + /// set for empty/unclassifiable input. + /// + public static bool TryParse(string identifier, out ParsedPackageId parsed, out string error) + { + parsed = null; + error = null; + + if (string.IsNullOrWhiteSpace(identifier)) + { + error = "Package identifier is empty. Provide a name (com.unity.foo[@version]), a git URL, or a file: path."; + return false; + } + + var id = identifier.Trim(); + switch (Classify(id)) + { + case PackageSourceKind.Local: + parsed = new ParsedPackageId + { + Kind = PackageSourceKind.Local, + Identifier = id, + Description = $"local package '{id}'" + }; + return true; + + case PackageSourceKind.Git: + { + string revision = null; + var hash = id.IndexOf('#'); + if (hash >= 0 && hash < id.Length - 1) + revision = id.Substring(hash + 1); + parsed = new ParsedPackageId + { + Kind = PackageSourceKind.Git, + Identifier = id, + Version = revision, + Description = revision != null ? $"git package '{id}' @ {revision}" : $"git package '{id}'" + }; + return true; + } + + case PackageSourceKind.Registry: + { + var name = id; + string version = null; + + // Split on the version separator '@'. Use the last '@' so npm-scoped names + // ("@scope/pkg@1.0.0") still split on the version, not the leading scope marker. + var at = id.LastIndexOf('@'); + if (at > 0) + { + name = id.Substring(0, at); + version = id.Substring(at + 1); + } + + if (string.IsNullOrWhiteSpace(name)) + { + error = $"Package name is empty in '{identifier}'."; + return false; + } + + parsed = new ParsedPackageId + { + Kind = PackageSourceKind.Registry, + Identifier = id, + Name = name, + Version = version, + Description = version != null ? $"'{name}' @ {version}" : $"'{name}' (latest compatible)" + }; + return true; + } + + default: + error = $"Could not classify package identifier '{identifier}'."; + return false; + } + } + + private static bool StartsWith(string value, string prefix) => + value.StartsWith(prefix, StringComparison.OrdinalIgnoreCase); + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageIdentifier.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageIdentifier.cs.meta new file mode 100644 index 0000000..2e8ec86 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageIdentifier.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b95405e8a4f04c93acbdd564a74f8cc2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageManagerCommand.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageManagerCommand.cs new file mode 100644 index 0000000..6dc8fb9 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageManagerCommand.cs @@ -0,0 +1,656 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using Newtonsoft.Json; +using Unity.Pipeline.Commands; +using UnityEditor; +using UnityEditor.PackageManager; +using UnityEditor.PackageManager.Requests; +using UnityEngine; +using PackageInfo = UnityEditor.PackageManager.PackageInfo; +#if UNITY_6000_5_OR_NEWER +using Unity.Scripting.LifecycleManagement; +#endif + +namespace Unity.Pipeline.Editor.Commands.PackageManager +{ + /// + /// UPM package management over the Client API (CLI-203): list / search / add / remove / resolve. + /// + /// Threading: UPM operations are asynchronous (the only + /// progresses while the editor ticks) and their members are main-thread only. Commands that wait on a + /// request therefore run off the main thread (MainThreadRequired = false) and marshal every + /// UPM touch back onto the main thread via the server dispatcher (), so they + /// can block without freezing the editor. + /// + /// Command surface: + /// - package_list (installed scope) reads the resolved set inline; available/all + /// and package_search query the registry and wait for it — all return synchronously. + /// - package_add/package_remove mutate the manifest and trigger a domain reload + /// that tears down the in-flight request and the HTTP connection. They are dual-mode: + /// + /// async (default) — kick the op off, return in_progress immediately, and let + /// an poller finalize a Temp status file. Poll + /// package_status until completed/failed, then recompile_status. This + /// keeps the (single-request) server responsive and survives the reload. + /// synchronous (wait=true) — block until the request completes and return the + /// full result. The result is captured in one main-thread hop the moment the request completes + /// (before the compile-triggered reload). Reliable for add; for remove the reload can fire fast + /// enough to drop the reply — the status file still settles, so package_status confirms it. + /// + /// Both write the status file, so a lost reply (or a reload mid-wait) is recoverable via + /// package_status; settles an in_progress + /// file on the next load. + /// - package_resolve records its status too, so package_status validates it. + /// + /// Mutating commands (add / remove) follow the shared confirm/dry_run convention. + /// UPM operations are not part of Unity's Undo. + /// + [InitializeOnLoad] +#if UNITY_6000_5_OR_NEWER + [NoAutoStaticsCleanup] +#endif + static class PackageManagerCommand + { + const string StatusFile = "Temp/pipeline_package_status.json"; + + // Bound on a synchronous wait, kept under the CLI's default request timeout so a stuck operation + // surfaces as a clean error rather than a dropped connection. + const int WaitTimeoutSeconds = 25; + const int PollIntervalMs = 50; + + static readonly object s_Lock = new object(); + + // The in-flight mutating request (add/remove) and how to project its result. s_InProgress is a + // plain flag (read off-thread by IsBusy) so the busy check never touches main-thread-only Request + // members. Both are reset by a domain reload; RecoverInterruptedOperation settles the status file. + static volatile bool s_InProgress; + static Request s_Request; + static string s_Operation; + static string s_Argument; + static Func s_ReadPackage; + + static PackageManagerCommand() + { + RecoverInterruptedOperation(); + } + + // ---- List / search (synchronous) ------------------------------------------------------- + + [CliCommand("package_list", + "List packages by scope: installed (default) | available (registry) | all (both). Returns the full " + + "result synchronously — available/all block until the registry query completes.", + MainThreadRequired = false, + Tags = new[] { "packages" })] + public static object PackageList( + [CliArg("scope", "Which packages to list: installed (default) | available | all.")] string scope = "installed", + [CliArg("include_indirect", "Include indirect (transitive) installed dependencies (applies to scope=installed/all).")] + bool includeIndirect = true, + [CliArg("offline", "For available/all: query the local cache instead of the registry.")] bool offline = false) + { + switch ((scope ?? "installed").Trim().ToLowerInvariant()) + { + case "installed": + return RunOnMain(() => ListInstalled(includeIndirect)); + case "available": + return ListFromRegistry("available", includeIndirect, offline); + case "all": + return ListFromRegistry("all", includeIndirect, offline); + default: + return new PackageListResponse + { + Success = false, + Scope = scope, + Message = $"Unknown scope '{scope}'. Use installed | available | all." + }; + } + } + + /// + /// Installed scope: reflects the resolved + /// set without a registry round-trip. Runs on the main thread (via ). + /// + static PackageListResponse ListInstalled(bool includeIndirect) + { + var summaries = new List(); + foreach (var p in PackageInfo.GetAllRegisteredPackages()) + { + if (includeIndirect || p.isDirectDependency) + summaries.Add(Map(p, isInstalled: true)); + } + + return new PackageListResponse + { + Success = true, + Scope = "installed", + Count = summaries.Count, + Packages = summaries, + Manifest = SafeReadManifest(), + Message = $"{summaries.Count} installed package(s)." + }; + } + + /// + /// available / all scope: these need the registry, so a Client.SearchAll request is + /// started on the main thread and awaited here (on the command's background thread). For + /// all, the installed set is merged in (and marked) so callers see one unified list. + /// + static object ListFromRegistry(string scope, bool includeIndirect, bool offline) + { + var request = RunOnMain(() => Client.SearchAll(offline)); + + if (!WaitForCompletion(request, out var waitError)) + return new PackageListResponse { Success = false, Scope = scope, Message = waitError }; + + return RunOnMain(() => + { + if (request.Status != StatusCode.Success) + return new PackageListResponse + { + Success = false, + Scope = scope, + Message = $"Registry query failed: {request.Error?.message ?? "unknown error"}" + }; + + var packages = BuildScopedList(scope, request.Result, includeIndirect); + return new PackageListResponse + { + Success = true, + Scope = scope, + Count = packages.Count, + Packages = packages, + Manifest = SafeReadManifest(), + Message = $"{packages.Count} package(s)." + }; + }); + } + + /// + /// Combine the registry search result with the installed set per : + /// available returns every registry package (flagged whether it is installed); + /// all returns installed packages (resolved info) plus the registry packages that are + /// not installed. + /// + static List BuildScopedList(string scope, PackageInfo[] available, bool includeIndirect) + { + var installed = new Dictionary(); + foreach (var p in PackageInfo.GetAllRegisteredPackages()) + installed[p.name] = p; + + var result = new List(); + + if (scope == "available") + { + foreach (var p in available ?? Array.Empty()) + result.Add(Map(p, isInstalled: installed.ContainsKey(p.name))); + return result; + } + + // scope == "all": installed entries first (with their resolved info), then registry-only ones. + var seen = new HashSet(); + foreach (var entry in installed.Values) + { + if (!includeIndirect && !entry.isDirectDependency) + continue; + result.Add(Map(entry, isInstalled: true)); + seen.Add(entry.name); + } + foreach (var p in available ?? Array.Empty()) + { + if (!seen.Contains(p.name)) + result.Add(Map(p, isInstalled: false)); + } + return result; + } + + [CliCommand("package_search", + "Search packages available in the registry. Provide a name (e.g. com.unity.foo) or omit to list all. " + + "Returns the full result synchronously (blocks until the registry query completes).", + MainThreadRequired = false, + Tags = new[] { "packages" })] + public static object PackageSearch( + [CliArg("query", "Package name to search for. Omit/empty to list all available packages.")] string query = "", + [CliArg("offline", "Search the local cache only.")] bool offline = false) + { + var trimmed = (query ?? string.Empty).Trim(); + + var request = RunOnMain(() => string.IsNullOrEmpty(trimmed) + ? Client.SearchAll(offline) + : Client.Search(trimmed, offline)); + + if (!WaitForCompletion(request, out var waitError)) + return new PackageSearchResponse { Success = false, Query = trimmed, Message = waitError }; + + return RunOnMain(() => + { + if (request.Status != StatusCode.Success) + return new PackageSearchResponse + { + Success = false, + Query = trimmed, + Message = $"Search failed: {request.Error?.message ?? "unknown error"}" + }; + + var packages = MapMarkingInstalled(request.Result); + return new PackageSearchResponse + { + Success = true, + Query = trimmed, + Count = packages.Count, + Packages = packages, + Message = $"{packages.Count} package(s)." + }; + }); + } + + // ---- Mutating operations (dual-mode, CAT-2509 gated) ----------------------------------- + + [CliCommand("package_add", + "Add a UPM package by name@version, git URL, or 'file:' local path. Async by default (returns " + + "in_progress; poll package_status); pass wait=true to block until added. A recompile/domain reload " + + "follows — poll recompile_status. Requires confirm=true; use dry_run to preview.", + MainThreadRequired = false, + Tags = new[] { "packages" })] + public static object PackageAdd( + [CliArg("identifier", "Package to add: 'com.unity.foo@1.2.3', a git URL, or 'file:../Path'.", Required = true)] string identifier = "", + [CliArg("confirm", "Apply the change. Without it the call is refused.")] bool confirm = false, + [CliArg("dry_run", "Preview the change without applying it.")] bool dryRun = false, + [CliArg("wait", "Block until the operation completes and return the result (synchronous). Default: return immediately and poll package_status.")] bool wait = false) + { + if (!PackageIdentifier.TryParse(identifier, out var parsed, out var parseError)) + return PackageMutationResponse.Failed("add", identifier, parseError); + + if (IsBusy()) + return PackageMutationResponse.Busy("add"); + + return ExecuteMutation( + operation: "add", + commandName: "package_add", + argument: parsed.Identifier, + planText: $"Add package {parsed.Description} [{parsed.Kind}]", + confirm: confirm, + dryRun: dryRun, + wait: wait, + start: () => Client.Add(parsed.Identifier), + readPackage: req => + { + var added = (req as AddRequest)?.Result; + return added != null ? Map(added, isInstalled: true) : null; + }); + } + + [CliCommand("package_remove", + "Remove a UPM package by name. Async by default (returns in_progress; poll package_status); pass " + + "wait=true to block until removed. A recompile/domain reload follows — poll recompile_status. " + + "Requires confirm=true; use dry_run to preview.", + MainThreadRequired = false, + Tags = new[] { "packages" })] + public static object PackageRemove( + [CliArg("name", "Package name to remove (e.g. com.unity.foo).", Required = true)] string name = "", + [CliArg("confirm", "Apply the change. Without it the call is refused.")] bool confirm = false, + [CliArg("dry_run", "Preview the change without applying it.")] bool dryRun = false, + [CliArg("wait", "Block until the operation completes and return the result (synchronous). Default: return immediately and poll package_status.")] bool wait = false) + { + if (string.IsNullOrWhiteSpace(name)) + return PackageMutationResponse.Failed("remove", name, "A package name is required."); + + var packageName = name.Trim(); + + if (IsBusy()) + return PackageMutationResponse.Busy("remove"); + + return ExecuteMutation( + operation: "remove", + commandName: "package_remove", + argument: packageName, + planText: $"Remove package '{packageName}'", + confirm: confirm, + dryRun: dryRun, + wait: wait, + start: () => Client.Remove(packageName), + readPackage: null); + } + + [CliCommand("package_resolve", + "Resolve/refresh packages from the manifest (re-fetch and re-link). May trigger a recompile/domain " + + "reload — poll recompile_status. Its outcome is recorded for package_status.", + MainThreadRequired = true, + Tags = new[] { "packages" })] + public static object PackageResolve() + { + WriteStatus(new PackageStatus + { + Status = "in_progress", + Operation = "resolve", + StartedAt = NowIso(), + Message = "Resolving packages..." + }); + + try + { + // Client.Resolve() is fire-and-forget (returns void) and schedules a resolve on a later + // tick, so the response flushes before any reload — no request to wait on. + Client.Resolve(); + } + catch (Exception ex) + { + var failed = new PackageStatus + { + Status = "failed", + Operation = "resolve", + Success = false, + Error = ex.Message, + Manifest = SafeReadManifest(), + CompletedAt = NowIso(), + Message = $"Resolve failed: {ex.Message}" + }; + WriteStatus(failed); + return PackageMutationResponse.Failed("resolve", null, failed.Error); + } + + var done = new PackageStatus + { + Status = "completed", + Operation = "resolve", + Success = true, + RequiresRecompile = true, + Manifest = SafeReadManifest(), + CompletedAt = NowIso(), + Message = "Resolve requested. If assemblies changed, a domain reload follows — poll recompile_status." + }; + WriteStatus(done); + return ToMutationResponse(done, plan: null); + } + + // ---- Status ---------------------------------------------------------------------------- + + [CliCommand("package_status", + "Status of the last async package operation (add/remove/resolve): idle | in_progress | completed | " + + "failed, with the added package, manifest, and any error.", + MainThreadRequired = false, + Tags = new[] { "packages" })] + public static string GetPackageStatus() + { + if (File.Exists(StatusFile)) + return File.ReadAllText(StatusFile); + return "{\"status\":\"idle\"}"; + } + + // ---- Mutation execution ---------------------------------------------------------------- + + /// + /// Gate (confirm / dry-run) and kick off the mutating op, then + /// either return in_progress (async, default) or block until completion (). + /// Either way the operation is tracked and a status file is written, so the result is recoverable + /// via package_status even if the domain reload severs a synchronous reply. + /// + static object ExecuteMutation( + string operation, string commandName, string argument, string planText, + bool confirm, bool dryRun, bool wait, + Func start, Func readPackage) + { + if (dryRun) + return PackageMutationResponse.DryRunPreview(operation, argument, planText, $"Dry run — {planText}"); + if (!confirm) + return PackageMutationResponse.Rejected(operation, argument, + "Refused: this changes project packages. Re-run with confirm=true to apply, or dry_run=true to preview."); + + // UPM operations are not part of Unity's Undo system, so there is no undo scope here. + var request = RunOnMain(() => + { + var r = start(); + // async mode finalizes via the update-loop poller; sync mode finalizes itself. + BeginTracking(operation, argument, r, readPackage, subscribePoll: !wait); + return r; + }); + + if (request == null) + return PackageMutationResponse.Failed(operation, argument, "Operation was confirmed but failed to start."); + + if (!wait) + return PackageMutationResponse.InProgress(operation, argument, planText); + + // Synchronous: poll until complete, capturing status + result atomically on the main thread + // (a reload can only fire between ticks, so the snapshot can't be interleaved). + var deadline = DateTime.UtcNow.AddSeconds(WaitTimeoutSeconds); + while (true) + { + var status = RunOnMain(TryFinalize); + if (status != null) + return ToMutationResponse(status, planText); + + if (DateTime.UtcNow > deadline) + { + // Hand off to the update-loop poller so package_status still settles after we bail. + RunOnMain(() => { SubscribePoll(); return null; }); + return PackageMutationResponse.Failed(operation, argument, + $"Timed out after {WaitTimeoutSeconds}s; the operation may still be in progress — poll package_status."); + } + + Thread.Sleep(PollIntervalMs); + } + } + + /// Record the in-flight op, write the in_progress status, and (async only) start polling. + static void BeginTracking(string operation, string argument, Request request, + Func readPackage, bool subscribePoll) + { + lock (s_Lock) + { + s_Request = request; + s_Operation = operation; + s_Argument = argument; + s_ReadPackage = readPackage; + s_InProgress = true; + } + + WriteStatus(new PackageStatus + { + Status = "in_progress", + Operation = operation, + Argument = argument, + StartedAt = NowIso(), + Message = $"{operation} in progress. Poll package_status." + }); + + if (subscribePoll) + SubscribePoll(); + } + + static void SubscribePoll() + { + EditorApplication.update -= Poll; + EditorApplication.update += Poll; + } + + /// Update-loop poller for async mode (and a timed-out sync wait): finalize when done. + static void Poll() => TryFinalize(); + + /// + /// If the tracked request has completed, write its final status, clear tracking, and return the + /// status; otherwise return null. Main-thread only (reads Request members); guarded so the sync + /// waiter and the update-loop poller can't double-finalize. + /// + static PackageStatus TryFinalize() + { + lock (s_Lock) + { + var request = s_Request; + if (request == null) + { + EditorApplication.update -= Poll; + return null; + } + if (!request.IsCompleted) + return null; + + var status = BuildStatus(s_Operation, s_Argument, request, s_ReadPackage); + WriteStatus(status); + + s_Request = null; + s_Operation = null; + s_Argument = null; + s_ReadPackage = null; + s_InProgress = false; + EditorApplication.update -= Poll; + return status; + } + } + + static PackageStatus BuildStatus(string operation, string argument, Request request, + Func readPackage) + { + var status = new PackageStatus + { + Operation = operation, + Argument = argument, + CompletedAt = NowIso(), + Manifest = SafeReadManifest() + }; + + if (request.Status == StatusCode.Success) + { + status.Status = "completed"; + status.Success = true; + status.RequiresRecompile = true; + try { status.Package = readPackage?.Invoke(request); } + catch (Exception ex) { Debug.LogWarning($"[pipeline] package result projection failed: {ex.Message}"); } + status.Message = $"{operation} completed."; + } + else + { + status.Status = "failed"; + status.Success = false; + status.Error = request.Error?.message ?? "Unknown package manager error."; + status.Message = $"{operation} failed: {status.Error}"; + } + + return status; + } + + static PackageMutationResponse ToMutationResponse(PackageStatus s, string plan) => new PackageMutationResponse + { + Success = s.Success, + Operation = s.Operation, + Argument = s.Argument, + Status = s.Status, + Applied = s.Success, + Plan = plan, + Package = s.Package, + Manifest = s.Manifest, + RequiresRecompile = s.RequiresRecompile, + Message = s.Message + }; + + /// + /// On load, settle a status file left at "in_progress" by a domain reload (the expected outcome of + /// a successful add/remove). The manifest change that triggered the reload has taken effect, so + /// the op is recorded completed; the follow-on recompile is observed via recompile_status. + /// + static void RecoverInterruptedOperation() + { + try + { + if (!File.Exists(StatusFile)) + return; + + var status = JsonConvert.DeserializeObject(File.ReadAllText(StatusFile)); + if (status == null || status.Status != "in_progress") + return; + + status.Status = "completed"; + status.Success = true; + status.RequiresRecompile = true; + status.CompletedAt = NowIso(); + status.Manifest = SafeReadManifest(); + status.Message = $"{status.Operation} completed (domain reload). Manifest updated; poll recompile_status for the recompile."; + WriteStatus(status); + } + catch (Exception ex) + { + Debug.LogWarning($"[pipeline] package status recovery failed: {ex.Message}"); + } + } + + // ---- Helpers --------------------------------------------------------------------------- + + static bool IsBusy() => s_InProgress; + + /// + /// Block until completes, polling its (main-thread-only) state via + /// while this thread sleeps between checks. Returns false with + /// set on timeout. Used by the read-only registry queries. + /// + static bool WaitForCompletion(Request request, out string error) + { + error = null; + var deadline = DateTime.UtcNow.AddSeconds(WaitTimeoutSeconds); + while (!RunOnMain(() => request.IsCompleted)) + { + if (DateTime.UtcNow > deadline) + { + error = $"Timed out after {WaitTimeoutSeconds}s waiting for the package manager."; + return false; + } + Thread.Sleep(PollIntervalMs); + } + return true; + } + + /// + /// Run on the Unity main thread. When invoked off-thread (the normal case + /// for the waiting commands), it marshals through the live server's dispatcher; when already on + /// the main thread (e.g. a direct in-process/test call, or no server running) it runs inline. + /// + static T RunOnMain(Func fn) + { + var dispatcher = PipelineServerStartup.Server?.Dispatcher; + if (dispatcher != null && dispatcher.IsInitialized && !dispatcher.IsMainThread()) + return dispatcher.Invoke(fn); + return fn(); + } + + static Dictionary SafeReadManifest() => + PackageManifest.TryRead(out var deps, out _) ? deps : null; + + static PackageSummary Map(PackageInfo p, bool isInstalled = false) => new PackageSummary + { + Name = p.name, + Version = p.version, + DisplayName = p.displayName, + Source = p.source.ToString(), + ResolvedPath = p.resolvedPath, + IsDirectDependency = p.isDirectDependency, + IsInstalled = isInstalled + }; + + /// Map registry results, flagging which are currently installed. + static List MapMarkingInstalled(IEnumerable packages) + { + var installed = new HashSet(); + foreach (var p in PackageInfo.GetAllRegisteredPackages()) + installed.Add(p.name); + + var list = new List(); + if (packages != null) + foreach (var p in packages) + list.Add(Map(p, installed.Contains(p.name))); + return list; + } + + static string NowIso() => DateTime.UtcNow.ToString("o"); + + static void WriteStatus(PackageStatus status) + { + try + { + File.WriteAllText(StatusFile, JsonConvert.SerializeObject(status)); + } + catch (Exception ex) + { + Debug.LogError($"[Package] Failed to write status file: {ex.Message}"); + } + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageManagerCommand.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageManagerCommand.cs.meta new file mode 100644 index 0000000..d322b20 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageManagerCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 248529bee7274235a46b64bf3f03da11 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageManifest.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageManifest.cs new file mode 100644 index 0000000..27b4aa8 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageManifest.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Newtonsoft.Json.Linq; +using UnityEngine; + +namespace Unity.Pipeline.Editor.Commands.PackageManager +{ + /// + /// Reads the project's UPM manifest (Packages/manifest.json) dependencies as a flat + /// name → version map, satisfying CLI-203's "return manifest state". The JSON parsing is split into + /// a pure seam so it is unit-testable without a live project; + /// resolves the project path and is main-thread only (it reads + /// ). + /// + static class PackageManifest + { + /// Project-relative path to the UPM manifest. + public const string RelativePath = "Packages/manifest.json"; + + /// Absolute path to the manifest for the current project. Main thread only. + public static string ManifestPath + { + get + { + var projectRoot = Path.GetDirectoryName(Application.dataPath); + return Path.Combine(projectRoot, "Packages", "manifest.json"); + } + } + + /// + /// Parse the dependencies object of a manifest.json document into a name → version map. + /// Returns an empty map for null/empty input or a manifest without dependencies. + /// + public static Dictionary ReadDependencies(string manifestJson) + { + var result = new Dictionary(); + if (string.IsNullOrWhiteSpace(manifestJson)) + return result; + + var root = JObject.Parse(manifestJson); + if (root["dependencies"] is JObject deps) + { + foreach (var kv in deps) + result[kv.Key] = kv.Value?.ToString(); + } + + return result; + } + + /// + /// Read the current project's manifest dependencies. Returns false with + /// set when the manifest is missing or unreadable. + /// + public static bool TryRead(out Dictionary dependencies, out string error) + { + dependencies = null; + error = null; + try + { + var path = ManifestPath; + if (!File.Exists(path)) + { + error = $"manifest not found at {path}"; + return false; + } + + dependencies = ReadDependencies(File.ReadAllText(path)); + return true; + } + catch (Exception ex) + { + error = ex.Message; + return false; + } + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageManifest.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageManifest.cs.meta new file mode 100644 index 0000000..8608bd4 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageManifest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0401cb232d5143bbb185ac248086a09f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageModels.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageModels.cs new file mode 100644 index 0000000..09a9195 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageModels.cs @@ -0,0 +1,209 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Unity.Pipeline.Editor.Commands.PackageManager +{ + /// + /// One package in a list/search/add result — a JSON-friendly projection of + /// UnityEditor.PackageManager.PackageInfo (CLI-203). + /// + [Serializable] + class PackageSummary + { + [JsonProperty("name")] public string Name { get; set; } + [JsonProperty("version")] public string Version { get; set; } + [JsonProperty("displayName")] public string DisplayName { get; set; } + + /// Resolved source: Registry, Embedded, Local, Git, BuiltIn, LocalTarball, Unknown. + [JsonProperty("source")] public string Source { get; set; } + + [JsonProperty("resolvedPath")] public string ResolvedPath { get; set; } + + /// True when the package is a direct manifest dependency (vs. a transitive one). + [JsonProperty("isDirectDependency")] public bool IsDirectDependency { get; set; } + + /// True when the package is currently installed/resolved in the project (vs. only + /// available in the registry). Always true for an installed-scope listing. + [JsonProperty("isInstalled")] public bool IsInstalled { get; set; } + } + + /// + /// Synchronous result of package_list (CLI-203). The command returns the full result in one + /// call for every scope — installed reads the resolved set inline; available/all + /// run a registry query and block until it completes — so listing never uses the trigger-then-poll + /// path that the mutating commands do. + /// + [Serializable] + class PackageListResponse + { + [JsonProperty("success")] public bool Success { get; set; } + + /// The scope that was listed: installed | available | all. + [JsonProperty("scope")] public string Scope { get; set; } + + [JsonProperty("count")] public int Count { get; set; } + + /// The packages in the requested scope. + [JsonProperty("packages")] public List Packages { get; set; } + + /// Manifest dependencies (name → version). + [JsonProperty("manifest")] public Dictionary Manifest { get; set; } + + [JsonProperty("message")] public string Message { get; set; } + } + + /// + /// Synchronous result of package_search (CLI-203). Like package_list, the registry + /// query is awaited inside the command, so the matches are returned in one call. Each entry carries + /// so callers can tell which results are already installed. + /// + [Serializable] + class PackageSearchResponse + { + [JsonProperty("success")] public bool Success { get; set; } + + /// The search query (empty when listing all available packages). + [JsonProperty("query")] public string Query { get; set; } + + [JsonProperty("count")] public int Count { get; set; } + + /// The matching packages available in the registry. + [JsonProperty("packages")] public List Packages { get; set; } + + [JsonProperty("message")] public string Message { get; set; } + } + + /// + /// Persisted status of the last async mutating operation (add / remove / resolve), written to a Temp + /// status file that survives the domain reload an add/remove/resolve triggers (CLI-203). Read back + /// verbatim by package_status so a caller can poll an async op — or validate one whose + /// synchronous reply was lost to the reload. + /// + [Serializable] + class PackageStatus + { + /// idle | in_progress | completed | failed. + [JsonProperty("status")] public string Status { get; set; } + + /// add | remove | resolve. + [JsonProperty("operation")] public string Operation { get; set; } + + /// The operation's subject (identifier/name), when applicable. + [JsonProperty("argument")] public string Argument { get; set; } + + [JsonProperty("success")] public bool Success { get; set; } + + [JsonProperty("error")] public string Error { get; set; } + + [JsonProperty("message")] public string Message { get; set; } + + /// The operation triggers a recompile/domain reload; poll recompile_status. + [JsonProperty("requiresRecompile")] public bool RequiresRecompile { get; set; } + + /// The added package (add only); null for remove/resolve. + [JsonProperty("package")] public PackageSummary Package { get; set; } + + /// Manifest dependencies (name → version) after the operation. + [JsonProperty("manifest")] public Dictionary Manifest { get; set; } + + [JsonProperty("startedAt")] public string StartedAt { get; set; } + [JsonProperty("completedAt")] public string CompletedAt { get; set; } + } + + /// + /// Result of a mutating package command — package_add / package_remove / + /// package_resolve (CLI-203). These are dual-mode: by default the call returns + /// in_progress immediately (poll package_status); with wait=true it blocks and + /// this carries the final completed/failed outcome. It reports the confirm/dry_run + /// gate via / . A successful add/remove + /// leaves a recompile/domain reload in flight () — poll + /// recompile_status to wait for the editor to be ready. + /// + [Serializable] + class PackageMutationResponse + { + [JsonProperty("success")] public bool Success { get; set; } + + /// add | remove | resolve. + [JsonProperty("operation")] public string Operation { get; set; } + + /// The operation's subject (identifier/name), when applicable. + [JsonProperty("argument")] public string Argument { get; set; } + + /// in_progress | completed | dry_run | rejected | failed | busy. + [JsonProperty("status")] public string Status { get; set; } + + /// True only when the operation actually mutated the project. + [JsonProperty("applied")] public bool Applied { get; set; } + + [JsonProperty("dryRun")] public bool DryRun { get; set; } + + /// Human-readable description of the intended/performed change. + [JsonProperty("plan")] public string Plan { get; set; } + + /// The operation leaves a recompile/domain reload in flight; poll recompile_status. + [JsonProperty("requiresRecompile")] public bool RequiresRecompile { get; set; } + + /// The added package (add only); null for remove/resolve. + [JsonProperty("package")] public PackageSummary Package { get; set; } + + /// Manifest dependencies (name → version) after the operation. + [JsonProperty("manifest")] public Dictionary Manifest { get; set; } + + [JsonProperty("message")] public string Message { get; set; } + + public static PackageMutationResponse InProgress(string operation, string argument, string plan) => + new PackageMutationResponse + { + Success = true, + Operation = operation, + Argument = argument, + Status = "in_progress", + Applied = true, + Plan = plan, + Message = $"{operation} started. Poll package_status until status is 'completed' or 'failed'." + }; + + public static PackageMutationResponse Busy(string operation) => + new PackageMutationResponse + { + Success = false, + Operation = operation, + Status = "busy", + Message = "Another package operation is in progress. Poll package_status, then retry." + }; + + public static PackageMutationResponse DryRunPreview(string operation, string argument, string plan, string message) => + new PackageMutationResponse + { + Success = true, + Operation = operation, + Argument = argument, + Status = "dry_run", + DryRun = true, + Plan = plan, + Message = message + }; + + public static PackageMutationResponse Rejected(string operation, string argument, string message) => + new PackageMutationResponse + { + Success = false, + Operation = operation, + Argument = argument, + Status = "rejected", + Message = message + }; + + public static PackageMutationResponse Failed(string operation, string argument, string message) => + new PackageMutationResponse + { + Success = false, + Operation = operation, + Argument = argument, + Status = "failed", + Message = message + }; + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageModels.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageModels.cs.meta new file mode 100644 index 0000000..01d45bd --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/PackageManager/PackageModels.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8fa665b51bbb4f2d8543fc02de12c377 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/PlayModeCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/PlayModeCommands.cs new file mode 100644 index 0000000..b06d056 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/PlayModeCommands.cs @@ -0,0 +1,55 @@ +using Unity.Pipeline.Commands; +using UnityEditor; +using UnityEngine; + +namespace Unity.Pipeline.Editor.Commands +{ + /// + /// Commands for controlling Unity Editor play mode state. + /// Enables automation workflows to control Editor play/stop/pause from CLI tools. + /// + static class PlayModeCommands + { + // TODO Pipeline: should all commands have name with namespace: editor.play build.generate instead of using _ + + [CliCommand("editor_play", "Enter Unity Editor play mode", Tags = new[] { "editor/playmode" })] + public static string EnterPlayMode() + { + if (EditorApplication.isPlaying) + { + Debug.LogWarning("Editor is already in play mode"); + return "Already in play mode"; + } + + EditorApplication.isPlaying = true; + return "Entered play mode"; + } + + [CliCommand("editor_stop", "Exit Unity Editor play mode", Tags = new[] { "editor/playmode" })] + public static string ExitPlayMode() + { + if (!EditorApplication.isPlaying) + { + Debug.LogWarning("Editor is already in edit mode"); + return "Already in edit mode"; + } + + EditorApplication.isPlaying = false; + return "Exited play mode"; + } + + [CliCommand("editor_pause", "Toggle pause state of Unity Editor play mode", Tags = new[] { "editor/playmode" })] + public static string PausePlayMode() + { + if (!EditorApplication.isPlaying) + { + Debug.LogWarning("Cannot pause - Editor is not in play mode"); + return "Cannot pause - not in play mode"; + } + + EditorApplication.isPaused = !EditorApplication.isPaused; + string state = EditorApplication.isPaused ? "paused" : "unpaused"; + return $"Play mode {state}"; + } + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/PlayModeCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/PlayModeCommands.cs.meta new file mode 100644 index 0000000..2eecf4b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/PlayModeCommands.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c86c7028f3fb8f24691d8a3a207f53ff +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Prefabs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Prefabs.meta new file mode 100644 index 0000000..23a327d --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Prefabs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1e6ed0649e884a59b7403a2f28a87644 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Prefabs/PrefabCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Prefabs/PrefabCommands.cs new file mode 100644 index 0000000..6797d7e --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Prefabs/PrefabCommands.cs @@ -0,0 +1,416 @@ +using System; +using System.IO; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Models; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; +using UnityEngine.SceneManagement; +using Object = UnityEngine.Object; + +namespace Unity.Pipeline.Editor.Commands.Prefabs +{ + /// + /// Prefab authoring commands (CLI-194). These cover the prefab lifecycle an agent needs to + /// build content procedurally: saving a configured GameObject as a prefab asset, instantiating + /// it into a scene, deriving a variant, applying/reverting instance overrides, unpacking, and + /// editing prefab contents through the prefab stage. + /// + /// Authoring conventions (CLI-190): + /// - Asset paths flow through so writes are sandboxed to the + /// authoring root and "../" traversal is rejected. + /// - Existing objects are referenced by and resolved with + /// ; results are returned as . + /// - Scene/object mutations (instantiation, override apply/revert, unpack) are wrapped in an + /// so they revert as one Editor undo step. + /// + /// IMPORTANT about undo coverage: prefab ASSET writes (, + /// variant creation, and prefab-stage save) are AssetDatabase operations and are NOT part of + /// Unity's Undo system, so the undo scope only reverts the scene-side effects. This mirrors the + /// note in and . + /// + /// Nested-prefab safety: structural edits to a prefab asset go through the prefab stage + /// ( / / + /// ) rather than mutating the asset root directly, + /// which preserves nested-prefab links instead of flattening them. + /// + static class PrefabCommands + { + /// + /// Save a source GameObject (typically a scene object) as a prefab asset. The source becomes + /// a connected instance of the new prefab (interactionMode: AutomatedAction). + /// + [CliCommand("create_prefab", "Save a GameObject as a prefab asset at a project path; the source becomes a connected instance.", Tags = new[] { "prefabs" })] + public static AuthoringResult CreatePrefab( + [CliArg("source", "Reference to the source GameObject to save as a prefab (globalId/path/guid/instanceId/hierarchyPath).", Required = true)] ObjectRef source, + [CliArg("path", "Prefab asset path relative to the authoring root (the Assets/ prefix is optional and the .prefab extension is added if missing). e.g. Prefabs/Enemy or Prefabs/Enemy.prefab", Required = true)] string path) + { + var go = ResolveGameObject(source, "source"); + + var assetPath = ResolvePrefabPath(path); + EnsureParentFolder(assetPath); + + GameObject saved; + using (new AuthoringUndoScope("Create Prefab")) + { + // ConnectToInstance leaves the source as an instance of the saved prefab so the agent + // can keep editing it; SaveAsPrefabAsset itself is an AssetDatabase op (not undoable). + saved = PrefabUtility.SaveAsPrefabAssetAndConnect(go, assetPath, InteractionMode.AutomatedAction, out var success); + if (!success || saved == null) + throw new InvalidOperationException($"Failed to save prefab at '{assetPath}'."); + } + + AssetDatabase.SaveAssets(); + var asset = AssetDatabase.LoadAssetAtPath(assetPath); + var result = ObjectResolver.Describe(asset) ?? new AuthoringResult { Type = nameof(GameObject) }; + result.AssetPath = assetPath; + return result; + } + + /// + /// Instantiate a prefab asset into the active (or specified) loaded scene and return the + /// scene instance's identity. + /// + [CliCommand("instantiate_prefab", "Instantiate a prefab asset into a loaded scene and return the created instance.", Tags = new[] { "prefabs" })] + public static AuthoringResult InstantiatePrefab( + [CliArg("prefab", "Reference to the prefab asset to instantiate (path/guid/globalId).", Required = true)] ObjectRef prefab, + [CliArg("scene_path", "Optional path of a loaded scene to instantiate into; defaults to the active scene.")] string scenePath = null, + [CliArg("name", "Optional name for the created instance; defaults to the prefab name.")] string name = null) + { + var prefabAsset = ResolvePrefabAsset(prefab, "prefab"); + + var scene = ResolveTargetScene(scenePath); + if (!scene.IsValid() || !scene.isLoaded) + throw new InvalidOperationException("No valid loaded scene to instantiate into."); + + AuthoringResult result; + using (new AuthoringUndoScope("Instantiate Prefab")) + { + var instance = (GameObject)PrefabUtility.InstantiatePrefab(prefabAsset, scene); + if (instance == null) + throw new InvalidOperationException($"Failed to instantiate prefab '{AssetDatabase.GetAssetPath(prefabAsset)}'."); + + if (!string.IsNullOrEmpty(name)) + instance.name = name; + + Undo.RegisterCreatedObjectUndo(instance, "Instantiate Prefab"); + EditorSceneManager.MarkSceneDirty(scene); + + result = ObjectResolver.Describe(instance) ?? new AuthoringResult { Type = nameof(GameObject) }; + } + + return result; + } + + /// + /// Create a prefab variant asset from a base prefab. The variant inherits the base and can + /// override it. Implemented by instantiating the base, saving the instance as a new prefab + /// asset (which becomes a variant because its root is a base-prefab instance), then removing + /// the temporary scene instance. + /// + [CliCommand("create_prefab_variant", "Create a prefab variant asset that inherits from a base prefab.", Tags = new[] { "prefabs" })] + public static AuthoringResult CreatePrefabVariant( + [CliArg("base", "Reference to the base prefab asset (path/guid/globalId).", Required = true)] ObjectRef basePrefab, + [CliArg("path", "Variant prefab asset path relative to the authoring root (.prefab added if missing).", Required = true)] string path) + { + var basePrefabAsset = ResolvePrefabAsset(basePrefab, "base"); + + var assetPath = ResolvePrefabPath(path); + EnsureParentFolder(assetPath); + + // Author the variant from a throwaway instance of the base (saving an instance of a prefab + // as a new prefab yields a variant). The temporary instance is created in an isolated + // preview scene and the instance + scene are torn down in the finally, so the user's active + // scene is never touched, dirtied, or subjected to object lifecycle callbacks. + var previewScene = EditorSceneManager.NewPreviewScene(); + GameObject instance = null; + GameObject variant; + try + { + instance = (GameObject)PrefabUtility.InstantiatePrefab(basePrefabAsset, previewScene); + if (instance == null) + throw new InvalidOperationException("Failed to instantiate base prefab for variant creation."); + + variant = PrefabUtility.SaveAsPrefabAsset(instance, assetPath, out var success); + if (!success || variant == null) + throw new InvalidOperationException($"Failed to save prefab variant at '{assetPath}'."); + } + finally + { + if (instance != null) + Object.DestroyImmediate(instance); + EditorSceneManager.ClosePreviewScene(previewScene); + } + + AssetDatabase.SaveAssets(); + var asset = AssetDatabase.LoadAssetAtPath(assetPath); + var result = ObjectResolver.Describe(asset) ?? new AuthoringResult { Type = nameof(GameObject) }; + result.AssetPath = assetPath; + return result; + } + + /// + /// Apply a prefab instance's overrides back to its source prefab asset. By default applies + /// the whole instance; the asset is updated on disk. + /// + [CliCommand("apply_prefab_overrides", "Apply a prefab instance's overrides back to its source prefab asset.", Tags = new[] { "prefabs" })] + public static AuthoringResult ApplyPrefabOverrides( + [CliArg("instance", "Reference to a prefab instance GameObject in a scene (instanceId/hierarchyPath/globalId).", Required = true)] ObjectRef instance) + { + var go = ResolveGameObject(instance, "instance"); + var root = PrefabUtility.GetOutermostPrefabInstanceRoot(go); + if (root == null) + throw new ArgumentException($"Object '{instance}' is not part of a prefab instance."); + + var assetPath = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(root); + // Applying overrides writes back to the source prefab asset, so confine it to the + // authoring root and reject instances whose source lives outside the sandbox. + ConfineToAuthoringRoot(assetPath, "instance's source prefab asset"); + + using (new AuthoringUndoScope("Apply Prefab Overrides")) + { + Undo.RegisterFullObjectHierarchyUndo(root, "Apply Prefab Overrides"); + PrefabUtility.ApplyPrefabInstance(root, InteractionMode.AutomatedAction); + EditorSceneManager.MarkSceneDirty(root.scene); + } + + AssetDatabase.SaveAssets(); + + var asset = AssetDatabase.LoadAssetAtPath(assetPath); + var result = ObjectResolver.Describe(asset) ?? new AuthoringResult { Type = nameof(GameObject) }; + if (!string.IsNullOrEmpty(assetPath)) + result.AssetPath = assetPath; + return result; + } + + /// + /// Revert a prefab instance's overrides, restoring it to match its source prefab asset. + /// + [CliCommand("revert_prefab_overrides", "Revert a prefab instance's overrides so it matches its source prefab asset.", Tags = new[] { "prefabs" })] + public static AuthoringResult RevertPrefabOverrides( + [CliArg("instance", "Reference to a prefab instance GameObject in a scene (instanceId/hierarchyPath/globalId).", Required = true)] ObjectRef instance) + { + var go = ResolveGameObject(instance, "instance"); + var root = PrefabUtility.GetOutermostPrefabInstanceRoot(go); + if (root == null) + throw new ArgumentException($"Object '{instance}' is not part of a prefab instance."); + + using (new AuthoringUndoScope("Revert Prefab Overrides")) + { + Undo.RegisterFullObjectHierarchyUndo(root, "Revert Prefab Overrides"); + PrefabUtility.RevertPrefabInstance(root, InteractionMode.AutomatedAction); + EditorSceneManager.MarkSceneDirty(root.scene); + } + + var result = ObjectResolver.Describe(root) ?? new AuthoringResult { Type = nameof(GameObject) }; + return result; + } + + /// + /// Unpack a prefab instance, turning it (and optionally its nested instances) back into plain + /// GameObjects. chooses between + /// (one level) and + /// (all nested levels). + /// + [CliCommand("unpack_prefab", "Unpack a prefab instance into plain GameObjects (outermost level or completely).", Tags = new[] { "prefabs" })] + public static AuthoringResult UnpackPrefab( + [CliArg("instance", "Reference to a prefab instance GameObject in a scene (instanceId/hierarchyPath/globalId).", Required = true)] ObjectRef instance, + [CliArg("completely", "If true, unpack all nested prefab levels (Completely); if false, only the outermost level (OutermostRoot).", DefaultValue = false)] bool completely = false) + { + var go = ResolveGameObject(instance, "instance"); + var root = PrefabUtility.GetOutermostPrefabInstanceRoot(go); + if (root == null) + throw new ArgumentException($"Object '{instance}' is not part of a prefab instance."); + + var mode = completely ? PrefabUnpackMode.Completely : PrefabUnpackMode.OutermostRoot; + + using (new AuthoringUndoScope("Unpack Prefab")) + { + PrefabUtility.UnpackPrefabInstance(root, mode, InteractionMode.AutomatedAction); + EditorSceneManager.MarkSceneDirty(root.scene); + } + + var result = ObjectResolver.Describe(root) ?? new AuthoringResult { Type = nameof(GameObject) }; + return result; + } + + /// + /// Edit a prefab asset's contents safely through the prefab stage. Loads the prefab into an + /// isolated, editable copy, optionally renames a child or reparents/adds nothing structural by + /// default, then saves and unloads. This is the nested-prefab-safe path: it never mutates the + /// asset root in-place, so nested prefab links are preserved. + /// + /// The MVP supports a small, declarative set of edits expressed as arguments so an agent can + /// drive common changes without an embedded script: + /// - + : toggle a child's activeSelf. + /// - + : rename a child. + /// A no-op call (no edit args) simply round-trips the asset through the stage, which is a useful + /// integrity check that the open/edit/close cycle does not corrupt the asset. + /// + [CliCommand("save_prefab_contents", "Open a prefab asset in an isolated prefab stage, apply a declarative edit, and save it back (nested-prefab safe).", Tags = new[] { "prefabs" })] + public static AuthoringResult SavePrefabContents( + [CliArg("prefab", "Reference to the prefab asset to edit (path/guid/globalId).", Required = true)] ObjectRef prefab, + [CliArg("rename_child", "Optional child name (relative path under the root, e.g. 'Body/Head') to rename.")] string renameChild = null, + [CliArg("new_name", "New name for the child identified by rename_child.")] string newName = null, + [CliArg("set_active_child", "Optional child name (relative path under the root) whose active state to set.")] string setActiveChild = null, + [CliArg("active", "Active state to apply when set_active_child is provided.", DefaultValue = true)] bool active = true) + { + var prefabAsset = ResolvePrefabAsset(prefab, "prefab"); + var assetPath = AssetDatabase.GetAssetPath(prefabAsset); + if (string.IsNullOrEmpty(assetPath)) + throw new ArgumentException($"'{prefab}' does not resolve to a prefab asset on disk."); + // This command writes the prefab asset back to disk, so confine it to the authoring root. + ConfineToAuthoringRoot(assetPath, "prefab asset"); + + // LoadPrefabContents gives an isolated, fully-editable copy of the prefab (with nested + // prefabs intact). All edits happen on this copy; SaveAsPrefabAsset writes it back without + // flattening nested prefabs. Always unload to avoid leaking the temporary scene. + var contentsRoot = PrefabUtility.LoadPrefabContents(assetPath); + try + { + if (!string.IsNullOrEmpty(renameChild)) + { + var child = FindChild(contentsRoot.transform, renameChild); + if (child == null) + throw new ArgumentException($"No child '{renameChild}' under prefab root '{contentsRoot.name}'."); + if (string.IsNullOrEmpty(newName)) + throw new ArgumentException("new_name is required when rename_child is provided."); + child.name = newName; + } + + if (!string.IsNullOrEmpty(setActiveChild)) + { + var child = FindChild(contentsRoot.transform, setActiveChild); + if (child == null) + throw new ArgumentException($"No child '{setActiveChild}' under prefab root '{contentsRoot.name}'."); + child.gameObject.SetActive(active); + } + + PrefabUtility.SaveAsPrefabAsset(contentsRoot, assetPath, out var success); + if (!success) + throw new InvalidOperationException($"Failed to save prefab contents to '{assetPath}'."); + } + finally + { + PrefabUtility.UnloadPrefabContents(contentsRoot); + } + + AssetDatabase.SaveAssets(); + var asset = AssetDatabase.LoadAssetAtPath(assetPath); + var result = ObjectResolver.Describe(asset) ?? new AuthoringResult { Type = nameof(GameObject) }; + result.AssetPath = assetPath; + return result; + } + + #region Helpers + + /// Resolve an to a GameObject (a component ref maps to its GameObject). + private static GameObject ResolveGameObject(ObjectRef handle, string argName) + { + if (!ObjectResolver.TryResolve(handle, out var obj, out var error)) + throw new ArgumentException($"Could not resolve {argName}: {error}"); + + var go = obj as GameObject ?? (obj as Component)?.gameObject; + if (go == null) + throw new ArgumentException($"{argName} '{handle}' does not resolve to a GameObject (got {obj.GetType().Name})."); + return go; + } + + /// Resolve an to a prefab asset GameObject on disk. + private static GameObject ResolvePrefabAsset(ObjectRef handle, string argName) + { + if (!ObjectResolver.TryResolve(handle, out var obj, out var error)) + throw new ArgumentException($"Could not resolve {argName}: {error}"); + + var go = obj as GameObject; + if (go == null) + throw new ArgumentException($"{argName} '{handle}' does not resolve to a prefab GameObject (got {obj.GetType().Name})."); + + var assetPath = AssetDatabase.GetAssetPath(go); + if (string.IsNullOrEmpty(assetPath) || !assetPath.EndsWith(".prefab", StringComparison.OrdinalIgnoreCase)) + throw new ArgumentException($"{argName} '{handle}' is not a prefab asset."); + return go; + } + + /// Sandbox + normalize a prefab asset path, ensuring the .prefab extension. + private static string ResolvePrefabPath(string path) + { + var resolved = ProjectPaths.Resolve(path, out var error); + if (resolved == null) + throw new ArgumentException(error); + + if (!resolved.EndsWith(".prefab", StringComparison.OrdinalIgnoreCase)) + resolved += ".prefab"; + return resolved; + } + + /// + /// Confine an existing asset path (one discovered from a resolved object, not user-supplied) + /// to the authoring root, rejecting writes outside the sandbox. Runs the path through + /// , which honors explicit "Assets/..." paths as-is and + /// errors when they escape the root. describes the path for the error. + /// + private static void ConfineToAuthoringRoot(string assetPath, string what) + { + if (ProjectPaths.Resolve(assetPath, out var error) == null) + throw new ArgumentException($"The {what} ('{assetPath}') is outside the authoring root: {error}"); + } + + /// Create the parent folder chain for an asset path if it does not yet exist. + private static void EnsureParentFolder(string assetPath) + { + var parent = Path.GetDirectoryName(assetPath)?.Replace('\\', '/'); + if (string.IsNullOrEmpty(parent) || AssetDatabase.IsValidFolder(parent)) + return; + CreateFolderRecursive(parent); + AssetDatabase.Refresh(); + } + + private static void CreateFolderRecursive(string folderPath) + { + if (AssetDatabase.IsValidFolder(folderPath)) + return; + + var parent = Path.GetDirectoryName(folderPath)?.Replace('\\', '/'); + var name = Path.GetFileName(folderPath); + if (string.IsNullOrEmpty(parent) || string.IsNullOrEmpty(name)) + throw new ArgumentException($"Invalid folder path '{folderPath}'."); + + if (!AssetDatabase.IsValidFolder(parent)) + CreateFolderRecursive(parent); + + AssetDatabase.CreateFolder(parent, name); + } + + /// Resolve the scene to instantiate into: a named loaded scene, or the active scene. + private static Scene ResolveTargetScene(string scenePath) + { + if (string.IsNullOrEmpty(scenePath)) + return SceneManager.GetActiveScene(); + + for (int i = 0; i < SceneManager.sceneCount; i++) + { + var scene = SceneManager.GetSceneAt(i); + if (scene.isLoaded && + (string.Equals(scene.path, scenePath, StringComparison.OrdinalIgnoreCase) || + string.Equals(scene.name, scenePath, StringComparison.OrdinalIgnoreCase))) + { + return scene; + } + } + + throw new ArgumentException($"No loaded scene matching '{scenePath}'."); + } + + /// Find a descendant by a '/'-separated relative path under a root transform. + private static Transform FindChild(Transform root, string relativePath) + { + // Transform.Find already supports '/'-separated paths for descendants. Normalize Windows-style + // '\' separators to '/' first (mirrors ProjectPaths.Resolve) so paths like 'Body\Head' work. + return root.Find(relativePath.Replace('\\', '/').Trim('/')); + } + + #endregion + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Prefabs/PrefabCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Prefabs/PrefabCommands.cs.meta new file mode 100644 index 0000000..e016724 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Prefabs/PrefabCommands.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f7c0d242da0d4deb9c5138d8966c51e2 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectAudit.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectAudit.meta new file mode 100644 index 0000000..1eb046b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectAudit.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a511f17b426c94dbb8b78d0869749d40 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectAudit/ProjectAuditCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectAudit/ProjectAuditCommands.cs new file mode 100644 index 0000000..933f533 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectAudit/ProjectAuditCommands.cs @@ -0,0 +1,604 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading; +using Newtonsoft.Json; +using Unity.Pipeline.Commands; +using UnityEditor; +using UnityEngine; +#if UNITY_6000_5_OR_NEWER +using Unity.Scripting.LifecycleManagement; +#endif + +namespace Unity.Pipeline.Editor.Commands.ProjectAudit +{ + /// + /// Exposes Unity's Project Auditor static-analysis scan as audit / audit_status: + /// start a scan, poll it, read a CSV of the reported issues. + /// + /// Project Auditor is reached entirely by reflection (as reaches + /// its editor internals): this package must compile and run in editors without Project Auditor, so + /// it takes no asmdef reference and no package dependency. One reflection path covers both Project + /// Auditor deployments — the built-in editor module and the com.unity.project-auditor package — + /// because they share the type name and public surface. They do not share an assembly name, so the + /// lookup scans loaded assemblies rather than naming one; see . + /// + /// AuditAsync is only partly asynchronous: it blocks its caller through assembly + /// compilation and the first analysis phase, then finishes on its own background thread and fires + /// OnCompleted there (or synchronously, when Code analysis is out of scope). So + /// audit only enqueues — an hook runs the scan on a + /// later tick — and audit_status answers off the main thread while compilation holds it. + /// + /// A resolvable Project Auditor is not necessarily a usable one: as a built-in editor module its + /// rules ship in the separate com.unity.project-auditor-rules package, and without them it + /// registers no modules and produces an empty report indistinguishable from a clean project. + /// Hence the registered-modules check, reported as unavailable. + /// + [InitializeOnLoad] +#if UNITY_6000_5_OR_NEWER + [NoAutoStaticsCleanup] +#endif + static class ProjectAuditCommands + { + const string StatusFile = "Temp/pipeline_audit_status.json"; + const string CsvDirectory = "Temp/pipeline-audit"; + const string RulesPackageName = "com.unity.project-auditor-rules"; + const string AuditorTypeName = "Unity.ProjectAuditor.Editor.ProjectAuditor"; + + static readonly object s_Lock = new object(); + + // Enqueued by audit(); consumed by the OnUpdate pump on the next main-thread tick. + static bool s_Pending; + // True from when the pump starts a scan until OnDone (completion) or a start failure. + static bool s_Scanning; + // Category array for AnalysisParams.Categories (element type varies by deployment), or null = all. + static object s_PendingCategories; + static string s_ScanId; + static string s_CsvPath; + // Last status JSON successfully written; lets audit_status answer while a write is in flight. + static volatile string s_LastStatusJson; + + static ProjectAuditCommands() + { + // A scan cannot survive a domain reload (its background thread and our static state are + // gone), so flip any dangling "scanning" status to "interrupted" before watching again. + ReconcileAfterReload(); + EditorApplication.update += OnUpdate; + } + + [CliCommand("audit", "Run a Project Auditor static-analysis scan. Returns immediately; poll audit_status until status is 'completed', then read the CSV.", MainThreadRequired = false, Tags = new[] { "observability/audit" })] + public static object Audit( + [CliArg("categories", "Comma-separated issue categories to scan (e.g. Code,ProjectSetting,Texture). Default: all categories.")] string categories = "", + [CliArg("output", "CSV output path (absolute or relative to the project root). Defaults to Temp/pipeline-audit/.csv.")] string output = "") + { + if (!TryResolve(out var pa, out var error)) + return new { status = "unavailable", message = error }; + + var requested = ParseCategoryNames(categories); + var validNames = Enum.GetNames(pa.IssueCategoryType); + var validationError = ValidateCategories(requested, validNames); + if (validationError != null) + return new { status = "error", message = validationError }; + + lock (s_Lock) + { + if (s_Pending || s_Scanning) + return new { status = "busy", message = "An audit is already queued or running. Poll audit_status." }; + + s_ScanId = Guid.NewGuid().ToString("N").Substring(0, 8); + s_CsvPath = ResolveCsvPath(output, s_ScanId); + s_PendingCategories = BuildCategoriesArray(pa, requested); + s_Pending = true; + + // Written inside the lock: the pump can take it on the very next frame and write a + // terminal status synchronously (unavailable, or completed when the scan runs inline). + // Writing after the release would clobber that, wedging audit_status on "scanning". + WriteStatus(new AuditStatus { Status = "scanning", ScanId = s_ScanId, CsvPath = s_CsvPath }); + } + + return new { status = "scanning", scanId = s_ScanId, csvPath = s_CsvPath }; + } + + [CliCommand("audit_status", "Get the status of the last audit: idle | scanning | completed | failed | interrupted | unavailable.", MainThreadRequired = false, Tags = new[] { "observability/audit" })] + public static string AuditStatus() + { + if (!TryResolve(out _, out var error)) + return JsonConvert.SerializeObject(new AuditStatus { Status = "unavailable", Message = error }); + + if (!File.Exists(StatusFile)) + return "{\"status\":\"idle\"}"; + + // WriteStatus truncates then rewrites, and its writer is usually another thread (the pump, + // or Project Auditor's background thread) while this read serves an HTTP worker. A read + // landing mid-write either throws (sharing violation) or returns truncated JSON, so retry, + // then fall back to the last status we wrote - the file will match it once the write lands. + for (var attempt = 0; attempt < 3; attempt++) + { + if (attempt > 0) + Thread.Sleep(20); + + try + { + var json = File.ReadAllText(StatusFile); + // WriteStatus writes serialized JSON with nothing after it, so a closing '}' means + // this read caught a whole object rather than a half-written one. + if (json.Length > 1 && json[json.Length - 1] == '}') + return json; + } + catch (IOException) + { + // Mid-write collision; retry. + } + } + + return s_LastStatusJson ?? File.ReadAllText(StatusFile); + } + + /// + /// Main-thread pump: picks up a queued request and runs the audit. Building AnalysisParams and + /// calling AuditAsync must happen on the main thread; AuditAsync then blocks here through + /// compilation and returns once the remaining analysis is handed to its background thread. + /// + static void OnUpdate() + { + object categories; + lock (s_Lock) + { + if (!s_Pending || s_Scanning) + return; + s_Pending = false; + s_Scanning = true; + categories = s_PendingCategories; + } + + try + { + if (!RunAudit(categories)) + { + // RunAudit wrote the terminal status and OnDone will not run: release the guard here. + lock (s_Lock) { s_Scanning = false; } + } + } + catch (Exception ex) + { + // Only up-front and synchronous failures reach here; once AuditAsync has handed off to + // its background thread, OnDone owns both the outcome and s_Scanning. + WriteStatus(new AuditStatus { Status = "failed", ScanId = s_ScanId, Error = ex.Message }); + lock (s_Lock) { s_Scanning = false; } + } + } + + /// + /// Starts the scan. Returns false when no scan was started, in which case the terminal status + /// has already been written and no completion callback will fire. + /// + static bool RunAudit(object categories) + { + if (!TryResolve(out var pa, out var error)) + throw new InvalidOperationException(error); + + // Constructing ProjectAuditor is what initializes its modules, so this is the earliest + // point at which the "has usable rules" precondition can be checked. + var auditor = Activator.CreateInstance(pa.ProjectAuditorType); + if (HasNoModules(pa, auditor)) + { + WriteStatus(new AuditStatus + { + Status = "unavailable", + ScanId = s_ScanId, + Message = "Project Auditor registered no analysis modules, so it cannot analyze this " + + $"project. Install the Project Auditor Rules package ({RulesPackageName})." + }); + return false; + } + + var analysisParams = Activator.CreateInstance(pa.AnalysisParamsType, new object[] { true }); + if (categories != null) + pa.CategoriesField.SetValue(analysisParams, categories); + + // Wire OnCompleted, which is an Action. OnDone takes 'object'; relaxed delegate + // binding permits it because Report derives from object (reference-type contravariance). + var actionType = typeof(Action<>).MakeGenericType(pa.ReportType); + var onDone = Delegate.CreateDelegate(actionType, typeof(ProjectAuditCommands) + .GetMethod(nameof(OnDone), BindingFlags.NonPublic | BindingFlags.Static)); + pa.OnCompletedField.SetValue(analysisParams, onDone); + + // AuditAsync(AnalysisParams, IProgress); a null progress means no progress and no cancel hook. + pa.AuditAsyncMethod.Invoke(auditor, new[] { analysisParams, null }); + return true; + } + + /// No registered modules means the rules package is missing: a scan would complete + /// instantly with an empty report. False when the reflected accessor is absent. + static bool HasNoModules(ResolvedProjectAuditor pa, object auditor) + { + if (pa.GetModulesMethod == null) + return false; + return pa.GetModulesMethod.Invoke(auditor, null) is ICollection modules && modules.Count == 0; + } + + /// + /// Completion callback bound to AnalysisParams.OnCompleted. Fires on Project Auditor's + /// background analysis thread (or synchronously inside AuditAsync when Code analysis is not in + /// scope). Only does thread-safe work: reads the report and writes the CSV + status files. + /// + static void OnDone(object report) + { + try + { + if (!TryResolve(out var pa, out var error)) + throw new InvalidOperationException(error); + + var rows = CollectRows(pa, report); + WriteCsv(s_CsvPath, rows); + WriteStatus(new AuditStatus + { + Status = "completed", + ScanId = s_ScanId, + CsvPath = s_CsvPath, + IssueCount = rows.Count + }); + } + catch (Exception ex) + { + WriteStatus(new AuditStatus { Status = "failed", ScanId = s_ScanId, Error = ex.Message }); + } + finally + { + lock (s_Lock) { s_Scanning = false; } + } + } + + /// + /// Enumerate the report's issues (ReportItems whose descriptor is valid — i.e. diagnostics, not + /// raw-inventory insights) and project each to a CSV row. Reflection only; safe off-thread. + /// + static List CollectRows(ResolvedProjectAuditor pa, object report) + { + var rows = new List(); + var all = pa.GetAllIssuesMethod.Invoke(report, null) as IEnumerable; + if (all == null) + return rows; + + foreach (var item in all) + { + if (item == null || !(bool)pa.IsIssueMethod.Invoke(item, null)) + continue; + + var descriptor = pa.GetDescriptorMethod.Invoke(pa.IdProperty.GetValue(item), null); + var line = (int)pa.LineProperty.GetValue(item); + + rows.Add(new[] + { + pa.CategoryProperty.GetValue(item)?.ToString() ?? string.Empty, + pa.SeverityProperty.GetValue(item)?.ToString() ?? string.Empty, + pa.AreasField.GetValue(descriptor)?.ToString() ?? string.Empty, + pa.DescriptionProperty.GetValue(item) as string ?? string.Empty, + pa.RelativePathProperty.GetValue(item) as string ?? string.Empty, + line > 0 ? line.ToString() : string.Empty, + pa.IdField.GetValue(descriptor) as string ?? string.Empty, + pa.RecommendationField.GetValue(descriptor) as string ?? string.Empty, + }); + } + + return rows; + } + + static readonly string[] k_CsvHeader = + { + "Category", "Severity", "Areas", "Description", "RelativePath", "Line", "DescriptorId", "Recommendation" + }; + + static void WriteCsv(string path, List rows) + { + var dir = Path.GetDirectoryName(path); + if (!string.IsNullOrEmpty(dir)) + Directory.CreateDirectory(dir); + + var sb = new StringBuilder(); + AppendCsvRow(sb, k_CsvHeader); + foreach (var row in rows) + AppendCsvRow(sb, row); + + File.WriteAllText(path, sb.ToString()); + } + + static void AppendCsvRow(StringBuilder sb, string[] fields) + { + for (var i = 0; i < fields.Length; i++) + { + if (i > 0) + sb.Append(','); + sb.Append(EscapeCsv(fields[i])); + } + sb.Append("\r\n"); + } + + /// RFC 4180 escaping: quote a field containing a comma, quote or newline; double any embedded quotes. + internal static string EscapeCsv(string field) + { + field = field ?? string.Empty; + if (field.IndexOfAny(new[] { ',', '"', '\n', '\r' }) < 0) + return field; + return "\"" + field.Replace("\"", "\"\"") + "\""; + } + + /// + /// Returns null when every requested category name is valid, otherwise an error message listing + /// the unknown names and the valid values. Pure (valid names injected) so it needs no Project + /// Auditor types to test. + /// + internal static string ValidateCategories(IReadOnlyList requested, IReadOnlyCollection validNames) + { + if (requested == null || requested.Count == 0) + return null; + + var unknown = requested + .Where(r => !validNames.Any(v => string.Equals(v, r, StringComparison.OrdinalIgnoreCase))) + .ToList(); + if (unknown.Count == 0) + return null; + + return $"Unknown categor{(unknown.Count == 1 ? "y" : "ies")}: {string.Join(", ", unknown)}. " + + $"Valid categories: {string.Join(", ", validNames)}."; + } + + static List ParseCategoryNames(string categories) + { + if (string.IsNullOrWhiteSpace(categories)) + return new List(); + return categories.Split(',') + .Select(c => c.Trim()) + .Where(c => c.Length > 0) + .ToList(); + } + + /// Build the array for AnalysisParams.Categories, or null when no filter was requested (= all). + static object BuildCategoriesArray(ResolvedProjectAuditor pa, IReadOnlyList requested) + { + if (requested.Count == 0) + return null; + return BuildCategoryArray(pa.CategoryElementType, pa.CategoryWrapperCtor, pa.IssueCategoryType, requested); + } + + /// + /// Build the typed category array. The element type is a deployment detail — the standalone + /// package stores the bare enum, the built-in module a serialization wrapper — so it and its + /// wrapping constructor are passed in, which also makes this testable without Project Auditor. + /// + internal static Array BuildCategoryArray(Type elementType, ConstructorInfo wrapperCtor, Type enumType, + IReadOnlyList requested) + { + var array = Array.CreateInstance(elementType, requested.Count); + for (var i = 0; i < requested.Count; i++) + { + var category = Enum.Parse(enumType, requested[i], ignoreCase: true); + array.SetValue(wrapperCtor == null ? category : wrapperCtor.Invoke(new[] { category }), i); + } + return array; + } + + static string ResolveCsvPath(string output, string scanId) + { + var projectRoot = Path.GetDirectoryName(Application.dataPath); + if (!string.IsNullOrWhiteSpace(output)) + return Path.IsPathRooted(output) ? output : Path.GetFullPath(Path.Combine(projectRoot, output)); + return Path.Combine(projectRoot, CsvDirectory, scanId + ".csv"); + } + + static void ReconcileAfterReload() + { + if (!File.Exists(StatusFile)) + return; + + AuditStatus prior; + try + { + prior = JsonConvert.DeserializeObject(File.ReadAllText(StatusFile)); + } + catch + { + return; + } + + if (prior != null && prior.Status == "scanning") + WriteStatus(new AuditStatus { Status = "interrupted", ScanId = prior.ScanId }); + } + + static void WriteStatus(AuditStatus status) + { + var json = JsonConvert.SerializeObject(status); + try + { + File.WriteAllText(StatusFile, json); + // Cached only after a successful write, so the audit_status fallback can never report a + // status the file does not hold. + s_LastStatusJson = json; + } + catch (Exception ex) + { + Debug.LogError($"[ProjectAudit] Failed to write status file: {ex.Message}"); + } + } + + #region reflection resolution + + static readonly object s_ResolveLock = new object(); + static ResolvedProjectAuditor s_Resolved; + + /// + /// Resolve the Project Auditor types/members once (thread-safe: audit_status runs off the main + /// thread). Returns false with a clear message when Project Auditor is not installed or an + /// expected member is missing (e.g. an incompatible version). + /// + static bool TryResolve(out ResolvedProjectAuditor pa, out string error) + { + lock (s_ResolveLock) + { + if (s_Resolved != null) + { + pa = s_Resolved; + error = null; + return true; + } + + pa = null; + error = null; + + var auditorType = FindLoadedType(AuditorTypeName); + if (auditorType == null) + { + error = $"Project Auditor is not installed in this Editor ({AuditorTypeName} not found)."; + return false; + } + + var asm = auditorType.Assembly; + try + { + var resolved = new ResolvedProjectAuditor(auditorType, asm); + s_Resolved = resolved; + pa = resolved; + return true; + } + catch (Exception ex) + { + error = $"Project Auditor is present but its API could not be resolved (version mismatch?): {ex.Message}"; + return false; + } + } + } + + /// + /// Find a type by full name in any loaded assembly. The assembly name cannot be used to narrow + /// the search: the same type ships in Unity.ProjectAuditor.Editor as a package but in + /// UnityEditor.ProjectAuditorModule as a built-in editor module (measured on 6000.7), so + /// an assembly-qualified finds only the package deployment. + /// + static Type FindLoadedType(string fullName) + { + foreach (var asm in PipelineUtils.GetLoadedAssemblies()) + { + var type = asm.GetType(fullName, throwOnError: false); + if (type != null) + return type; + } + + return null; + } + + #endregion + } + + /// + /// Cached Project Auditor reflection handles. The constructor throws if any expected member is + /// missing, so can report a clean "unavailable" rather than + /// failing mid-scan. All members come from the one assembly that declares ProjectAuditor. + /// + sealed class ResolvedProjectAuditor + { + public readonly Type ProjectAuditorType; + public readonly Type AnalysisParamsType; + public readonly Type ReportType; + public readonly Type IssueCategoryType; + + public readonly MethodInfo AuditAsyncMethod; + public readonly FieldInfo CategoriesField; + // Element type of AnalysisParams.Categories: the bare IssueCategory in the standalone Project + // Auditor package, a SerializableEnum wrapper in the built-in editor module. + public readonly Type CategoryElementType; + // Constructor wrapping an IssueCategory into that element type; null when it is the bare enum. + public readonly ConstructorInfo CategoryWrapperCtor; + // Optional (internal API): when absent, the registered-modules precondition check is skipped. + public readonly MethodInfo GetModulesMethod; + public readonly FieldInfo OnCompletedField; + + public readonly MethodInfo GetAllIssuesMethod; + public readonly MethodInfo IsIssueMethod; + public readonly PropertyInfo CategoryProperty; + public readonly PropertyInfo SeverityProperty; + public readonly PropertyInfo DescriptionProperty; + public readonly PropertyInfo RelativePathProperty; + public readonly PropertyInfo LineProperty; + public readonly PropertyInfo IdProperty; + + public readonly MethodInfo GetDescriptorMethod; + public readonly FieldInfo IdField; + public readonly FieldInfo AreasField; + public readonly FieldInfo RecommendationField; + + public ResolvedProjectAuditor(Type auditorType, Assembly asm) + { + ProjectAuditorType = auditorType; + AnalysisParamsType = Require(asm, "Unity.ProjectAuditor.Editor.AnalysisParams"); + ReportType = Require(asm, "Unity.ProjectAuditor.Editor.Report"); + IssueCategoryType = Require(asm, "Unity.ProjectAuditor.Editor.IssueCategory"); + var reportItemType = Require(asm, "Unity.ProjectAuditor.Editor.ReportItem"); + var descriptorType = Require(asm, "Unity.ProjectAuditor.Editor.Descriptor"); + + AuditAsyncMethod = Require(ProjectAuditorType.GetMethods() + .FirstOrDefault(m => m.Name == "AuditAsync" && m.GetParameters().Length == 2), "ProjectAuditor.AuditAsync"); + CategoriesField = Require(AnalysisParamsType.GetField("Categories"), "AnalysisParams.Categories"); + CategoryElementType = Require(CategoriesField.FieldType.GetElementType(), "AnalysisParams.Categories element type"); + CategoryWrapperCtor = CategoryElementType == IssueCategoryType + ? null + : Require(CategoryElementType.GetConstructor(new[] { IssueCategoryType }), + $"{CategoryElementType.Name}(IssueCategory) constructor"); + GetModulesMethod = ProjectAuditorType.GetMethod("GetModules", + BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Type.EmptyTypes, null); + OnCompletedField = Require(AnalysisParamsType.GetField("OnCompleted"), "AnalysisParams.OnCompleted"); + + GetAllIssuesMethod = Require(ReportType.GetMethod("GetAllIssues", Type.EmptyTypes), "Report.GetAllIssues"); + IsIssueMethod = Require(reportItemType.GetMethod("IsIssue", Type.EmptyTypes), "ReportItem.IsIssue"); + CategoryProperty = Require(reportItemType.GetProperty("Category"), "ReportItem.Category"); + SeverityProperty = Require(reportItemType.GetProperty("Severity"), "ReportItem.Severity"); + DescriptionProperty = Require(reportItemType.GetProperty("Description"), "ReportItem.Description"); + RelativePathProperty = Require(reportItemType.GetProperty("RelativePath"), "ReportItem.RelativePath"); + LineProperty = Require(reportItemType.GetProperty("Line"), "ReportItem.Line"); + IdProperty = Require(reportItemType.GetProperty("Id"), "ReportItem.Id"); + + GetDescriptorMethod = Require(IdProperty.PropertyType.GetMethod("GetDescriptor", Type.EmptyTypes), "DescriptorId.GetDescriptor"); + IdField = Require(descriptorType.GetField("Id"), "Descriptor.Id"); + AreasField = Require(descriptorType.GetField("Areas"), "Descriptor.Areas"); + RecommendationField = Require(descriptorType.GetField("Recommendation"), "Descriptor.Recommendation"); + } + + static Type Require(Assembly asm, string fullName) + { + return Require(asm.GetType(fullName, throwOnError: false), fullName); + } + + static T Require(T member, string name) where T : class + { + if (member == null) + throw new MissingMemberException($"Project Auditor member not found: {name}"); + return member; + } + } + + /// Status/result payload for the audit / audit_status commands. + [Serializable] + class AuditStatus + { + [JsonProperty("status")] + public string Status { get; set; } + + [JsonProperty("scanId", NullValueHandling = NullValueHandling.Ignore)] + public string ScanId { get; set; } + + [JsonProperty("csvPath", NullValueHandling = NullValueHandling.Ignore)] + public string CsvPath { get; set; } + + [JsonProperty("issueCount", NullValueHandling = NullValueHandling.Ignore)] + public int? IssueCount { get; set; } + + [JsonProperty("error", NullValueHandling = NullValueHandling.Ignore)] + public string Error { get; set; } + + [JsonProperty("message", NullValueHandling = NullValueHandling.Ignore)] + public string Message { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectAudit/ProjectAuditCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectAudit/ProjectAuditCommands.cs.meta new file mode 100644 index 0000000..213f94c --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectAudit/ProjectAuditCommands.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 16350a6f8b1204eeea6649d939abc4b8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings.meta new file mode 100644 index 0000000..6a5e044 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8fe6d0edfccd2e8429890cf65cb7417c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/AudioSettingsCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/AudioSettingsCommands.cs new file mode 100644 index 0000000..c0b0177 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/AudioSettingsCommands.cs @@ -0,0 +1,116 @@ +using System.Collections.Generic; +using Unity.Pipeline.Commands; +using UnityEditor; +using UnityEngine; + +namespace Unity.Pipeline.Editor.Commands.ProjectSettings +{ + /// + /// Get/set the project Audio settings (CLI-202). The AudioManager has no scripting API, so this + /// reads/writes its serialized properties (global volume, rolloff scale, doppler factor) via + /// . Properties absent in a given Unity version are skipped. + /// + static class AudioSettingsCommands + { + const string Group = "audio"; + const string AssetPath = "ProjectSettings/AudioManager.asset"; + + // Serialized property name -> response/plan label. + const string VolumeProp = "m_Volume"; + const string RolloffProp = "Rolloff Scale"; + const string DopplerProp = "Doppler Factor"; + + [CliCommand("get_audio_settings", "Read project Audio settings (volume, rolloff scale, doppler factor).", MainThreadRequired = true, Tags = new[] { "settings/audio" })] + public static ProjectSettingsResponse Get() => ProjectSettingsCommand.Get(Group, Read); + + [CliCommand("set_audio_settings", "Change project Audio settings. Requires confirm=true; use dry_run to preview. Not undoable via Ctrl+Z.", MainThreadRequired = true, Tags = new[] { "settings/audio" })] + public static ProjectSettingsResponse Set( + [CliArg("settings", "Fields to change; omitted fields are left unchanged.")] AudioSettingsInput settings = null, + [CliArg("confirm", "Apply the change. Without it the call is refused.")] bool confirm = false, + [CliArg("dry_run", "Preview the change without applying it.")] bool dryRun = false) + { + if (settings == null) + return ProjectSettingsResponse.Fail(Group, "No 'settings' object provided."); + + var so = ProjectSettingsAsset.Load(AssetPath); + var changes = new List(); + AddFloatChange(so, VolumeProp, "volume", settings.Volume, changes); + AddFloatChange(so, RolloffProp, "rolloffScale", settings.RolloffScale, changes); + AddFloatChange(so, DopplerProp, "dopplerFactor", settings.DopplerFactor, changes); + + if (changes.Count == 0) + return NoChanges(); + + var planText = "Set audio settings: " + string.Join("; ", changes); + + void Apply() + { + var obj = ProjectSettingsAsset.Load(AssetPath); + SetFloat(obj, VolumeProp, settings.Volume); + SetFloat(obj, RolloffProp, settings.RolloffScale); + SetFloat(obj, DopplerProp, settings.DopplerFactor); + obj.ApplyModifiedProperties(); + AssetDatabase.SaveAssets(); + } + + return ProjectSettingsCommand.Apply(Group, confirm, dryRun, settings, () => planText, Apply, Read); + } + + static ProjectSettingsResponse NoChanges() + { + var response = ProjectSettingsCommand.Get(Group, Read); + response.Message = "No changes specified; nothing to apply."; + return response; + } + + static Dictionary Read() + { + var so = ProjectSettingsAsset.Load(AssetPath); + var values = new Dictionary(); + AddFloat(so, VolumeProp, "volume", values); + AddFloat(so, RolloffProp, "rolloffScale", values); + AddFloat(so, DopplerProp, "dopplerFactor", values); + return values; + } + + static void AddFloat(SerializedObject so, string prop, string label, Dictionary values) + { + var p = so.FindProperty(prop); + if (p != null) + values[label] = p.floatValue; + } + + static void AddFloatChange(SerializedObject so, string prop, string label, float? newValue, List changes) + { + if (!newValue.HasValue) + return; + var p = so.FindProperty(prop); + if (p == null) + return; // not present in this Unity version + if (!Mathf.Approximately(p.floatValue, newValue.Value)) + changes.Add($"{label} {p.floatValue} -> {newValue.Value}"); + } + + static void SetFloat(SerializedObject so, string prop, float? value) + { + if (!value.HasValue) + return; + var p = so.FindProperty(prop); + if (p != null) + p.floatValue = value.Value; + } + } + + /// Audio settings to change. Null/omitted fields are left unchanged. + class AudioSettingsInput : IStructuredCommandInput + { + [CliArg("volume", "Global audio volume (0..1).")] + public float? Volume { get; set; } + + [CliArg("rolloffScale", "Global rolloff scale.")] + public float? RolloffScale { get; set; } + + [CliArg("dopplerFactor", "Global doppler factor.")] + public float? DopplerFactor { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/AudioSettingsCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/AudioSettingsCommands.cs.meta new file mode 100644 index 0000000..ebc8107 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/AudioSettingsCommands.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1a7abd0c1722ba34dae96408746d2c9a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/GraphicsSettingsCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/GraphicsSettingsCommands.cs new file mode 100644 index 0000000..0828dee --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/GraphicsSettingsCommands.cs @@ -0,0 +1,87 @@ +using System.Collections.Generic; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Models; +using UnityEditor; +using UnityEngine.Rendering; + +namespace Unity.Pipeline.Editor.Commands.ProjectSettings +{ + /// + /// Get/set the project's default render pipeline (CLI-202). The settable field is a handle to a + /// ; an empty reference selects the built-in pipeline (no SRP). + /// + static class GraphicsSettingsCommands + { + const string Group = "graphics"; + + [CliCommand("get_graphics_settings", "Read GraphicsSettings (default render pipeline).", MainThreadRequired = true, Tags = new[] { "settings/graphics" })] + public static ProjectSettingsResponse Get() => ProjectSettingsCommand.Get(Group, Read); + + [CliCommand("set_graphics_settings", "Set the default render pipeline asset. Requires confirm=true; use dry_run to preview. Not undoable via Ctrl+Z.", MainThreadRequired = true, Tags = new[] { "settings/graphics" })] + public static ProjectSettingsResponse Set( + [CliArg("settings", "Fields to change; omitted fields are left unchanged.")] GraphicsSettingsInput settings = null, + [CliArg("confirm", "Apply the change. Without it the call is refused.")] bool confirm = false, + [CliArg("dry_run", "Preview the change without applying it.")] bool dryRun = false) + { + if (settings == null) + return ProjectSettingsResponse.Fail(Group, "No 'settings' object provided."); + + // omitted (null) = leave unchanged; an empty reference = built-in pipeline; otherwise a + // handle to a RenderPipelineAsset resolved through the shared ObjectResolver. + if (settings.RenderPipelineAsset == null) + return NoChanges(); + + RenderPipelineAsset asset = null; + if (!settings.RenderPipelineAsset.IsEmpty) + { + if (!ObjectResolver.TryResolve(settings.RenderPipelineAsset, out var obj, out var resolveError)) + return ProjectSettingsResponse.Fail(Group, resolveError); + asset = obj as RenderPipelineAsset; + if (asset == null) + return ProjectSettingsResponse.Fail(Group, $"'{settings.RenderPipelineAsset}' is not a RenderPipelineAsset."); + } + + var current = GraphicsSettings.defaultRenderPipeline; + if (current == asset) + return NoChanges(); + + var currentName = current != null ? current.name : ""; + var newName = asset != null ? asset.name : ""; + var planText = $"Set defaultRenderPipeline {currentName} -> {newName}"; + + void Apply() + { + GraphicsSettings.defaultRenderPipeline = asset; + AssetDatabase.SaveAssets(); + } + + return ProjectSettingsCommand.Apply(Group, confirm, dryRun, settings, () => planText, Apply, Read); + } + + static ProjectSettingsResponse NoChanges() + { + var response = ProjectSettingsCommand.Get(Group, Read); + response.Message = "No changes specified; nothing to apply."; + return response; + } + + static Dictionary Read() + { + var srp = GraphicsSettings.defaultRenderPipeline; + return new Dictionary + { + ["defaultRenderPipeline"] = srp != null ? srp.name : null, + ["defaultRenderPipelinePath"] = srp != null ? AssetDatabase.GetAssetPath(srp) : null, + ["usingScriptableRenderPipeline"] = srp != null + }; + } + } + + /// Graphics settings to change. Null/omitted fields are left unchanged. + class GraphicsSettingsInput : IStructuredCommandInput + { + [CliArg("renderPipelineAsset", "Reference (path / guid / globalId) to a RenderPipelineAsset to set as the default. Pass an empty reference ({}) to select the built-in pipeline; omit to leave unchanged.")] + public ObjectRef RenderPipelineAsset { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/GraphicsSettingsCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/GraphicsSettingsCommands.cs.meta new file mode 100644 index 0000000..f14c08d --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/GraphicsSettingsCommands.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5095c024b3a03e94996b73e4e42c4e4c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/InputSettingsCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/InputSettingsCommands.cs new file mode 100644 index 0000000..56d2209 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/InputSettingsCommands.cs @@ -0,0 +1,150 @@ +using System.Collections.Generic; +using Unity.Pipeline.Commands; +using UnityEditor; +using UnityEngine; + +namespace Unity.Pipeline.Editor.Commands.ProjectSettings +{ + /// + /// Get/set the legacy Input Manager (CLI-202). The InputManager has no scripting API, so this + /// reads/writes ProjectSettings/InputManager.asset via serialized properties: + /// get lists the configured axis names; set tunes a named axis's + /// sensitivity/gravity/dead values. + /// + /// "Input (legacy / Input System where feasible)" per the ticket: the legacy InputManager is + /// always present, so it is the portable target. Projects on the new Input System package store + /// their config in a separate input-actions asset, which would be a follow-up. + /// + static class InputSettingsCommands + { + const string Group = "input"; + const string AssetPath = "ProjectSettings/InputManager.asset"; + + [CliCommand("get_input_settings", "Read the legacy Input Manager axes (names and count).", MainThreadRequired = true, Tags = new[] { "settings/input" })] + public static ProjectSettingsResponse Get() => ProjectSettingsCommand.Get(Group, Read); + + [CliCommand("set_input_settings", "Tune a legacy Input Manager axis (sensitivity/gravity/dead) by name. Requires confirm=true; use dry_run to preview. Not undoable via Ctrl+Z.", MainThreadRequired = true, Tags = new[] { "settings/input" })] + public static ProjectSettingsResponse Set( + [CliArg("settings", "Axis change. 'axis' selects the axis by name; omitted numeric fields are left unchanged.")] InputAxisInput settings = null, + [CliArg("confirm", "Apply the change. Without it the call is refused.")] bool confirm = false, + [CliArg("dry_run", "Preview the change without applying it.")] bool dryRun = false) + { + if (settings == null) + return ProjectSettingsResponse.Fail(Group, "No 'settings' object provided."); + if (string.IsNullOrEmpty(settings.Axis)) + return ProjectSettingsResponse.Fail(Group, "'axis' is required."); + + var so = ProjectSettingsAsset.Load(AssetPath); + var axes = so.FindProperty("m_Axes"); + var index = FindAxisIndex(axes, settings.Axis); + if (index < 0) + return ProjectSettingsResponse.Fail(Group, $"No axis named '{settings.Axis}'."); + + var axis = axes.GetArrayElementAtIndex(index); + var changes = new List(); + AddFloatChange(axis, "sensitivity", settings.Sensitivity, changes); + AddFloatChange(axis, "gravity", settings.Gravity, changes); + AddFloatChange(axis, "dead", settings.Dead, changes); + + if (changes.Count == 0) + return NoChanges(); + + var planText = $"Set input axis '{settings.Axis}': " + string.Join("; ", changes); + + void Apply() + { + var obj = ProjectSettingsAsset.Load(AssetPath); + var arr = obj.FindProperty("m_Axes"); + var idx = FindAxisIndex(arr, settings.Axis); + if (idx < 0) + return; + + var ax = arr.GetArrayElementAtIndex(idx); + SetFloat(ax, "sensitivity", settings.Sensitivity); + SetFloat(ax, "gravity", settings.Gravity); + SetFloat(ax, "dead", settings.Dead); + obj.ApplyModifiedProperties(); + AssetDatabase.SaveAssets(); + } + + return ProjectSettingsCommand.Apply(Group, confirm, dryRun, settings, () => planText, Apply, Read); + } + + static ProjectSettingsResponse NoChanges() + { + var response = ProjectSettingsCommand.Get(Group, Read); + response.Message = "No changes specified; nothing to apply."; + return response; + } + + static int FindAxisIndex(SerializedProperty axes, string name) + { + if (axes == null) + return -1; + for (var i = 0; i < axes.arraySize; i++) + { + var nameProp = axes.GetArrayElementAtIndex(i).FindPropertyRelative("m_Name"); + if (nameProp != null && nameProp.stringValue == name) + return i; + } + return -1; + } + + static void AddFloatChange(SerializedProperty axis, string prop, float? newValue, List changes) + { + if (!newValue.HasValue) + return; + var p = axis.FindPropertyRelative(prop); + if (p == null) + return; + if (!Mathf.Approximately(p.floatValue, newValue.Value)) + changes.Add($"{prop} {p.floatValue} -> {newValue.Value}"); + } + + static void SetFloat(SerializedProperty axis, string prop, float? value) + { + if (!value.HasValue) + return; + var p = axis.FindPropertyRelative(prop); + if (p != null) + p.floatValue = value.Value; + } + + static Dictionary Read() + { + var so = ProjectSettingsAsset.Load(AssetPath); + var axes = so.FindProperty("m_Axes"); + var names = new List(); + if (axes != null) + { + for (var i = 0; i < axes.arraySize; i++) + { + var nameProp = axes.GetArrayElementAtIndex(i).FindPropertyRelative("m_Name"); + names.Add(nameProp != null ? nameProp.stringValue : null); + } + } + + return new Dictionary + { + ["axisCount"] = names.Count, + ["axes"] = names + }; + } + } + + /// Selects a legacy input axis by name and the numeric fields to change (omitted = unchanged). + class InputAxisInput : IStructuredCommandInput + { + [CliArg("axis", "Name of the axis to modify (e.g. 'Horizontal').", Required = true)] + public string Axis { get; set; } + + [CliArg("sensitivity", "New sensitivity.")] + public float? Sensitivity { get; set; } + + [CliArg("gravity", "New gravity.")] + public float? Gravity { get; set; } + + [CliArg("dead", "New dead-zone size.")] + public float? Dead { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/InputSettingsCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/InputSettingsCommands.cs.meta new file mode 100644 index 0000000..582c4a0 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/InputSettingsCommands.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 27a9903daaf869948aa6dd45e9735f6f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/PhysicsSettingsCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/PhysicsSettingsCommands.cs new file mode 100644 index 0000000..b0a89c1 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/PhysicsSettingsCommands.cs @@ -0,0 +1,98 @@ +using System.Collections.Generic; +using Unity.Pipeline.Commands; +using UnityEditor; +using UnityEngine; + +namespace Unity.Pipeline.Editor.Commands.ProjectSettings +{ + /// + /// Get/set a representative slice of 3D settings (CLI-202): gravity (by + /// component), default solver iterations, and the bounce threshold. + /// + static class PhysicsSettingsCommands + { + const string Group = "physics"; + + [CliCommand("get_physics_settings", "Read Physics settings (gravity, solver iterations, bounce threshold).", MainThreadRequired = true, Tags = new[] { "settings/physics" })] + public static ProjectSettingsResponse Get() => ProjectSettingsCommand.Get(Group, Read); + + [CliCommand("set_physics_settings", "Change Physics settings. Requires confirm=true; use dry_run to preview. Not undoable via Ctrl+Z.", MainThreadRequired = true, Tags = new[] { "settings/physics" })] + public static ProjectSettingsResponse Set( + [CliArg("settings", "Fields to change; omitted fields are left unchanged.")] PhysicsSettingsInput settings = null, + [CliArg("confirm", "Apply the change. Without it the call is refused.")] bool confirm = false, + [CliArg("dry_run", "Preview the change without applying it.")] bool dryRun = false) + { + if (settings == null) + return ProjectSettingsResponse.Fail(Group, "No 'settings' object provided."); + + var changes = new List(); + + var gravity = Physics.gravity; + var newGravity = gravity; + if (settings.GravityX.HasValue) newGravity.x = settings.GravityX.Value; + if (settings.GravityY.HasValue) newGravity.y = settings.GravityY.Value; + if (settings.GravityZ.HasValue) newGravity.z = settings.GravityZ.Value; + if (newGravity != gravity) + changes.Add($"gravity {gravity} -> {newGravity}"); + + if (settings.DefaultSolverIterations.HasValue && settings.DefaultSolverIterations.Value != Physics.defaultSolverIterations) + changes.Add($"defaultSolverIterations {Physics.defaultSolverIterations} -> {settings.DefaultSolverIterations.Value}"); + if (settings.BounceThreshold.HasValue && !Mathf.Approximately(settings.BounceThreshold.Value, Physics.bounceThreshold)) + changes.Add($"bounceThreshold {Physics.bounceThreshold} -> {settings.BounceThreshold.Value}"); + + if (changes.Count == 0) + return NoChanges(); + + var planText = "Set physics settings: " + string.Join("; ", changes); + + void Apply() + { + Physics.gravity = newGravity; + if (settings.DefaultSolverIterations.HasValue) Physics.defaultSolverIterations = settings.DefaultSolverIterations.Value; + if (settings.BounceThreshold.HasValue) Physics.bounceThreshold = settings.BounceThreshold.Value; + AssetDatabase.SaveAssets(); + } + + return ProjectSettingsCommand.Apply(Group, confirm, dryRun, settings, () => planText, Apply, Read); + } + + static ProjectSettingsResponse NoChanges() + { + var response = ProjectSettingsCommand.Get(Group, Read); + response.Message = "No changes specified; nothing to apply."; + return response; + } + + static Dictionary Read() + { + var g = Physics.gravity; + return new Dictionary + { + ["gravityX"] = g.x, + ["gravityY"] = g.y, + ["gravityZ"] = g.z, + ["defaultSolverIterations"] = Physics.defaultSolverIterations, + ["bounceThreshold"] = Physics.bounceThreshold + }; + } + } + + /// Physics settings to change. Null/omitted fields are left unchanged. + class PhysicsSettingsInput : IStructuredCommandInput + { + [CliArg("gravityX", "Gravity X component.")] + public float? GravityX { get; set; } + + [CliArg("gravityY", "Gravity Y component (e.g. -9.81).")] + public float? GravityY { get; set; } + + [CliArg("gravityZ", "Gravity Z component.")] + public float? GravityZ { get; set; } + + [CliArg("defaultSolverIterations", "Default solver iteration count.")] + public int? DefaultSolverIterations { get; set; } + + [CliArg("bounceThreshold", "Bounce threshold velocity.")] + public float? BounceThreshold { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/PhysicsSettingsCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/PhysicsSettingsCommands.cs.meta new file mode 100644 index 0000000..6ce0c1b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/PhysicsSettingsCommands.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 06de808693ce8c24891baa1026490d3d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/PlayerSettingsCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/PlayerSettingsCommands.cs new file mode 100644 index 0000000..efb0191 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/PlayerSettingsCommands.cs @@ -0,0 +1,122 @@ +using System.Collections.Generic; +using Unity.Pipeline.Commands; +using UnityEditor; +using UnityEditor.Build; + +namespace Unity.Pipeline.Editor.Commands.ProjectSettings +{ + /// + /// Get/set a representative slice of (CLI-202): identity + /// (company/product/version) and the two domain-reload-triggering toggles — scripting backend and + /// API compatibility level. Scripting-backend / API-level changes are read and written against the + /// active build target's . + /// + /// Icons and splash are intentionally out of this MVP set: they take Texture2D assets, not + /// scalar JSON, so they need a dedicated asset-reference convention. + /// + static class PlayerSettingsCommands + { + const string Group = "player"; + + [CliCommand("get_player_settings", "Read PlayerSettings (company/product/version, scripting backend, API level).", MainThreadRequired = true, Tags = new[] { "settings/player" })] + public static ProjectSettingsResponse Get() => ProjectSettingsCommand.Get(Group, Read); + + [CliCommand("set_player_settings", "Change PlayerSettings. Requires confirm=true; use dry_run to preview. Not undoable via Ctrl+Z. Scripting backend / API level changes trigger a domain reload.", MainThreadRequired = true, Tags = new[] { "settings/player" })] + public static ProjectSettingsResponse Set( + [CliArg("settings", "Fields to change; omitted fields are left unchanged.")] PlayerSettingsInput settings = null, + [CliArg("confirm", "Apply the change. Without it the call is refused.")] bool confirm = false, + [CliArg("dry_run", "Preview the change without applying it.")] bool dryRun = false) + { + if (settings == null) + return ProjectSettingsResponse.Fail(Group, "No 'settings' object provided."); + + var target = NamedBuildTarget.FromBuildTargetGroup(EditorUserBuildSettings.selectedBuildTargetGroup); + var changes = new List(); + var reload = false; + + if (settings.CompanyName != null && settings.CompanyName != PlayerSettings.companyName) + changes.Add($"companyName '{PlayerSettings.companyName}' -> '{settings.CompanyName}'"); + if (settings.ProductName != null && settings.ProductName != PlayerSettings.productName) + changes.Add($"productName '{PlayerSettings.productName}' -> '{settings.ProductName}'"); + if (settings.BundleVersion != null && settings.BundleVersion != PlayerSettings.bundleVersion) + changes.Add($"bundleVersion '{PlayerSettings.bundleVersion}' -> '{settings.BundleVersion}'"); + + if (settings.ScriptingBackend.HasValue) + { + var current = PlayerSettings.GetScriptingBackend(target); + if (settings.ScriptingBackend.Value != current) + { + changes.Add($"scriptingBackend {current} -> {settings.ScriptingBackend.Value} (domain reload)"); + reload = true; + } + } + + if (settings.ApiCompatibilityLevel.HasValue) + { + var current = PlayerSettings.GetApiCompatibilityLevel(target); + if (settings.ApiCompatibilityLevel.Value != current) + { + changes.Add($"apiCompatibilityLevel {current} -> {settings.ApiCompatibilityLevel.Value} (domain reload)"); + reload = true; + } + } + + if (changes.Count == 0) + return NoChanges(); + + var planText = "Set player settings: " + string.Join("; ", changes); + + void Apply() + { + if (settings.CompanyName != null) PlayerSettings.companyName = settings.CompanyName; + if (settings.ProductName != null) PlayerSettings.productName = settings.ProductName; + if (settings.BundleVersion != null) PlayerSettings.bundleVersion = settings.BundleVersion; + if (settings.ScriptingBackend.HasValue) PlayerSettings.SetScriptingBackend(target, settings.ScriptingBackend.Value); + if (settings.ApiCompatibilityLevel.HasValue) PlayerSettings.SetApiCompatibilityLevel(target, settings.ApiCompatibilityLevel.Value); + AssetDatabase.SaveAssets(); + } + + return ProjectSettingsCommand.Apply(Group, confirm, dryRun, settings, () => planText, Apply, Read, requiresDomainReload: reload); + } + + static ProjectSettingsResponse NoChanges() + { + var response = ProjectSettingsCommand.Get(Group, Read); + response.Message = "No changes specified; nothing to apply."; + return response; + } + + static Dictionary Read() + { + var target = NamedBuildTarget.FromBuildTargetGroup(EditorUserBuildSettings.selectedBuildTargetGroup); + return new Dictionary + { + ["companyName"] = PlayerSettings.companyName, + ["productName"] = PlayerSettings.productName, + ["bundleVersion"] = PlayerSettings.bundleVersion, + ["buildTarget"] = target.TargetName, + ["scriptingBackend"] = PlayerSettings.GetScriptingBackend(target).ToString(), + ["apiCompatibilityLevel"] = PlayerSettings.GetApiCompatibilityLevel(target).ToString() + }; + } + } + + /// Player settings to change. Null/omitted fields are left unchanged. + class PlayerSettingsInput : IStructuredCommandInput + { + [CliArg("companyName", "Company name.")] + public string CompanyName { get; set; } + + [CliArg("productName", "Product name.")] + public string ProductName { get; set; } + + [CliArg("bundleVersion", "Bundle/application version string.")] + public string BundleVersion { get; set; } + + [CliArg("scriptingBackend", "Scripting backend (e.g. Mono2x, IL2CPP). Triggers a domain reload.")] + public ScriptingImplementation? ScriptingBackend { get; set; } + + [CliArg("apiCompatibilityLevel", "API compatibility level (e.g. NET_Standard_2_0, NET_Unity_4_8). Triggers a domain reload.")] + public ApiCompatibilityLevel? ApiCompatibilityLevel { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/PlayerSettingsCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/PlayerSettingsCommands.cs.meta new file mode 100644 index 0000000..1ef2ad2 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/PlayerSettingsCommands.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4fcf409834ac0bf4bb18a7b7fadad8dd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/ProjectSettingsAsset.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/ProjectSettingsAsset.cs new file mode 100644 index 0000000..0c8bcb5 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/ProjectSettingsAsset.cs @@ -0,0 +1,23 @@ +using System; +using UnityEditor; + +namespace Unity.Pipeline.Editor.Commands.ProjectSettings +{ + /// + /// Loads a for a singleton settings asset under + /// ProjectSettings/ (e.g. InputManager.asset, TagManager.asset, + /// AudioManager.asset) that has no first-class scripting API. Used by the settings-group + /// commands that must read/write those managers via serialized properties. + /// + internal static class ProjectSettingsAsset + { + public static SerializedObject Load(string assetPath) + { + var objects = AssetDatabase.LoadAllAssetsAtPath(assetPath); + if (objects == null || objects.Length == 0 || objects[0] == null) + throw new InvalidOperationException($"Could not load settings asset at '{assetPath}'."); + + return new SerializedObject(objects[0]); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/ProjectSettingsAsset.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/ProjectSettingsAsset.cs.meta new file mode 100644 index 0000000..5f9d933 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/ProjectSettingsAsset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5646d5f43f10f344ab42eecab65f08c8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/ProjectSettingsCommand.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/ProjectSettingsCommand.cs new file mode 100644 index 0000000..b645793 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/ProjectSettingsCommand.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace Unity.Pipeline.Editor.Commands.ProjectSettings +{ + /// + /// Shared plumbing the per-group project-settings commands (CLI-202) wrap, so each group's + /// get/set handler stays thin and the policy is applied uniformly: + /// + /// — read a group's values into a . + /// — gate a write with the confirm/dry_run convention and + /// apply it (project-settings writes are not part of Unity's Undo), then re-read the group so the response + /// reflects the post-change state, and surface domain-reload / reimport signals. + /// + /// + /// Group handlers supply two callbacks: readValues (snapshot the group's current values) + /// and, for writes, apply (perform the mutation) plus a plan describing the intended + /// effect. All run on the main thread (these commands are MainThreadRequired = true). + /// + static class ProjectSettingsCommand + { + /// + /// Read-only path: build a success response carrying the group's current values. + /// + public static ProjectSettingsResponse Get(string group, Func> readValues) + { + if (readValues == null) + throw new ArgumentNullException(nameof(readValues)); + + if (!TryReadValues(readValues, out var values, out var readError)) + return ProjectSettingsResponse.Fail(group, $"Failed to read {group} settings: {readError}"); + + return new ProjectSettingsResponse + { + Success = true, + Group = group, + Values = values, + Message = $"Read {group} settings." + }; + } + + /// + /// Write path: gate the change with the confirm/dry_run convention and apply it + /// (project-settings writes are not undoable via Ctrl+Z), then re-read the + /// group. / declare + /// side effects of this specific change (Unity defers them, so the response returns first); + /// they are reported for an applied change and for a dry-run preview alike, and suppressed when + /// the operation is refused or fails. + /// + public static ProjectSettingsResponse Apply( + string group, + bool confirm, + bool dryRun, + object auditParams, + Func plan, + Action apply, + Func> readValues, + bool requiresDomainReload = false, + bool requiresReimport = false) + { + if (plan == null) + throw new ArgumentNullException(nameof(plan)); + if (apply == null) + throw new ArgumentNullException(nameof(apply)); + if (readValues == null) + throw new ArgumentNullException(nameof(readValues)); + + string planText; + try + { + planText = plan(); + } + catch (Exception ex) + { + return ProjectSettingsResponse.Fail(group, $"Failed to compute the operation preview: {ex.Message}"); + } + + // Inline confirm / dry_run gate + Undo grouping (the codebase-wide mutating convention). + var response = new ProjectSettingsResponse { Group = group }; + if (dryRun) + { + response.Success = true; + response.DryRun = true; + response.Applied = false; + response.Message = $"Dry run — no changes made. Intended effect: {planText}"; + } + else if (!confirm) + { + response.Success = false; + response.Applied = false; + response.Message = + "Refused: this operation mutates the project. Re-run with confirm=true to apply, " + + "or dry_run=true to preview the change."; + } + else + { + try + { + apply(); + response.Success = true; + response.Applied = true; + response.Message = planText; + } + catch (Exception ex) + { + response.Success = false; + response.Applied = false; + response.Message = $"Operation failed: {ex.Message}"; + } + } + + // Side-effect signals are only meaningful when the operation went through (applied) or was + // previewed (dry run); suppress them for a refusal or failure. + response.RequiresDomainReload = response.Success && requiresDomainReload; + response.RequiresReimport = response.Success && requiresReimport; + + // Re-read so the caller sees the resulting (or, for a dry run / refusal, the unchanged) + // state. A read failure must not mask the write outcome, so it is non-fatal here. + if (TryReadValues(readValues, out var values, out var readError)) + response.Values = values; + else + Debug.LogWarning($"[pipeline] Read-back of {group} settings failed: {readError}"); + + return response; + } + + private static bool TryReadValues(Func> readValues, + out Dictionary values, out string error) + { + try + { + values = readValues() ?? new Dictionary(); + error = null; + return true; + } + catch (Exception ex) + { + values = null; + error = ex.Message; + return false; + } + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/ProjectSettingsCommand.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/ProjectSettingsCommand.cs.meta new file mode 100644 index 0000000..87ad679 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/ProjectSettingsCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 00e8d8eb6857c9d40babc72bb711b9c4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/ProjectSettingsResponse.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/ProjectSettingsResponse.cs new file mode 100644 index 0000000..6131fd9 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/ProjectSettingsResponse.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Unity.Pipeline.Editor.Commands.ProjectSettings +{ + /// + /// + /// Shared response for the project-settings get/set commands (CLI-202). One type backs every + /// settings group (PlayerSettings, Quality, Graphics, Physics, Time, Input, Tags & Layers, + /// Audio) so agents get a uniform shape across them. + /// + /// + /// carries the current settings for the group as a flat + /// name → value map — returned by a get, and re-read after a set so the caller can + /// confirm the change without a second round-trip. + /// + /// Writes follow the shared confirm/dry_run convention, so + /// / mirror its semantics: a change only mutates when + /// it actually ran (not a preview, not refused). and + /// flag side effects an agent must wait out — e.g. switching the + /// scripting backend or API level triggers a domain reload; some graphics/texture changes trigger + /// an asset reimport. They describe the operation, so a dry_run still reports them. + /// + [Serializable] + class ProjectSettingsResponse + { + [JsonProperty("success")] + public bool Success { get; set; } + + /// Settings group this response is for (e.g. "player", "quality", "time"). + [JsonProperty("group")] + public string Group { get; set; } + + /// True only when a write actually mutated the project (false for get/dry-run/refused/failed). + [JsonProperty("applied")] + public bool Applied { get; set; } + + /// True when a write was a preview only (no mutation). + [JsonProperty("dryRun")] + public bool DryRun { get; set; } + + /// The operation triggers a domain reload; the agent should wait for the editor to settle. + [JsonProperty("requiresDomainReload")] + public bool RequiresDomainReload { get; set; } + + /// The operation triggers an asset reimport; the agent should wait for it to finish. + [JsonProperty("requiresReimport")] + public bool RequiresReimport { get; set; } + + /// Current settings for the group as a name → value map. + [JsonProperty("values")] + public Dictionary Values { get; set; } + + [JsonProperty("message")] + public string Message { get; set; } + + public static ProjectSettingsResponse Fail(string group, string message) => new ProjectSettingsResponse + { + Success = false, + Group = group, + Message = message + }; + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/ProjectSettingsResponse.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/ProjectSettingsResponse.cs.meta new file mode 100644 index 0000000..200fa82 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/ProjectSettingsResponse.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8f8c1356c54a05248b34aff8e0490c0c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/QualitySettingsCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/QualitySettingsCommands.cs new file mode 100644 index 0000000..6cbeebc --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/QualitySettingsCommands.cs @@ -0,0 +1,95 @@ +using System.Collections.Generic; +using Unity.Pipeline.Commands; +using UnityEditor; +using UnityEngine; + +namespace Unity.Pipeline.Editor.Commands.ProjectSettings +{ + /// + /// Get/set (CLI-202): the active quality level plus a couple of + /// representative per-level toggles (vSync, anti-aliasing). Level changes apply expensive changes + /// so the switch takes full effect. + /// + static class QualitySettingsCommands + { + const string Group = "quality"; + + [CliCommand("get_quality_settings", "Read QualitySettings (current level, level names, vSync, anti-aliasing).", MainThreadRequired = true, Tags = new[] { "settings/quality" })] + public static ProjectSettingsResponse Get() => ProjectSettingsCommand.Get(Group, Read); + + [CliCommand("set_quality_settings", "Change QualitySettings. Requires confirm=true; use dry_run to preview. Not undoable via Ctrl+Z.", MainThreadRequired = true, Tags = new[] { "settings/quality" })] + public static ProjectSettingsResponse Set( + [CliArg("settings", "Fields to change; omitted fields are left unchanged.")] QualitySettingsInput settings = null, + [CliArg("confirm", "Apply the change. Without it the call is refused.")] bool confirm = false, + [CliArg("dry_run", "Preview the change without applying it.")] bool dryRun = false) + { + if (settings == null) + return ProjectSettingsResponse.Fail(Group, "No 'settings' object provided."); + + var names = QualitySettings.names; + var changes = new List(); + + if (settings.Level.HasValue) + { + if (settings.Level.Value < 0 || settings.Level.Value >= names.Length) + return ProjectSettingsResponse.Fail(Group, $"level {settings.Level.Value} out of range (0..{names.Length - 1})."); + if (settings.Level.Value != QualitySettings.GetQualityLevel()) + changes.Add($"level {QualitySettings.GetQualityLevel()} -> {settings.Level.Value}"); + } + + if (settings.VSyncCount.HasValue && settings.VSyncCount.Value != QualitySettings.vSyncCount) + changes.Add($"vSyncCount {QualitySettings.vSyncCount} -> {settings.VSyncCount.Value}"); + if (settings.AntiAliasing.HasValue && settings.AntiAliasing.Value != QualitySettings.antiAliasing) + changes.Add($"antiAliasing {QualitySettings.antiAliasing} -> {settings.AntiAliasing.Value}"); + + if (changes.Count == 0) + return NoChanges(); + + var planText = "Set quality settings: " + string.Join("; ", changes); + + void Apply() + { + if (settings.Level.HasValue) QualitySettings.SetQualityLevel(settings.Level.Value, true); + if (settings.VSyncCount.HasValue) QualitySettings.vSyncCount = settings.VSyncCount.Value; + if (settings.AntiAliasing.HasValue) QualitySettings.antiAliasing = settings.AntiAliasing.Value; + AssetDatabase.SaveAssets(); + } + + return ProjectSettingsCommand.Apply(Group, confirm, dryRun, settings, () => planText, Apply, Read); + } + + static ProjectSettingsResponse NoChanges() + { + var response = ProjectSettingsCommand.Get(Group, Read); + response.Message = "No changes specified; nothing to apply."; + return response; + } + + static Dictionary Read() + { + var names = QualitySettings.names; + var level = QualitySettings.GetQualityLevel(); + return new Dictionary + { + ["level"] = level, + ["levelName"] = (level >= 0 && level < names.Length) ? names[level] : null, + ["levelNames"] = names, + ["vSyncCount"] = QualitySettings.vSyncCount, + ["antiAliasing"] = QualitySettings.antiAliasing + }; + } + } + + /// Quality settings to change. Null/omitted fields are left unchanged. + class QualitySettingsInput : IStructuredCommandInput + { + [CliArg("level", "Quality level index (see levelNames from get_quality_settings).")] + public int? Level { get; set; } + + [CliArg("vSyncCount", "VSync count (0 = off, 1, 2).")] + public int? VSyncCount { get; set; } + + [CliArg("antiAliasing", "MSAA sample count (0, 2, 4, 8).")] + public int? AntiAliasing { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/QualitySettingsCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/QualitySettingsCommands.cs.meta new file mode 100644 index 0000000..359020a --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/QualitySettingsCommands.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b4bc1a976dcac514796a70fd1b91a2be +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/RuntimePipelineSettingsCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/RuntimePipelineSettingsCommands.cs new file mode 100644 index 0000000..62b7b54 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/RuntimePipelineSettingsCommands.cs @@ -0,0 +1,151 @@ +using System.Collections.Generic; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Config; +using UnityEditor; +using UnityEngine; + +namespace Unity.Pipeline.Editor.Commands.ProjectSettings +{ + /// + /// Get/set the Pipeline Runtime settings (Project Settings > Pipeline > Runtime), i.e. + /// RuntimePipelineConfig: whether the runtime Pipeline server is enabled in builds, its port, + /// timeouts, audit logging, auto-start, and per-frame work item budget. This is the structured + /// equivalent of what a human does through that Project Settings page — the config has no + /// scene GameObject or asset to script against directly (see RuntimePipelineConfig.Load/Save). + /// + static class RuntimePipelineSettingsCommands + { + const string Group = "runtime_pipeline"; + + // Must stay in sync with RuntimePipelineConfig's own enforcement: OnValidate() clamps port + // to this same range, and requestTimeoutMs/maxWorkItemsPerFrame carry matching [Range] + // attributes — but neither is enforced on a direct field set like Apply() below performs, + // so Set() must check them itself. The 7900-7999 "recommended" port range is deliberately + // NOT enforced here: that's Validate()'s job as a build-time warning, not a hard rejection. + const int MinPort = 0, MaxPort = 65535; + const int MinRequestTimeoutMs = 1000, MaxRequestTimeoutMs = 60000; + const int MinMaxWorkItemsPerFrame = 1, MaxMaxWorkItemsPerFrame = 50; + + [CliCommand("get_runtime_pipeline_settings", "Read Pipeline Runtime settings (enableInBuilds, port, requestTimeoutMs, enableAuditLogging, autoStart, maxWorkItemsPerFrame). Reports the settings in effect, falling back to built-in defaults when none have been authored; never creates the settings file.", MainThreadRequired = true, Tags = new[] { "settings/runtime_pipeline" })] + public static ProjectSettingsResponse Get() => ProjectSettingsCommand.Get(Group, Read); + + [CliCommand("set_runtime_pipeline_settings", "Change Pipeline Runtime settings. Requires confirm=true; use dry_run to preview. Not undoable via Ctrl+Z. Refused while in Play Mode: the running driver already loaded its own settings, so a change would silently not apply until the next Play session or build. port, requestTimeoutMs, and maxWorkItemsPerFrame are rejected outright if outside the same bounds the Project Settings page enforces.", MainThreadRequired = true, Tags = new[] { "settings/runtime_pipeline" })] + public static ProjectSettingsResponse Set( + [CliArg("settings", "Fields to change; omitted fields are left unchanged.")] RuntimePipelineSettingsInput settings = null, + [CliArg("confirm", "Apply the change. Without it the call is refused.")] bool confirm = false, + [CliArg("dry_run", "Preview the change without applying it.")] bool dryRun = false) + { + if (settings == null) + return ProjectSettingsResponse.Fail(Group, "No 'settings' object provided."); + + if (EditorApplication.isPlaying) + { + return ProjectSettingsResponse.Fail(Group, + "Refused: Pipeline Runtime settings are read-only while in Play Mode — the running " + + "driver already loaded its own settings, so a change here would silently not apply " + + "until the next Play session or build."); + } + + var violations = new List(); + if (settings.Port.HasValue && (settings.Port.Value < MinPort || settings.Port.Value > MaxPort)) + violations.Add($"port {settings.Port.Value} out of range ({MinPort}..{MaxPort})."); + if (settings.RequestTimeoutMs.HasValue && (settings.RequestTimeoutMs.Value < MinRequestTimeoutMs || settings.RequestTimeoutMs.Value > MaxRequestTimeoutMs)) + violations.Add($"requestTimeoutMs {settings.RequestTimeoutMs.Value} out of range ({MinRequestTimeoutMs}..{MaxRequestTimeoutMs})."); + if (settings.MaxWorkItemsPerFrame.HasValue && (settings.MaxWorkItemsPerFrame.Value < MinMaxWorkItemsPerFrame || settings.MaxWorkItemsPerFrame.Value > MaxMaxWorkItemsPerFrame)) + violations.Add($"maxWorkItemsPerFrame {settings.MaxWorkItemsPerFrame.Value} out of range ({MinMaxWorkItemsPerFrame}..{MaxMaxWorkItemsPerFrame})."); + if (violations.Count > 0) + return ProjectSettingsResponse.Fail(Group, string.Join("; ", violations)); + + var config = RuntimePipelineSettingsProvider.LoadOrCreateConfig(); + try + { + var changes = new List(); + + if (settings.EnableInBuilds.HasValue && settings.EnableInBuilds.Value != config.enableInBuilds) + changes.Add($"enableInBuilds {config.enableInBuilds} -> {settings.EnableInBuilds.Value}"); + if (settings.Port.HasValue && settings.Port.Value != config.port) + changes.Add($"port {config.port} -> {settings.Port.Value}"); + if (settings.RequestTimeoutMs.HasValue && settings.RequestTimeoutMs.Value != config.requestTimeoutMs) + changes.Add($"requestTimeoutMs {config.requestTimeoutMs} -> {settings.RequestTimeoutMs.Value}"); + if (settings.EnableAuditLogging.HasValue && settings.EnableAuditLogging.Value != config.enableAuditLogging) + changes.Add($"enableAuditLogging {config.enableAuditLogging} -> {settings.EnableAuditLogging.Value}"); + if (settings.AutoStart.HasValue && settings.AutoStart.Value != config.autoStart) + changes.Add($"autoStart {config.autoStart} -> {settings.AutoStart.Value}"); + if (settings.MaxWorkItemsPerFrame.HasValue && settings.MaxWorkItemsPerFrame.Value != config.maxWorkItemsPerFrame) + changes.Add($"maxWorkItemsPerFrame {config.maxWorkItemsPerFrame} -> {settings.MaxWorkItemsPerFrame.Value}"); + + if (changes.Count == 0) + return NoChanges(); + + var planText = "Set Pipeline Runtime settings: " + string.Join("; ", changes); + + void Apply() + { + if (settings.EnableInBuilds.HasValue) config.enableInBuilds = settings.EnableInBuilds.Value; + if (settings.Port.HasValue) config.port = settings.Port.Value; + if (settings.RequestTimeoutMs.HasValue) config.requestTimeoutMs = settings.RequestTimeoutMs.Value; + if (settings.EnableAuditLogging.HasValue) config.enableAuditLogging = settings.EnableAuditLogging.Value; + if (settings.AutoStart.HasValue) config.autoStart = settings.AutoStart.Value; + if (settings.MaxWorkItemsPerFrame.HasValue) config.maxWorkItemsPerFrame = settings.MaxWorkItemsPerFrame.Value; + config.Save(); + } + + return ProjectSettingsCommand.Apply(Group, confirm, dryRun, settings, () => planText, Apply, Read); + } + finally + { + Object.DestroyImmediate(config); + } + } + + static ProjectSettingsResponse NoChanges() + { + var response = ProjectSettingsCommand.Get(Group, Read); + response.Message = "No changes specified; nothing to apply."; + return response; + } + + static Dictionary Read() + { + var config = RuntimePipelineSettingsProvider.LoadOrCreateConfig(); + try + { + return new Dictionary + { + ["enableInBuilds"] = config.enableInBuilds, + ["port"] = config.port, + ["requestTimeoutMs"] = config.requestTimeoutMs, + ["enableAuditLogging"] = config.enableAuditLogging, + ["autoStart"] = config.autoStart, + ["maxWorkItemsPerFrame"] = config.maxWorkItemsPerFrame + }; + } + finally + { + Object.DestroyImmediate(config); + } + } + } + + /// Pipeline Runtime settings to change. Null/omitted fields are left unchanged. + class RuntimePipelineSettingsInput : IStructuredCommandInput + { + [CliArg("enableInBuilds", "Enable the Pipeline HTTP server in Player builds. SECURITY WARNING: only enable in development/QA builds.")] + public bool? EnableInBuilds { get; set; } + + [CliArg("port", "HTTP port for the Pipeline server. 0 = auto-assign from range 7900-7999.")] + public int? Port { get; set; } + + [CliArg("requestTimeoutMs", "Request timeout in milliseconds.")] + public int? RequestTimeoutMs { get; set; } + + [CliArg("enableAuditLogging", "Log every remote request for security auditing.")] + public bool? EnableAuditLogging { get; set; } + + [CliArg("autoStart", "Start the server automatically when the Player boots (or Play Mode is entered).")] + public bool? AutoStart { get; set; } + + [CliArg("maxWorkItemsPerFrame", "Maximum work items the dispatcher processes per frame.")] + public int? MaxWorkItemsPerFrame { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/RuntimePipelineSettingsCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/RuntimePipelineSettingsCommands.cs.meta new file mode 100644 index 0000000..6885fd4 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/RuntimePipelineSettingsCommands.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0bb9e7729ec0e2045a5e1501a5fbfe8c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/TagsLayersCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/TagsLayersCommands.cs new file mode 100644 index 0000000..7226fa7 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/TagsLayersCommands.cs @@ -0,0 +1,143 @@ +using System.Collections.Generic; +using Unity.Pipeline.Commands; +using UnityEditor; +using UnityEditorInternal; + +namespace Unity.Pipeline.Editor.Commands.ProjectSettings +{ + /// + /// Get/set project tags and layers (CLI-202). Tags use the + /// add/remove API; user layers (indices 8..31; 0..7 are + /// reserved) are assigned via the TagManager's serialized layers array. + /// + static class TagsLayersCommands + { + const string Group = "tags_layers"; + const string TagManagerPath = "ProjectSettings/TagManager.asset"; + const int FirstUserLayer = 8; + const int LastUserLayer = 31; + + [CliCommand("get_tags_layers", "Read the project's tags and (named) layers.", MainThreadRequired = true, Tags = new[] { "settings/tags_layers" })] + public static ProjectSettingsResponse Get() => ProjectSettingsCommand.Get(Group, Read); + + [CliCommand("set_tags_layers", "Add/remove tags and assign user layer names (index 8-31). Requires confirm=true; use dry_run to preview. Not undoable via Ctrl+Z.", MainThreadRequired = true, Tags = new[] { "settings/tags_layers" })] + public static ProjectSettingsResponse Set( + [CliArg("settings", "Tag/layer changes to make.")] TagsLayersInput settings = null, + [CliArg("confirm", "Apply the change. Without it the call is refused.")] bool confirm = false, + [CliArg("dry_run", "Preview the change without applying it.")] bool dryRun = false) + { + if (settings == null) + return ProjectSettingsResponse.Fail(Group, "No 'settings' object provided."); + + if (settings.SetLayers != null) + { + foreach (var layer in settings.SetLayers) + { + if (layer == null) + continue; + if (layer.Index < FirstUserLayer || layer.Index > LastUserLayer) + return ProjectSettingsResponse.Fail(Group, + $"layer index {layer.Index} is reserved or out of range; user layers are {FirstUserLayer}..{LastUserLayer}."); + } + } + + var existingTags = new HashSet(InternalEditorUtility.tags); + var existingLayers = InternalEditorUtility.layers; + var changes = new List(); + + if (settings.AddTags != null) + foreach (var tag in settings.AddTags) + if (!string.IsNullOrEmpty(tag) && !existingTags.Contains(tag)) + changes.Add($"add tag '{tag}'"); + + if (settings.RemoveTags != null) + foreach (var tag in settings.RemoveTags) + if (!string.IsNullOrEmpty(tag) && existingTags.Contains(tag)) + changes.Add($"remove tag '{tag}'"); + + if (settings.SetLayers != null) + foreach (var layer in settings.SetLayers) + if (layer != null) + { + var desired = layer.Name ?? string.Empty; + var current = (existingLayers != null && layer.Index >= 0 && layer.Index < existingLayers.Length) + ? (existingLayers[layer.Index] ?? string.Empty) + : string.Empty; + if (current != desired) + changes.Add($"layer[{layer.Index}] = '{desired}'"); + } + + if (changes.Count == 0) + return NoChanges(); + + var planText = "Set tags/layers: " + string.Join("; ", changes); + + void Apply() + { + // Remove before add so a remove+re-add in one call behaves predictably. + if (settings.RemoveTags != null) + foreach (var tag in settings.RemoveTags) + if (!string.IsNullOrEmpty(tag)) + InternalEditorUtility.RemoveTag(tag); + + if (settings.AddTags != null) + foreach (var tag in settings.AddTags) + if (!string.IsNullOrEmpty(tag)) + InternalEditorUtility.AddTag(tag); + + if (settings.SetLayers != null && settings.SetLayers.Length > 0) + { + var so = ProjectSettingsAsset.Load(TagManagerPath); + var layersProp = so.FindProperty("layers"); + foreach (var layer in settings.SetLayers) + { + if (layer == null) + continue; + layersProp.GetArrayElementAtIndex(layer.Index).stringValue = layer.Name ?? string.Empty; + } + so.ApplyModifiedProperties(); + } + + AssetDatabase.SaveAssets(); + } + + return ProjectSettingsCommand.Apply(Group, confirm, dryRun, settings, () => planText, Apply, Read); + } + + static ProjectSettingsResponse NoChanges() + { + var response = ProjectSettingsCommand.Get(Group, Read); + response.Message = "No changes specified; nothing to apply."; + return response; + } + + static Dictionary Read() => new Dictionary + { + ["tags"] = InternalEditorUtility.tags, + ["layers"] = InternalEditorUtility.layers + }; + } + + /// Tag/layer changes. All fields optional; omitted ones make no change. + class TagsLayersInput : IStructuredCommandInput + { + [CliArg("addTags", "Tag names to add.")] + public string[] AddTags { get; set; } + + [CliArg("removeTags", "Tag names to remove.")] + public string[] RemoveTags { get; set; } + + [CliArg("setLayers", "User layer assignments (index 8-31).")] + public LayerAssignment[] SetLayers { get; set; } + } + + /// Assigns a name to a single user layer slot. + class LayerAssignment : IStructuredCommandInput + { + [CliArg("index", "Layer index (8-31 for user layers).", Required = true)] + public int Index { get; set; } + + [CliArg("name", "Layer name (empty string clears the slot).", Required = true)] + public string Name { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/TagsLayersCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/TagsLayersCommands.cs.meta new file mode 100644 index 0000000..c68e647 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/TagsLayersCommands.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2c6cb0f1d0a407f498fc141814f2d329 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/TimeSettingsCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/TimeSettingsCommands.cs new file mode 100644 index 0000000..076f806 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/TimeSettingsCommands.cs @@ -0,0 +1,80 @@ +using System.Collections.Generic; +using Unity.Pipeline.Commands; +using UnityEditor; +using UnityEngine; + +namespace Unity.Pipeline.Editor.Commands.ProjectSettings +{ + /// + /// Get/set the project Time settings (CLI-202): fixed timestep, maximum allowed timestep, and the + /// time scale. + /// + static class TimeSettingsCommands + { + const string Group = "time"; + + [CliCommand("get_time_settings", "Read Time settings (fixedDeltaTime, maximumDeltaTime, timeScale).", MainThreadRequired = true, Tags = new[] { "settings/time" })] + public static ProjectSettingsResponse Get() => ProjectSettingsCommand.Get(Group, Read); + + [CliCommand("set_time_settings", "Change Time settings. Requires confirm=true; use dry_run to preview. Not undoable via Ctrl+Z.", MainThreadRequired = true, Tags = new[] { "settings/time" })] + public static ProjectSettingsResponse Set( + [CliArg("settings", "Fields to change; omitted fields are left unchanged.")] TimeSettingsInput settings = null, + [CliArg("confirm", "Apply the change. Without it the call is refused.")] bool confirm = false, + [CliArg("dry_run", "Preview the change without applying it.")] bool dryRun = false) + { + if (settings == null) + return ProjectSettingsResponse.Fail(Group, "No 'settings' object provided."); + + var changes = new List(); + + if (settings.FixedDeltaTime.HasValue && !Mathf.Approximately(settings.FixedDeltaTime.Value, Time.fixedDeltaTime)) + changes.Add($"fixedDeltaTime {Time.fixedDeltaTime} -> {settings.FixedDeltaTime.Value}"); + if (settings.MaximumDeltaTime.HasValue && !Mathf.Approximately(settings.MaximumDeltaTime.Value, Time.maximumDeltaTime)) + changes.Add($"maximumDeltaTime {Time.maximumDeltaTime} -> {settings.MaximumDeltaTime.Value}"); + if (settings.TimeScale.HasValue && !Mathf.Approximately(settings.TimeScale.Value, Time.timeScale)) + changes.Add($"timeScale {Time.timeScale} -> {settings.TimeScale.Value}"); + + if (changes.Count == 0) + return NoChanges(); + + var planText = "Set time settings: " + string.Join("; ", changes); + + void Apply() + { + if (settings.FixedDeltaTime.HasValue) Time.fixedDeltaTime = settings.FixedDeltaTime.Value; + if (settings.MaximumDeltaTime.HasValue) Time.maximumDeltaTime = settings.MaximumDeltaTime.Value; + if (settings.TimeScale.HasValue) Time.timeScale = settings.TimeScale.Value; + AssetDatabase.SaveAssets(); + } + + return ProjectSettingsCommand.Apply(Group, confirm, dryRun, settings, () => planText, Apply, Read); + } + + static ProjectSettingsResponse NoChanges() + { + var response = ProjectSettingsCommand.Get(Group, Read); + response.Message = "No changes specified; nothing to apply."; + return response; + } + + static Dictionary Read() => new Dictionary + { + ["fixedDeltaTime"] = Time.fixedDeltaTime, + ["maximumDeltaTime"] = Time.maximumDeltaTime, + ["timeScale"] = Time.timeScale + }; + } + + /// Time settings to change. Null/omitted fields are left unchanged. + class TimeSettingsInput : IStructuredCommandInput + { + [CliArg("fixedDeltaTime", "Fixed timestep in seconds (e.g. 0.02).")] + public float? FixedDeltaTime { get; set; } + + [CliArg("maximumDeltaTime", "Maximum allowed timestep in seconds.")] + public float? MaximumDeltaTime { get; set; } + + [CliArg("timeScale", "Time scale (1 = real-time).")] + public float? TimeScale { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/TimeSettingsCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/TimeSettingsCommands.cs.meta new file mode 100644 index 0000000..c467654 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ProjectSettings/TimeSettingsCommands.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a5973463d405c064687fe56fee5d011a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/PushReloadCommand.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/PushReloadCommand.cs new file mode 100644 index 0000000..6202325 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/PushReloadCommand.cs @@ -0,0 +1,509 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Compilation; +using Unity.Pipeline.CodeReload; +using UnityEditor; +using UnityEditor.Networking.PlayerConnection; +using UnityEngine; +using UnityEngine.Networking.PlayerConnection; + +namespace Unity.Pipeline.Editor.Commands +{ + /// + /// Compile a source file's [CodeReload] override(s) in the editor and push the IL to a connected + /// player over PlayerConnection — the Profiler/Console channel (tunnels over USB, no open port or + /// token). The player applies it through the IlInterpreter interpreter (IL2CPP-safe: no Assembly.Load, + /// no Roslyn on device). + /// + /// filename may be a single .cs file or a folder: a folder is walked recursively and every + /// .cs that opts into code reload is compiled and pushed once. For a continuous watch, use the Hot + /// Reload Interpreter Watch section of the Pipeline Settings inspector (). + /// + /// Requires a Development Build connected to the editor (Build Settings → Autoconnect Profiler, + /// or attach via the Profiler/Console) with the runtime Pipeline enabled. The player's + /// ack is asynchronous and logged to the editor console. + /// + static class PushReloadCommand + { + private static bool s_Registered; + + // Pending-ack watchdog. A push that reaches no receiver (e.g. the runtime Pipeline isn't + // enabled in the player) is otherwise indistinguishable from success: the editor logs + // "pushed … (ack async)" and then nothing, forever. One entry per expected ack; entries are + // matched to acks oldest-first (acks carry no correlation id). Editor-session static: a + // domain reload drops pending entries together with the ack handler itself. + private const double AckTimeoutSeconds = 5.0; + private static readonly List<(double deadline, string desc)> s_PendingAcks = new List<(double, string)>(); + private static bool s_AckPumpHooked; + + static PushReloadCommand() + { + AssemblyReloadEvents.beforeAssemblyReload += Unregister; + } + + [CliCommand("reload_file_player_interpreter", + "Compile a file's (or folder's) [CodeReload] method(s) and push the IL to a connected player (IL2CPP-safe) over PlayerConnection. Folders are walked recursively and pushed once.", + MainThreadRequired = true, Tags = new[] { "scripts/codereload" })] + public static object PushReload( + [CliArg("filename", "Source .cs file or a folder containing [CodeReload] methods (e.g. Assets/pong.cs or Assets/Scripts)", Required = true)] string filename, + [CliArg("player", "Target connected player id; -1 = broadcast to all connected players")] int player = -1) + { + if (string.IsNullOrWhiteSpace(filename)) + return new { success = false, error = "filename is required" }; + + if (!TryResolvePath(filename, out var fullPath, out var isFolder)) + return new { success = false, error = $"Could not locate source file or folder: {filename}" }; + + if (isFolder) + return PushFolderOnce(fullPath, player); + + var ok = DoCompileAndSend(fullPath, player, out var summary, out var diagnostics); + return new { success = ok, message = summary, diagnostics }; + } + + /// Compile and push every reloadable .cs under a folder once. Files that don't opt into + /// code reload are skipped (not errors). + private static object PushFolderOnce(string folder, int player) + { + List files; + try + { + files = Directory.EnumerateFiles(folder, "*.cs", SearchOption.AllDirectories) + .Where(FileMentionsCodeReload) + .ToList(); + } + catch (Exception ex) + { + return new { success = false, error = $"Could not enumerate {folder}: {ex.Message}" }; + } + + if (files.Count == 0) + return new { success = false, error = $"No .cs files mentioning [CodeReload] found under {folder}" }; + + var pushed = new List(); + var failed = new List(); + foreach (var f in files) + { + if (DoCompileAndSend(f, player, out var summary, out var diagnostics)) + pushed.Add(Path.GetFileName(f)); + else + failed.Add(new { file = Path.GetFileName(f), error = summary, diagnostics }); + } + + return new + { + success = failed.Count == 0, + message = $"Pushed {pushed.Count}/{files.Count} file(s) from {DisplayName(folder)}" + + (pushed.Count > 0 ? $": {string.Join(", ", pushed)}" : ""), + pushed, + failed + }; + } + + /// Watcher-save push: like for a single file, but diffed + /// against the watch-start — methods still matching it are + /// left running compiled on the device, and a fully up-to-date file skips the compile and + /// send entirely. The explicit CLI command stays unfiltered as the escape hatch when the + /// connected player was NOT built from the watched sources (the baseline can't see a + /// device's build state). + internal static void PushChanged(string fullPath, int player) + { + DoCompileAndSend(fullPath, player, out _, out _, useBaseline: true); + } + + /// Re-push the watched file's/folder's code-reload overrides to one player, compiled + /// from current source. Called by when a player + /// (re)connects while a Player-target watch is active: a restarted player boots the original + /// AOT code, so everything pushed during its previous run is gone until re-pushed. + internal static void RepushAll(string fullPath, bool isFolder, int player) + { + if (!isFolder) + { + DoCompileAndSend(fullPath, player, out _, out _, useBaseline: true); // logs success and failure itself + return; + } + + List files; + try + { + files = Directory.EnumerateFiles(fullPath, "*.cs", SearchOption.AllDirectories) + .Where(FileMentionsCodeReload) + .ToList(); + } + catch (Exception ex) + { + Debug.LogError($"[PushReload] Re-push to player {player} failed — could not enumerate {fullPath}: {ex.Message}"); + return; + } + + int pushed = 0; + foreach (var f in files) + if (DoCompileAndSend(f, player, out _, out _, useBaseline: true)) + pushed++; + Debug.Log($"[PushReload] Re-pushed {pushed}/{files.Count} reloadable file(s) to player {player}."); + } + + /// Preprocessor symbols the target player's copy of this file was compiled with: + /// the defines of the player-variant assembly that owns the file, falling back to any + /// player assembly's defines, then null (= editor defines downstream) if the compilation + /// pipeline can't answer. Cheap relative to the compile that follows. + internal static string[] PlayerDefinesFor(string fullPath) + { + try + { + var assemblies = UnityEditor.Compilation.CompilationPipeline + .GetAssemblies(UnityEditor.Compilation.AssembliesType.Player); + var norm = Path.GetFullPath(fullPath).Replace('\\', '/'); + foreach (var a in assemblies) + foreach (var f in a.sourceFiles) + if (Path.GetFullPath(f).Replace('\\', '/') + .Equals(norm, StringComparison.OrdinalIgnoreCase)) + return a.defines; + return assemblies.Length > 0 ? assemblies[0].defines : null; + } + catch (Exception) + { + return null; + } + } + + /// Compile the file's overrides and send them to the target player(s). Never throws. + /// Failures are logged to the editor console as well as returned: the code-reload watcher + /// (Player target) discards the return value, so the console is the only surface where a + /// failing watch-mode push is visible at all. + private static bool DoCompileAndSend(string fullPath, int player, out string summary, out List diagnostics, + bool useBaseline = false) + { + diagnostics = null; + try + { + EnsureRegistered(); + + // Compile with the PLAYER's preprocessor symbols, not the editor's: the pushed body + // must resolve #if UNITY_EDITOR / platform regions the way the player's own + // assemblies did, or the override diverges from the code it replaces. + var playerDefines = PlayerDefinesFor(fullPath); + // Methods already overridden on a device must reload even when they match the + // baseline again: there is no remote unregister, so the only way to clear a stale + // override is to replace it with one compiled from the (reverted) source. + var mustReload = useBaseline ? GetPushedMethods(fullPath) : null; + + // Up-to-date pre-check BEFORE the pending notice: announcing a compile and then + // sending nothing would leave the device overlay stuck on "compiling…". + if (useBaseline && FileIsUpToDate(fullPath, playerDefines, mustReload)) + { + summary = "up to date — every [CodeReload] method matches the watch-start baseline; nothing pushed"; + Debug.Log($"[PushReload] {Path.GetFileName(fullPath)}: {summary}"); + return true; + } + + // Compilation happens here in the editor — announce it so the player's status overlay + // can show "compiling…" during the gap before the payload (or failure notice) arrives. + TrySendNotice(PipelineCodeReloadConnect.ReloadPendingMsg, Path.GetFileName(fullPath), player); + + var compiled = InPlaceReloadProcessor.CompileOverrideForPush(fullPath, playerDefines, + useBaseline ? mustReload : null, useBaseline); + diagnostics = compiled.Diagnostics; + + // The pre-check should have caught this; a save landing between the two reads can + // still get here. Nothing to push either way. + if (compiled.AllUpToDate) + { + summary = "up to date — every [CodeReload] method matches the watch-start baseline; nothing pushed"; + Debug.Log($"[PushReload] {Path.GetFileName(fullPath)}: {summary}"); + return true; + } + if (!compiled.Success) + { + summary = "compile failed: " + (compiled.Error ?? "unknown"); + var details = diagnostics != null && diagnostics.Count > 0 + ? ":\n- " + string.Join("\n- ", diagnostics) + : ""; + Debug.LogError($"[PushReload] {Path.GetFileName(fullPath)}: {summary}{details}"); + TrySendNotice(PipelineCodeReloadConnect.ReloadFailedMsg, + $"{Path.GetFileName(fullPath)}: {summary} (details in the editor console)", player); + return false; + } + + // Run the same interpreter load pass the player runs on receipt, so binding gaps come + // back in THIS response — the player's async ack carries only a warning count (the + // member list goes to the device log). Never blocks the push: an unbound member is a + // stub that throws only if executed. + var unbound = InterpreterCodeReloadExecutor.ValidateBindingSurface( + compiled.IlBytes, compiled.TypeName, compiled.MethodNames, out var validationNote); + if (unbound.Count > 0) + { + diagnostics ??= new List(); + foreach (var member in unbound) + diagnostics.Add($"binding: host member '{member}' is not registered and will " + + "throw if the reloaded code reaches it"); + Debug.LogWarning($"[PushReload] {Path.GetFileName(fullPath)}: {unbound.Count} host " + + $"member(s) referenced by the override are not in the interpreter binding and will " + + $"throw if reached: {string.Join(", ", unbound)}. Types outside the standard " + + "surface and demand-time auto-bind are not callable from pushed overrides; BCL " + + "members outside the standard surface need an explicit AllowBcl shim."); + } + if (validationNote != null) + Debug.LogWarning($"[PushReload] {Path.GetFileName(fullPath)}: binding validation note: {validationNote}"); + + var players = EditorConnection.instance.ConnectedPlayers; + if (players == null || players.Count == 0) + { + summary = "no player connected (run a Development Build with Autoconnect Profiler)"; + Debug.LogWarning($"[PushReload] {Path.GetFileName(fullPath)}: {summary}"); + return false; + } + + var payload = PipelineCodeReloadConnect.Encode(compiled.TypeName, compiled.MethodNames, compiled.IlBytes); + var desc = $"{compiled.TypeName} ({Path.GetFileName(fullPath)})"; + + // Every player gets its own signed envelope (session nonces differ), so "broadcast" + // is a per-player loop rather than one connection-wide Send. PushSigner tracks the + // expected ack per actual send, so no TrackExpectedAcks call here. + int sent = 0, deferred = 0, failedSends = 0, matched = 0; + foreach (var target in players) + { + if (player >= 0 && target.playerId != player) continue; + matched++; + switch (PushSigner.PushOrDefer(target.playerId, payload, desc)) + { + case PushSendStatus.Sent: sent++; break; + case PushSendStatus.Deferred: deferred++; break; + default: failedSends++; break; + } + } + + if (matched == 0) + { + summary = $"player {player} is not connected"; + Debug.LogWarning($"[PushReload] {Path.GetFileName(fullPath)}: {summary}"); + return false; + } + + // A device can't unregister an override, so record every method sent or deferred — a + // later baseline-filtered push must re-include it or a reverted edit would strand the + // device on the stale override. + RecordPushedMethods(fullPath, compiled.MethodNames); + + summary = $"pushed {compiled.TypeName} ({compiled.MethodNames.Count} method(s), {compiled.IlBytes.Length} B) " + + $"signed to {sent} player(s)" + + (deferred > 0 ? $"; {deferred} deferred awaiting player handshake" : "") + + (failedSends > 0 ? $"; {failedSends} failed (see console)" : "") + + (compiled.UpToDateMethods.Count > 0 ? $"; {compiled.UpToDateMethods.Count} method(s) up to date, left compiled" : "") + + (unbound.Count > 0 ? $"; {unbound.Count} binding warning(s) — see diagnostics" : "") + + " (ack async)"; + Debug.Log($"[PushReload] {summary}"); + return failedSends == 0; + } + catch (Exception ex) + { + summary = $"push error: {ex.Message}"; + Debug.LogError($"[PushReload] {Path.GetFileName(fullPath)}: {summary}"); + TrySendNotice(PipelineCodeReloadConnect.ReloadFailedMsg, + $"{Path.GetFileName(fullPath)}: {summary}", player); + return false; + } + } + + /// Best-effort overlay notice to the target player(s); a notice failing must never + /// fail the push itself. + private static void TrySendNotice(Guid msg, string text, int player) + { + try + { + var payload = PipelineCodeReloadConnect.EncodeText(text); + if (player >= 0) + EditorConnection.instance.Send(msg, payload, player); + else + EditorConnection.instance.Send(msg, payload); + } + catch { /* overlay notices are cosmetic */ } + } + + private static void EnsureRegistered() + { + EditorConnection.instance.Initialize(); + if (s_Registered) return; + EditorConnection.instance.Register(PipelineCodeReloadConnect.ResultMsg, OnResult); + s_Registered = true; + } + + private static void Unregister() + { + s_PendingAcks.Clear(); + if (s_AckPumpHooked) + { + EditorApplication.update -= PumpPendingAcks; + s_AckPumpHooked = false; + } + if (!s_Registered) return; + try { EditorConnection.instance.Unregister(PipelineCodeReloadConnect.ResultMsg, OnResult); } + catch { /* connection may already be gone during teardown */ } + s_Registered = false; + } + + // EditorConnection callbacks are dispatched on the main thread, same as the update pump — + // no locking needed around s_PendingAcks. + private static void OnResult(MessageEventArgs args) + { + if (s_PendingAcks.Count > 0) + s_PendingAcks.RemoveAt(0); + if (PipelineCodeReloadConnect.TryDecodeResult(args.data, out var ok, out var message)) + { + // A pre-signing player build cannot parse a signed envelope and acks it as malformed + // — name the actual fix instead of leaving a mystery. + var hint = !ok && message != null && message.Contains("malformed code-reload push") + ? " (if this player build predates push signing, rebuild it with the current com.unity.pipeline package)" + : ""; + Debug.Log($"[PushReload] Player ack: {(ok ? "OK" : "FAILED")} — {message}{hint}"); + } + else + Debug.LogWarning("[PushReload] Received a player ack that could not be decoded."); + } + + /// One expected-ack slot for a push just sent. + internal static void TrackAck(string desc) + { + EnsureRegistered(); + TrackExpectedAcks(1, desc); + } + + private static void TrackExpectedAcks(int count, string desc) + { + double deadline = EditorApplication.timeSinceStartup + AckTimeoutSeconds; + for (int i = 0; i < count; i++) + s_PendingAcks.Add((deadline, desc)); + if (!s_AckPumpHooked) + { + EditorApplication.update += PumpPendingAcks; + s_AckPumpHooked = true; + } + } + + private static void PumpPendingAcks() + { + double now = EditorApplication.timeSinceStartup; + for (int i = s_PendingAcks.Count - 1; i >= 0; i--) + { + if (now < s_PendingAcks[i].deadline) continue; + Debug.LogWarning($"[PushReload] No player ack for {s_PendingAcks[i].desc} within {AckTimeoutSeconds:0}s — " + + "is the player still connected, and does it have the runtime Pipeline enabled?"); + s_PendingAcks.RemoveAt(i); + } + if (s_PendingAcks.Count == 0) + { + EditorApplication.update -= PumpPendingAcks; + s_AckPumpHooked = false; + } + } + + /// Resolve to an existing folder or .cs file. Folders are checked + /// first (so a bare directory name isn't turned into "<dir>.cs"); files get a .cs suffix if missing. + private static bool TryResolvePath(string input, out string fullPath, out bool isFolder) + { + fullPath = null; + isFolder = false; + + foreach (var d in new[] { input, Path.Combine("Assets", input) }) + { + if (Directory.Exists(d)) + { + fullPath = Path.GetFullPath(d); + isFolder = true; + return true; + } + } + + var file = input.EndsWith(".cs", StringComparison.OrdinalIgnoreCase) ? input : input + ".cs"; + fullPath = ResolveSourceFilePath(file); + return fullPath != null; + } + + private static string ResolveSourceFilePath(string filename) + { + if (Path.IsPathRooted(filename) && File.Exists(filename)) + return filename; + foreach (var p in new[] { Path.Combine("Assets", filename), Path.Combine("Assets", "Scripts", filename), filename }) + if (File.Exists(p)) + return Path.GetFullPath(p); + return null; + } + + /// Every [CodeReload] method in the file still matches the watch-start baseline + /// (player defines) and none of them was ever pushed. Read failure = not up to date. + private static bool FileIsUpToDate(string fullPath, string[] playerDefines, HashSet mustReload) + { + try + { + var source = File.ReadAllText(fullPath); + return CodeReloadBaseline.IsFileUpToDate(fullPath, source, playerDefines, mustReload); + } + catch + { + return false; + } + } + + // Method names pushed to any player this editor session, per file. A device can't + // unregister an override, so once a method is pushed, every later baseline-filtered push + // must include it again — otherwise reverting an edit would strand the device on the stale + // override while the editor reports "up to date". SessionState-backed so the play-mode + // domain reload doesn't forget what connected devices still hold. + private const string SkPushedMethods = "Pipeline.PushReload.PushedMethods"; + + private static HashSet GetPushedMethods(string fullPath) + { + var set = new HashSet(StringComparer.Ordinal); + var raw = SessionState.GetString(SkPushedMethods, ""); + if (string.IsNullOrEmpty(raw)) return set; + var key = Path.GetFullPath(fullPath); + foreach (var line in raw.Split('\n')) + { + int sep = line.IndexOf('\u001f'); + if (sep <= 0 || !string.Equals(line.Substring(0, sep), key, StringComparison.OrdinalIgnoreCase)) + continue; + foreach (var m in line.Substring(sep + 1).Split(';')) + if (m.Length > 0) + set.Add(m); + } + return set; + } + + private static void RecordPushedMethods(string fullPath, List methods) + { + if (methods == null || methods.Count == 0) return; + var set = GetPushedMethods(fullPath); + int before = set.Count; + foreach (var m in methods) + set.Add(m); + if (set.Count == before) return; + + var key = Path.GetFullPath(fullPath); + var lines = new List(); + var raw = SessionState.GetString(SkPushedMethods, ""); + if (!string.IsNullOrEmpty(raw)) + foreach (var line in raw.Split('\n')) + { + int sep = line.IndexOf('\u001f'); + if (sep > 0 && !string.Equals(line.Substring(0, sep), key, StringComparison.OrdinalIgnoreCase)) + lines.Add(line); + } + lines.Add(key + '\u001f' + string.Join(";", set)); + SessionState.SetString(SkPushedMethods, string.Join("\n", lines)); + } + + // Cheap opt-in filter shared with EditorCodeReloadWatcher: a file that never mentions + // "CodeReload" cannot carry the attribute, so folder scans skip it without compiling. + internal static bool FileMentionsCodeReload(string path) + { + try { return File.ReadAllText(path).Contains("CodeReload"); } + catch { return false; } + } + + private static string DisplayName(string path) => + string.IsNullOrEmpty(path) ? "?" : Path.GetFileName(path.TrimEnd('/', '\\')); + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/PushReloadCommand.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/PushReloadCommand.cs.meta new file mode 100644 index 0000000..fe632d6 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/PushReloadCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7c78e53a3bb1c6948b9be86010c9a405 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/RecompileCommand.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/RecompileCommand.cs new file mode 100644 index 0000000..3d2ff4e --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/RecompileCommand.cs @@ -0,0 +1,211 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Newtonsoft.Json; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Console; +using UnityEditor; +using UnityEditor.Compilation; +using UnityEngine; +#if UNITY_6000_5_OR_NEWER +using Unity.Scripting.LifecycleManagement; +#endif + +namespace Unity.Pipeline.Editor.Commands +{ + /// + /// Forces a script recompile that works even when the editor is unfocused or minimized. + /// + /// Why this is non-trivial: + /// - Unity only runs script compilation while the editor is the active OS application. Pass + /// focus=true to bring it to the foreground (editor_focus) before AssetDatabase.Refresh(); + /// it is off by default because the server keeps the editor ticking while unfocused, so + /// compilation still proceeds without stealing the user's foreground window. + /// - A successful compile triggers a domain reload, which destroys the managed AppDomain + /// (HTTP server, in-flight requests, statics). The triggering request therefore cannot stay + /// open and return when done. + /// + /// Pattern (mirrors the test runner): completion is reported via a status file that survives the + /// domain reload. Call "recompile" to trigger, then poll "recompile_status" until status is + /// "completed" or "up_to_date". The client must tolerate connection errors during the reload. + /// + /// The status file is not sufficient on its own: a failed editor compile suppresses the domain + /// reload entirely, and the file lives under Temp/, which Unity deletes at every editor launch. + /// Both commands therefore also consult the compile-failure flag Unity keeps natively. + /// + [InitializeOnLoad] +#if UNITY_6000_5_OR_NEWER + [NoAutoStaticsCleanup] +#endif + static class RecompileCommand + { + const string StatusFile = "Temp/pipeline_recompile_status.json"; + + // How stale a ground-truth sample may be and still describe the present. Sampling runs on + // the main thread, so it stops while the Editor is blocked and across a domain reload. + const double MaxGroundTruthAgeSeconds = 2.0; + + static readonly List s_Errors = new List(); + + // Focus action, indirected so tests can observe whether focus was performed without + // actually stealing the OS foreground window. + internal static Action s_FocusAction = () => FocusEditorCommand.FocusEditor(); + + // Indirected for the same reason: a test cannot make Unity's native compile-failure flag + // true, but it can point this at a stub. + internal static Func s_CompilationFailedProbe = () => EditorUtility.scriptCompilationFailed; + + /// The status file's contents. Shared by the writer and both readers. + [Serializable] + class RecompileStatusPayload + { + [JsonProperty("status")] public string Status; + [JsonProperty("failed")] public bool Failed; + [JsonProperty("errors")] public string[] Errors; + + /// + /// Whether the project currently has editor compile errors, as Unity reports it + /// natively. Filled when the status is read rather than written: it outlives both the + /// status file and any domain reload, so it is the authority when the two disagree. + /// + [JsonProperty("compilationFailed")] public bool CompilationFailed; + } + + static RecompileCommand() + { + CompilationPipeline.compilationStarted += OnCompilationStarted; + CompilationPipeline.assemblyCompilationFinished += OnAssemblyCompilationFinished; + CompilationPipeline.compilationFinished += OnCompilationFinished; + } + + [CliCommand("recompile", "Force a script recompile (works while unfocused/minimized). Poll recompile_status for completion.", MainThreadRequired = true, Tags = new[] { "scripts/compile" })] + public static object Recompile( + [CliArg("focus", "If true, bring the Editor to the foreground before compiling. Off by default.")] bool focus = false) + { + // Unity compiles only while it is the active application. Optionally bring it to the + // foreground first; off by default (the server keeps the editor ticking while unfocused, + // so compilation still proceeds). + if (focus) + s_FocusAction(); + + var previous = ReadStatusOrIdle(); + WriteStatus("triggered", false, null); + + // Trigger asset import + compilation. + AssetDatabase.Refresh(); + + if (EditorApplication.isCompiling) + { + // compilationStarted has written "compiling"; a domain reload will follow on success. + return new { status = "compiling", message = "Recompilation started. Poll recompile_status until completed." }; + } + + // Nothing was imported and nothing compiled. That is only "up to date" if the code + // actually builds: a failed editor compile leaves the errors standing and suppresses the + // domain reload, so a repeat call with nothing changed lands here with the failure still + // true. Reporting "up_to_date" would erase it. + if (s_CompilationFailedProbe()) + { + if (previous.Failed) + WriteStatus(previous.Status, true, previous.Errors); + else + WriteStatus("completed", true, Array.Empty()); + + return new { status = "failed", message = "Scripts still have compile errors; nothing was recompiled. Read them with the console command." }; + } + + WriteStatus("up_to_date", false, null); + return new { status = "up_to_date", message = "No scripts needed recompilation." }; + } + + [CliCommand("recompile_status", "Get the status of the last recompile: idle | triggered | compiling | completed | up_to_date.", MainThreadRequired = false, Tags = new[] { "scripts/compile" })] + public static string RecompileStatus() + { + var status = ReadStatusOrIdle(); + + var truth = ConsoleLogCapture.GroundTruth; + var fresh = truth != null + && (DateTime.UtcNow - truth.SampledUtc).TotalSeconds <= MaxGroundTruthAgeSeconds; + + status.CompilationFailed = fresh && truth.CompilationFailed; + + // Only a status that carries no evidence of its own defers to the native flag. "idle" is + // what the file reads after an editor launch, since Temp/ is deleted then, and + // "up_to_date" means nothing compiled — in both cases errors can be standing with + // nothing in the file to say so. + // + // A "completed" status is not overridden: it was written by the compile that just ran and + // lists exactly what that compile produced. The native flag still reads true for a moment + // after a fixing compile finishes — it clears with the domain reload that follows — so + // trusting it there would report a build that has just been fixed as broken. + var carriesNoEvidence = status.Status == "idle" || status.Status == "up_to_date"; + if (status.CompilationFailed && carriesNoEvidence && !status.Failed) + { + status.Status = "completed"; + status.Failed = true; + } + + return JsonConvert.SerializeObject(status); + } + + static void OnCompilationStarted(object _) + { + s_Errors.Clear(); + WriteStatus("compiling", false, null); + } + + static void OnAssemblyCompilationFinished(string assembly, CompilerMessage[] messages) + { + if (messages == null) return; + foreach (var m in messages) + if (m.type == CompilerMessageType.Error) + s_Errors.Add(m.message); + } + + static void OnCompilationFinished(object _) + { + // Written before the domain reload, so it persists for pollers after the reload. + WriteStatus("completed", s_Errors.Count > 0, s_Errors.ToArray()); + } + + static RecompileStatusPayload ReadStatusOrIdle() + { + try + { + if (File.Exists(StatusFile)) + { + var payload = JsonConvert.DeserializeObject(File.ReadAllText(StatusFile)); + if (payload != null) + { + payload.Errors = payload.Errors ?? Array.Empty(); + return payload; + } + } + } + catch (Exception ex) + { + Debug.LogWarning($"[Recompile] Failed to read status file: {ex.Message}"); + } + + return new RecompileStatusPayload { Status = "idle", Errors = Array.Empty() }; + } + + static void WriteStatus(string status, bool failed, string[] errors) + { + try + { + var payload = new RecompileStatusPayload + { + Status = status, + Failed = failed, + Errors = errors ?? Array.Empty() + }; + File.WriteAllText(StatusFile, JsonConvert.SerializeObject(payload)); + } + catch (Exception ex) + { + Debug.LogError($"[Recompile] Failed to write status file: {ex.Message}"); + } + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/RecompileCommand.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/RecompileCommand.cs.meta new file mode 100644 index 0000000..287a05c --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/RecompileCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c0ded562e1968c342b40922dbb32f3f5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scenes.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scenes.meta new file mode 100644 index 0000000..e7459cb --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d7cf2e413ccd43f0b9dfb4db22c6cb29 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scenes/SceneCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scenes/SceneCommands.cs new file mode 100644 index 0000000..1b59b4f --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scenes/SceneCommands.cs @@ -0,0 +1,395 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Models; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine; +using UnityEngine.SceneManagement; + +namespace Unity.Pipeline.Editor.Commands.Scenes +{ + /// + /// Scene-management authoring commands (CLI-193): create / open / save scenes, inspect open + /// scenes, control the active scene, snapshot a scene's hierarchy, and manage the build scene + /// list. They build on the same foundation as the asset commands — paths go through the + /// sandbox and results come back as the canonical + /// envelope so an agent can chain follow-up calls. + /// + /// WHY the play-mode guard: mutations (new/open/save/setActive) + /// are undefined and destructive while the editor is entering or in play mode — they can discard + /// in-flight play-mode state or leave the scene manager inconsistent. Rather than risk corrupting + /// state, every mutating command refuses up front with a clear, *recoverable* error (an + /// , surfaced by the server as a 400 "Command Execution + /// Failed" without touching scene state). The caller can exit play mode and retry. + /// + static class SceneCommands + { + private const string SceneExtension = ".unity"; + + // create_scene --template values. "empty" is the historical default (blank scene); "default" + // seeds Unity's built-in "3D" new-scene contents (Main Camera + Directional Light). + private const string TemplateEmpty = "empty"; + private const string TemplateDefault = "default"; + + #region Create / Open / Save + + [CliCommand("create_scene", "Create a new scene and save it to the given path under the authoring root.", Tags = new[] { "scenes" })] + public static AuthoringResult CreateScene( + [CliArg("path", "Scene path relative to the authoring root (default Assets/); the Assets/ prefix and the .unity extension are optional. e.g. Scenes/Level1", Required = true)] string path, + [CliArg("additive", "Open the new scene additively alongside currently open scenes instead of replacing them.", DefaultValue = false)] bool additive = false, + [CliArg("template", "Initial contents: 'empty' (default) for a blank scene, or 'default' to seed a Main Camera + Directional Light matching Unity's built-in 3D template.", DefaultValue = TemplateEmpty)] string template = TemplateEmpty) + { + GuardNotPlaying("create_scene"); + + // Validate the template up front (before touching scene state) so an unknown value fails + // recoverably with a clear, enumerated error rather than silently doing the wrong thing. + var sceneSetup = ResolveSceneSetup(template); + + var normalized = ResolveScenePath(path); + EnsureParentFolder(normalized); + + // NewSceneMode.Single replaces all open scenes; Additive keeps them. NewSceneSetup.EmptyScene + // gives a blank scene (no default camera/light) — predictable for programmatic population; + // NewSceneSetup.DefaultGameObjects gives exactly a Main Camera (tagged MainCamera) + a + // Directional Light, identical to Unity's built-in "3D" new-scene template. + var setup = additive ? NewSceneMode.Additive : NewSceneMode.Single; + var scene = EditorSceneManager.NewScene(sceneSetup, setup); + + if (!EditorSceneManager.SaveScene(scene, normalized)) + throw new InvalidOperationException($"Failed to save new scene to '{normalized}'."); + + AssetDatabase.Refresh(); + return DescribeSceneAsset(normalized); + } + + [CliCommand("open_scene", "Open an existing scene from the given path.", Tags = new[] { "scenes" })] + public static AuthoringResult OpenScene( + [CliArg("path", "Scene path relative to the authoring root (default Assets/); the Assets/ prefix and the .unity extension are optional.", Required = true)] string path, + [CliArg("additive", "Open additively alongside currently open scenes instead of replacing them.", DefaultValue = false)] bool additive = false) + { + GuardNotPlaying("open_scene"); + + var normalized = ResolveScenePath(path); + if (string.IsNullOrEmpty(AssetDatabase.AssetPathToGUID(normalized))) + throw new InvalidOperationException($"No scene asset at '{normalized}'."); + + var mode = additive ? OpenSceneMode.Additive : OpenSceneMode.Single; + var scene = EditorSceneManager.OpenScene(normalized, mode); + if (!scene.IsValid()) + throw new InvalidOperationException($"Failed to open scene '{normalized}'."); + + return DescribeSceneAsset(normalized); + } + + [CliCommand("save_scene", "Save an open scene. Saves the active scene when no path is given.", Tags = new[] { "scenes" })] + public static AuthoringResult SaveScene( + [CliArg("path", "Path of the open scene to save (authoring-root relative; Assets/ prefix and .unity optional). Omit to save the active scene.")] string path = null) + { + GuardNotPlaying("save_scene"); + + var scene = string.IsNullOrEmpty(path) + ? EditorSceneManager.GetActiveScene() + : FindOpenScene(ResolveScenePath(path)); + + if (!scene.IsValid() || !scene.isLoaded) + throw new InvalidOperationException( + string.IsNullOrEmpty(path) + ? "No valid active scene to save." + : $"Scene '{path}' is not open."); + + // An untitled/never-saved scene has an empty path. SaveScene(scene) with no explicit path + // would either trigger a modal "Save Scene" dialog (hangs a headless editor) or fail + // non-deterministically. Refuse up front with a recoverable error so the caller picks a path. + if (string.IsNullOrEmpty(scene.path)) + throw new InvalidOperationException( + $"Scene '{scene.name}' has never been saved (no path). " + + "Create or save it with an explicit path first (create_scene ) — no scene state was changed."); + + if (!EditorSceneManager.SaveScene(scene)) + throw new InvalidOperationException($"Failed to save scene '{scene.name}'."); + + AssetDatabase.Refresh(); + return DescribeSceneAsset(scene.path); + } + + [CliCommand("save_all", "Save all open scenes that have unsaved changes.", Tags = new[] { "scenes" })] + public static object SaveAll() + { + GuardNotPlaying("save_all"); + + // SaveOpenScenes saves every loaded, dirty scene. A dirty untitled scene (empty path) would + // make it pop a modal "Save Scene" dialog, which hangs a headless editor. Fail fast with a + // recoverable error before saving anything so the caller saves that scene with an explicit path. + var dirty = OpenScenes().Where(s => s.isDirty).ToList(); + var untitled = dirty.Where(s => string.IsNullOrEmpty(s.path)).Select(s => s.name).ToList(); + if (untitled.Count > 0) + throw new InvalidOperationException( + $"Cannot save all: {untitled.Count} dirty scene(s) have never been saved ({string.Join(", ", untitled)}). " + + "Save each with an explicit path first (create_scene ) — no scenes were saved."); + + // Report which scenes it touched. + var dirtyBefore = dirty.Select(s => s.path).ToList(); + + var saved = EditorSceneManager.SaveOpenScenes(); + if (!saved && dirtyBefore.Count > 0) + throw new InvalidOperationException("Failed to save one or more open scenes."); + + AssetDatabase.Refresh(); + return new { saved, scenes = dirtyBefore }; + } + + #endregion + + #region Inspect / Active + + [CliCommand("list_open_scenes", "List all currently open scenes with their load/active/dirty state.", Tags = new[] { "scenes" })] + public static object ListOpenScenes() + { + // Read-only; safe in play mode, so no guard here. + var active = SceneManager.GetActiveScene(); + var scenes = OpenScenes() + .Select(s => new + { + name = s.name, + path = s.path, + isLoaded = s.isLoaded, + isDirty = s.isDirty, + isActive = s.handle == active.handle, + rootCount = s.isLoaded ? s.rootCount : 0 + }) + .ToList(); + + return new { count = scenes.Count, scenes }; + } + + [CliCommand("set_active_scene", "Set which open scene is the active scene (new objects are created in the active scene).", Tags = new[] { "scenes" })] + public static AuthoringResult SetActiveScene( + [CliArg("path", "Path of an already-open scene to make active (authoring-root relative; Assets/ prefix and .unity optional).", Required = true)] string path) + { + GuardNotPlaying("set_active_scene"); + + var normalized = ResolveScenePath(path); + var scene = FindOpenScene(normalized); + if (!scene.IsValid() || !scene.isLoaded) + throw new InvalidOperationException($"Scene '{path}' is not open; open it before making it active."); + + if (!SceneManager.SetActiveScene(scene)) + throw new InvalidOperationException($"Failed to set '{normalized}' as the active scene."); + + return DescribeSceneAsset(scene.path); + } + + [CliCommand("get_scene_hierarchy", "Return the GameObject tree of an open scene (or the active scene). Each node carries instanceId + hierarchyPath usable by GameObject commands.", Tags = new[] { "scenes" })] + public static SceneHierarchy GetSceneHierarchy( + [CliArg("path", "Path of the open scene to snapshot (authoring-root relative; Assets/ prefix and .unity optional). Omit for the active scene.")] string path = null) + { + // Read-only; safe in play mode. + var scene = string.IsNullOrEmpty(path) + ? SceneManager.GetActiveScene() + : FindOpenScene(ResolveScenePath(path)); + + if (!scene.IsValid() || !scene.isLoaded) + throw new InvalidOperationException( + string.IsNullOrEmpty(path) + ? "No valid active scene to read." + : $"Scene '{path}' is not open."); + + var active = SceneManager.GetActiveScene(); + var hierarchy = new SceneHierarchy + { + SceneName = scene.name, + ScenePath = scene.path, + IsDirty = scene.isDirty, + IsActive = scene.handle == active.handle + }; + + foreach (var root in scene.GetRootGameObjects()) + hierarchy.Roots.Add(BuildNode(root, "/" + root.name)); + + return hierarchy; + } + + #endregion + + #region Build settings + + [CliCommand("add_scene_to_build", "Add a scene to the Build Settings scene list (idempotent). Optionally enable it.", Tags = new[] { "scenes", "build/settings" })] + public static object AddSceneToBuild( + [CliArg("path", "Scene path to add (authoring-root relative; Assets/ prefix and .unity optional).", Required = true)] string path, + [CliArg("enabled", "Whether the scene is enabled in the build list.", DefaultValue = true)] bool enabled = true) + { + GuardNotPlaying("add_scene_to_build"); + + var normalized = ResolveScenePath(path); + if (string.IsNullOrEmpty(AssetDatabase.AssetPathToGUID(normalized))) + throw new InvalidOperationException($"No scene asset at '{normalized}'."); + + var scenes = EditorBuildSettings.scenes.ToList(); + var existing = scenes.FindIndex(s => PathsEqual(s.path, normalized)); + if (existing >= 0) + { + // Idempotent: just reconcile the enabled flag. + if (scenes[existing].enabled != enabled) + scenes[existing] = new EditorBuildSettingsScene(normalized, enabled); + } + else + { + scenes.Add(new EditorBuildSettingsScene(normalized, enabled)); + } + + EditorBuildSettings.scenes = scenes.ToArray(); + return new { path = normalized, enabled, buildIndex = SceneUtility.GetBuildIndexByScenePath(normalized), count = scenes.Count }; + } + + [CliCommand("remove_scene_from_build", "Remove a scene from the Build Settings scene list (idempotent).", Tags = new[] { "scenes", "build/settings" })] + public static object RemoveSceneFromBuild( + [CliArg("path", "Scene path to remove (authoring-root relative; Assets/ prefix and .unity optional).", Required = true)] string path) + { + GuardNotPlaying("remove_scene_from_build"); + + var normalized = ResolveScenePath(path); + var scenes = EditorBuildSettings.scenes.ToList(); + var removed = scenes.RemoveAll(s => PathsEqual(s.path, normalized)); + EditorBuildSettings.scenes = scenes.ToArray(); + return new { path = normalized, removed = removed > 0, count = scenes.Count }; + } + + #endregion + + #region Helpers + + /// + /// Refuse a mutating scene op while entering or in play mode. We deliberately throw a + /// recoverable *before* touching any state, so the + /// command surfaces as a clean failure rather than leaving the scene manager inconsistent. + /// + private static void GuardNotPlaying(string command) + { + if (EditorApplication.isPlayingOrWillChangePlaymode) + throw new InvalidOperationException( + $"'{command}' cannot run while the editor is in (or entering) play mode. " + + "Exit play mode (editor_stop) and retry — no scene state was changed."); + } + + /// + /// Map the create_scene template argument to a . "empty" + /// (or a null/blank value) keeps the historical blank-scene behavior; "default" seeds Unity's + /// built-in "3D" template (Main Camera tagged MainCamera + Directional Light). An unknown value + /// throws a recoverable listing the valid options. + /// + private static NewSceneSetup ResolveSceneSetup(string template) + { + // Treat a null/blank template as the default ("empty") for parity with an omitted argument. + var value = string.IsNullOrWhiteSpace(template) ? TemplateEmpty : template.Trim(); + + if (string.Equals(value, TemplateEmpty, StringComparison.OrdinalIgnoreCase)) + return NewSceneSetup.EmptyScene; + if (string.Equals(value, TemplateDefault, StringComparison.OrdinalIgnoreCase)) + return NewSceneSetup.DefaultGameObjects; + + throw new ArgumentException( + $"Unknown template '{template}'. Valid values: '{TemplateEmpty}', '{TemplateDefault}'."); + } + + /// Resolve an agent path through the sandbox and normalize it to a "*.unity" asset path. + private static string ResolveScenePath(string path) + { + var normalized = ProjectPaths.Resolve(path, out var error); + if (normalized == null) + throw new ArgumentException(error); + + if (!normalized.EndsWith(SceneExtension, StringComparison.OrdinalIgnoreCase)) + normalized += SceneExtension; + + return normalized; + } + + /// Create the scene's parent folder chain if missing (mirrors FolderCommands). + private static void EnsureParentFolder(string scenePath) + { + var parent = Path.GetDirectoryName(scenePath)?.Replace('\\', '/'); + if (string.IsNullOrEmpty(parent) || AssetDatabase.IsValidFolder(parent)) + return; + + CreateFolderRecursive(parent); + } + + private static void CreateFolderRecursive(string assetsPath) + { + if (AssetDatabase.IsValidFolder(assetsPath)) + return; + + var parent = Path.GetDirectoryName(assetsPath)?.Replace('\\', '/'); + var name = Path.GetFileName(assetsPath); + if (string.IsNullOrEmpty(parent) || string.IsNullOrEmpty(name)) + throw new ArgumentException($"Invalid folder path '{assetsPath}'."); + + if (!AssetDatabase.IsValidFolder(parent)) + CreateFolderRecursive(parent); + + AssetDatabase.CreateFolder(parent, name); + } + + /// Build the canonical identity envelope for a scene asset path. + private static AuthoringResult DescribeSceneAsset(string scenePath) + { + var asset = AssetDatabase.LoadAssetAtPath(scenePath); + var result = ObjectResolver.Describe(asset) ?? new AuthoringResult { Type = nameof(SceneAsset) }; + result.AssetPath = scenePath; + return result; + } + + /// Enumerate every open scene (loaded or not) by index. + private static IEnumerable OpenScenes() + { + for (int i = 0; i < SceneManager.sceneCount; i++) + yield return SceneManager.GetSceneAt(i); + } + + /// Find an open scene by its (normalized) asset path. Returns an invalid Scene when not open. + private static Scene FindOpenScene(string normalizedPath) + { + foreach (var scene in OpenScenes()) + { + if (PathsEqual(scene.path, normalizedPath)) + return scene; + } + + return default; + } + + private static bool PathsEqual(string a, string b) => + string.Equals(a, b, StringComparison.OrdinalIgnoreCase); + + private static SceneHierarchyNode BuildNode(GameObject go, string hierarchyPath) + { + var node = new SceneHierarchyNode + { + Name = go.name, + InstanceId = PipelineUtils.GetObjectId(go), + HierarchyPath = hierarchyPath, + ActiveSelf = go.activeSelf, + Components = go.GetComponents() + // A missing/broken script serializes as a null component; skip it rather than NRE. + .Where(c => c != null) + .Select(c => c.GetType().Name) + .ToList() + }; + + var transform = go.transform; + for (int i = 0; i < transform.childCount; i++) + { + var child = transform.GetChild(i).gameObject; + node.Children.Add(BuildNode(child, hierarchyPath + "/" + child.name)); + } + + return node; + } + + #endregion + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scenes/SceneCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scenes/SceneCommands.cs.meta new file mode 100644 index 0000000..94e4e99 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scenes/SceneCommands.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 2c7b859adf794e05969586b070d0ab79 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scenes/SceneHierarchy.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scenes/SceneHierarchy.cs new file mode 100644 index 0000000..be87333 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scenes/SceneHierarchy.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Unity.Pipeline.Editor.Commands.Scenes +{ + /// + /// Serializable snapshot of an open scene's GameObject tree, returned by + /// get_scene_hierarchy. + /// + /// WHY a dedicated tree type (rather than reusing ): + /// the hierarchy is meant to be the *input* to GameObject-targeting commands. Every node carries + /// a stable and a , + /// either of which is directly accepted by + /// / . + /// That lets an agent fetch the tree once and then address any node without a second round-trip. + /// The shape is kept intentionally small and JSON-friendly (no UnityEngine references) so it + /// survives the HTTP boundary cleanly. + /// + [Serializable] + class SceneHierarchy + { + /// Scene name (the file name without extension for a saved scene). + [JsonProperty("sceneName")] + public string SceneName { get; set; } + + /// Project-relative scene asset path, or empty for an unsaved scene. + [JsonProperty("scenePath")] + public string ScenePath { get; set; } + + /// Whether this scene currently has unsaved changes. + [JsonProperty("isDirty")] + public bool IsDirty { get; set; } + + /// Whether this scene is the active scene. + [JsonProperty("isActive")] + public bool IsActive { get; set; } + + /// Root GameObjects of the scene, each with their descendants. + [JsonProperty("roots")] + public List Roots { get; set; } = new List(); + } + + /// + /// One GameObject node in a , with enough identity to be used as an + /// handle (instanceId or hierarchyPath) by + /// follow-up GameObject commands. + /// + [Serializable] + class SceneHierarchyNode + { + /// GameObject name. + [JsonProperty("name")] + public string Name { get; set; } + + /// + /// Runtime instance id of the GameObject. Stable for the lifetime of the loaded scene and + /// directly usable as ObjectRef.instanceId. + /// + [JsonProperty("instanceId")] + public ObjectId InstanceId { get; set; } + + /// + /// Slash-delimited scene path (e.g. "/Root/Child/Leaf"), directly usable as + /// ObjectRef.hierarchyPath. + /// + [JsonProperty("hierarchyPath")] + public string HierarchyPath { get; set; } + + /// Whether the GameObject is active in the hierarchy. + [JsonProperty("activeSelf")] + public bool ActiveSelf { get; set; } + + /// Component type names attached to this GameObject (e.g. "Transform", "Camera"). + [JsonProperty("components")] + public List Components { get; set; } = new List(); + + /// Child nodes. + [JsonProperty("children")] + public List Children { get; set; } = new List(); + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scenes/SceneHierarchy.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scenes/SceneHierarchy.cs.meta new file mode 100644 index 0000000..5c3d820 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scenes/SceneHierarchy.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a93c6751c9564baca2addf1deb479da4 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ScreenshotCommand.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ScreenshotCommand.cs new file mode 100644 index 0000000..8be4637 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ScreenshotCommand.cs @@ -0,0 +1,198 @@ +using System; +using System.Globalization; +using System.IO; +using Newtonsoft.Json; +using Unity.Pipeline.Commands; +using UnityEditor; +using UnityEngine; + +namespace Unity.Pipeline.Editor.Commands +{ + /// + /// Captures the Scene or Game view of a running Editor as a PNG and returns the file path. + /// Backs the unity screenshot CLI command (CLI-112): the CLI only forwards the request + /// via unity request screenshot — all capture logic lives here in the package, per the + /// two-commands design. + /// + /// Capture renders the relevant view camera into an offscreen RenderTexture and reads it back, + /// rather than using ScreenCapture.CaptureScreenshot. CaptureScreenshot only targets the Game + /// view and writes asynchronously on the next frame — a single request/response can't reliably + /// wait for that, and it does nothing for the Scene view in edit mode. Camera.Render() into a + /// RenderTexture is synchronous, needs no play mode, and handles both views identically. + /// + static class ScreenshotCommand + { + const int k_DefaultWidth = 1920; + const int k_DefaultHeight = 1080; + + [CliCommand("screenshot", "Capture the Scene or Game view as a PNG and return its file path", MainThreadRequired = true, Tags = new[] { "capture" })] + public static ScreenshotResponse CaptureScreenshot( + [CliArg("view", "Which view to capture: 'game' (default) or 'scene'")] string view = "game", + [CliArg("output", "Output PNG path (absolute, or relative to the project root). Defaults to a timestamped file under /Temp/pipeline-screenshots/.")] string output = "", + [CliArg("width", "Output width in pixels. 0 (default) uses the view camera's current width.")] int width = 0, + [CliArg("height", "Output height in pixels. 0 (default) uses the view camera's current height.")] int height = 0) + { + var normalizedView = string.IsNullOrWhiteSpace(view) ? "game" : view.Trim().ToLowerInvariant(); + if (normalizedView != "game" && normalizedView != "scene") + return ScreenshotResponse.Fail($"Invalid view '{view}'. Expected 'game' or 'scene'."); + + if (width < 0 || height < 0) + return ScreenshotResponse.Fail("width and height must be >= 0 (0 = use the view's current size)."); + + var camera = ResolveCamera(normalizedView, out var resolveError); + if (camera == null) + return ScreenshotResponse.Fail(resolveError); + + // Default the size to the camera's current pixel size, falling back to 1080p when the + // camera reports nothing useful (can happen for an off-screen scene camera). + var w = width > 0 ? width : camera.pixelWidth; + var h = height > 0 ? height : camera.pixelHeight; + if (w <= 1) w = k_DefaultWidth; + if (h <= 1) h = k_DefaultHeight; + + var path = ResolveOutputPath(output, normalizedView); + + try + { + var png = RenderToPng(camera, w, h); + var dir = Path.GetDirectoryName(path); + if (!string.IsNullOrEmpty(dir)) + Directory.CreateDirectory(dir); + File.WriteAllBytes(path, png); + } + catch (Exception ex) + { + return ScreenshotResponse.Fail($"Failed to capture {normalizedView} view: {ex.Message}"); + } + + return new ScreenshotResponse + { + Success = true, + Path = path, + View = normalizedView, + Width = w, + Height = h, + Message = $"Captured {normalizedView} view to {path}" + }; + } + + /// + /// Resolve the camera to render for the requested view, or null with an explanatory error. + /// + static Camera ResolveCamera(string view, out string error) + { + error = null; + + if (view == "scene") + { + var sv = SceneView.lastActiveSceneView; + if (sv == null || sv.camera == null) + { + error = "No active Scene view to capture. Open a Scene view window and try again."; + return null; + } + return sv.camera; + } + + // Game view: prefer the main camera, otherwise the first enabled camera in the open scenes. + var cam = Camera.main; + if (cam == null && Camera.allCamerasCount > 0) + { + var all = Camera.allCameras; + if (all.Length > 0) + cam = all[0]; + } + + if (cam == null) + error = "No camera found to capture the Game view (no MainCamera and no enabled cameras in the open scenes)."; + + return cam; + } + + /// + /// Render into an offscreen RenderTexture at the given size and + /// encode it to PNG. Restores the camera's previous target and the active RenderTexture so + /// the capture leaves no side effects on the live editor. + /// + static byte[] RenderToPng(Camera camera, int width, int height) + { + var rt = new RenderTexture(width, height, 24); + var prevTarget = camera.targetTexture; + var prevActive = RenderTexture.active; + Texture2D tex = null; + + try + { + camera.targetTexture = rt; + camera.Render(); + + RenderTexture.active = rt; + tex = new Texture2D(width, height, TextureFormat.RGB24, false); + tex.ReadPixels(new Rect(0, 0, width, height), 0, 0); + tex.Apply(); + + return tex.EncodeToPNG(); + } + finally + { + camera.targetTexture = prevTarget; + RenderTexture.active = prevActive; + rt.Release(); + UnityEngine.Object.DestroyImmediate(rt); + if (tex != null) + UnityEngine.Object.DestroyImmediate(tex); + } + } + + /// + /// Resolve the output path: an explicit path is used as-is (rooted) or relative to the + /// project root; an empty path defaults to a timestamped file under Temp. + /// + static string ResolveOutputPath(string output, string view) + { + var projectRoot = Path.GetDirectoryName(Application.dataPath); + + if (!string.IsNullOrWhiteSpace(output)) + { + return Path.IsPathRooted(output) + ? output + : Path.GetFullPath(Path.Combine(projectRoot, output)); + } + + var stamp = DateTime.Now.ToString("yyyyMMdd_HHmmss_fff", CultureInfo.InvariantCulture); + return Path.Combine(projectRoot, "Temp", "pipeline-screenshots", $"screenshot_{view}_{stamp}.png"); + } + } + + /// + /// Result of the screenshot command. Serialized to JSON for the CLI's --format json + /// output; the human formatter reads . + /// + [Serializable] + class ScreenshotResponse + { + [JsonProperty("success")] + public bool Success { get; set; } + + [JsonProperty("path")] + public string Path { get; set; } + + [JsonProperty("view")] + public string View { get; set; } + + [JsonProperty("width")] + public int Width { get; set; } + + [JsonProperty("height")] + public int Height { get; set; } + + [JsonProperty("message")] + public string Message { get; set; } + + public static ScreenshotResponse Fail(string message) => new ScreenshotResponse + { + Success = false, + Message = message + }; + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/ScreenshotCommand.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ScreenshotCommand.cs.meta new file mode 100644 index 0000000..1dcce16 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/ScreenshotCommand.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ee6b23eed8dc4ff096cf01b461985fcc diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts.meta new file mode 100644 index 0000000..5c91cfb --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c4d83f412a414f419f97bac28b65f25b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/AttachScriptCommand.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/AttachScriptCommand.cs new file mode 100644 index 0000000..7980803 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/AttachScriptCommand.cs @@ -0,0 +1,139 @@ +using System; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Models; +using UnityEditor; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace Unity.Pipeline.Editor.Commands.Scripts +{ + /// + /// Authoring command that adds a MonoBehaviour component to a GameObject, addressing the script + /// either by its (compiled) type name OR by its source asset path (CLI-195, CLI-224). + /// + /// COMPILE-AWARE: the type must already be compiled. A script created via create_script does not + /// have a compiled until a domain reload runs, so attaching it before that + /// fails with a CLEAR, RECOVERABLE error (no crash, no silent no-op) telling the agent to + /// recompile and retry. The full flow is: + /// create_script -> recompile -> poll recompile_status (completed/up_to_date) -> attach_script. + /// + /// Addressing by asset path resolves the backing class through + /// , which correctly handles a class whose name differs from + /// the filename. A path whose MonoScript has no class yet (not compiled, or no single matching + /// top-level type) surfaces the same recoverable "not yet compiled / ambiguous" error. + /// + /// The component add is wrapped in an and registered with the + /// Undo system so it reverts as one step and the owning object/prefab is marked dirty. + /// + static class AttachScriptCommand + { + [CliCommand("attach_script", + "Add a MonoBehaviour to a GameObject by its (compiled) type name OR by its script asset path. " + + "Provide exactly one of 'type' or 'script'. " + + "If the type isn't compiled yet, returns a recoverable error: recompile, poll recompile_status, then retry.", + Tags = new[] { "scripts" })] + public static AuthoringResult AttachScript( + [CliArg("target", "Reference to the GameObject to add the component to (globalId/path/guid/instanceId/hierarchyPath).", Required = true)] ObjectRef target, + [CliArg("type", "Component type name to add, e.g. PlayerController or Game.Player.PlayerController. Must already be compiled. Mutually exclusive with 'script'.")] string type = null, + [CliArg("script", "Script asset path, e.g. 'Assets/Pool/Scripts/CueShooter.cs'. The backing class is resolved via MonoScript.GetClass(), so the class name may differ from the filename. Mutually exclusive with 'type'.")] string script = null) + { + if (target == null || target.IsEmpty) + throw new ArgumentException("attach_script 'target' is required."); + + // Exactly one addressing form must be supplied. Both is ambiguous; neither is incomplete. + var hasType = !string.IsNullOrWhiteSpace(type); + var hasScript = !string.IsNullOrWhiteSpace(script); + if (hasType && hasScript) + throw new ArgumentException( + "Provide either 'type' (class name) or 'script' (asset path), not both."); + if (!hasType && !hasScript) + throw new ArgumentException( + "Provide either 'type' (class name) or 'script' (asset path)."); + + if (!ObjectResolver.TryResolve(target, out var obj, out var resolveError)) + throw new ArgumentException($"Could not resolve target: {resolveError}"); + + var go = obj as GameObject ?? (obj as Component)?.gameObject; + if (go == null) + throw new ArgumentException( + $"Target '{target}' resolved to a {obj.GetType().Name}, which is not a GameObject. " + + "attach_script needs a GameObject."); + + // Resolve the component Type from whichever addressing form was given. A type that exists but + // isn't compiled yet (or is the wrong kind) surfaces as InvalidOperationException so the + // server returns a 400 "Command Execution Failed" with the recovery instructions intact. + // ArgumentException is reserved for caller input mistakes — both/neither args, or a script + // path that points at no asset — which the server reports as "Parameter Validation Failed". + var componentType = hasScript + ? ResolveTypeFromScriptPath(script) + : ResolveTypeFromName(type); + + using (new AuthoringUndoScope($"Attach {componentType.Name}")) + { + // Undo.AddComponent registers the add for undo and returns the new component. + var component = Undo.AddComponent(go, componentType); + if (component == null) + throw new InvalidOperationException( + $"Failed to add component '{componentType.FullName}' to '{go.name}'. " + + "It may conflict with [DisallowMultipleComponent] or a required-component rule."); + + EditorUtility.SetDirty(go); + + var result = ObjectResolver.Describe(component) ?? new AuthoringResult { Type = componentType.Name }; + return result; + } + } + + /// + /// Resolve a component type by its compiled type name. A missing type is the expected, + /// recoverable "created but not yet compiled" case. + /// + private static Type ResolveTypeFromName(string type) + { + if (!ScriptTypeResolver.TryResolveComponentType(type, out var componentType, out var typeError)) + throw new InvalidOperationException(typeError); + + return componentType; + } + + /// + /// Resolve a component type from a script asset path. Loads the at the + /// path and resolves its backing class via — which correctly + /// handles a class whose name differs from the filename. Validates the class is a concrete + /// MonoBehaviour. A null class is the recoverable "not yet compiled / ambiguous" case and + /// mirrors the type-not-found message style. A path that resolves to no MonoScript asset is a + /// caller input mistake (ArgumentException → "Parameter Validation Failed"), not a recompile- + /// recoverable failure. + /// + private static Type ResolveTypeFromScriptPath(string path) + { + var trimmed = path.Trim(); + + var mono = AssetDatabase.LoadAssetAtPath(trimmed); + if (mono == null) + throw new ArgumentException( + $"No MonoScript at '{trimmed}'. Check the asset path (it should be a project-relative " + + "path to a .cs file, e.g. 'Assets/Scripts/PlayerController.cs')."); + + var cls = mono.GetClass(); + if (cls == null) + throw new InvalidOperationException( + $"Script at '{trimmed}' has no resolvable class. " + + "If you just created or edited this script it is not compiled yet: run 'recompile', poll " + + "'recompile_status' until it reports completed/up_to_date, then retry attach_script. " + + "If it should already exist, ensure the file has a single top-level type matching the " + + "script and that it compiled without errors."); + + if (!typeof(MonoBehaviour).IsAssignableFrom(cls)) + throw new InvalidOperationException( + $"Type '{cls.FullName}' (from '{trimmed}') does not derive from MonoBehaviour and cannot be added as a component."); + + if (cls.IsAbstract) + throw new InvalidOperationException( + $"Type '{cls.FullName}' (from '{trimmed}') is abstract and cannot be instantiated as a component."); + + return cls; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/AttachScriptCommand.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/AttachScriptCommand.cs.meta new file mode 100644 index 0000000..2c4aca0 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/AttachScriptCommand.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 488a53ecbf5c4984bdc009bf1f2f9a45 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/CreateScriptCommand.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/CreateScriptCommand.cs new file mode 100644 index 0000000..9a1c690 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/CreateScriptCommand.cs @@ -0,0 +1,164 @@ +using System; +using System.IO; +using System.Text; +using System.Text.RegularExpressions; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Models; +using UnityEditor; + +namespace Unity.Pipeline.Editor.Commands.Scripts +{ + /// + /// Authoring command that writes a new C# MonoBehaviour (or other base-class) script from a + /// template into the project under the authoring root (CLI-195). + /// + /// IMPORTANT — the compile/domain-reload boundary: + /// Writing a .cs file does NOT make the type available. Unity must import and compile the new + /// file, which triggers a domain reload, before the type exists and can be attached. The agent + /// workflow is therefore: + /// 1. create_script (this command — writes the file) + /// 2. recompile (triggers compilation; see ) + /// 3. poll recompile_status (wait until "completed" / "up_to_date") + /// 4. attach_script (now the type exists; see ) + /// This command intentionally does its part only: it creates the file and returns the asset + /// identity. It does not trigger a recompile itself — the agent owns that step so it can batch + /// multiple authoring writes before paying the domain-reload cost once. + /// + static class CreateScriptCommand + { + /// + /// Default class body (the Start/Update stubs) written inside the generated class, matching + /// Unity's own new-MonoBehaviour template so the output reads like a hand-authored script. + /// wraps it with the using/class declaration and an optional namespace. + /// + private const string DefaultBody = + " // Use this for initialization\n" + + " void Start()\n" + + " {\n\n" + + " }\n\n" + + " // Update is called once per frame\n" + + " void Update()\n" + + " {\n\n" + + " }\n"; + + [CliCommand("create_script", + "Create a new C# script (default base class MonoBehaviour) from a template under the authoring root. " + + "NOTE: the type does not exist until a recompile completes — to attach it, call recompile, poll recompile_status, then attach_script.", + Tags = new[] { "scripts" })] + public static AuthoringResult CreateScript( + [CliArg("name", "Class/file name without extension, e.g. PlayerController. Must be a valid C# identifier.", Required = true)] string name, + [CliArg("path", "Folder (relative to the authoring root; the Assets/ prefix is optional) to write the .cs into. Defaults to the authoring root.")] string path = null, + [CliArg("namespace", "Optional namespace to wrap the class in. Omit for the global namespace.")] string @namespace = null, + [CliArg("base_class", "Base class to derive from. Defaults to MonoBehaviour.")] string baseClass = "MonoBehaviour", + [CliArg("overwrite", "Overwrite the file if it already exists. Defaults to false (an existing file is an error).")] bool overwrite = false) + { + if (string.IsNullOrWhiteSpace(name)) + throw new ArgumentException("Script 'name' is required."); + + var className = name.Trim(); + if (className.EndsWith(".cs", StringComparison.OrdinalIgnoreCase)) + className = className.Substring(0, className.Length - 3); + + if (!IsValidIdentifier(className)) + throw new ArgumentException($"Script name '{className}' is not a valid C# class identifier."); + + if (string.IsNullOrWhiteSpace(baseClass)) + baseClass = "MonoBehaviour"; + + // Resolve & sandbox the destination folder through the project-path policy. A null/empty + // path means "the authoring root itself" — Resolve treats an empty path as an error, so + // fall back to the configured root in that case (it is already a confined, valid path). + string folder; + if (string.IsNullOrWhiteSpace(path)) + { + folder = ProjectPaths.AuthoringRoot; + } + else + { + folder = ProjectPaths.Resolve(path, out var error); + if (folder == null) + throw new ArgumentException(error); + } + + if (!AssetDatabase.IsValidFolder(folder)) + throw new ArgumentException( + $"Destination folder '{folder}' does not exist. Create it first with create_folder."); + + var assetPath = $"{folder}/{className}.cs"; + if (File.Exists(ToAbsolute(assetPath)) && !overwrite) + throw new ArgumentException( + $"A script already exists at '{assetPath}'. Pass overwrite=true to replace it."); + + var source = BuildSource(className, @namespace, baseClass); + + // Write through the filesystem then import: AssetDatabase has no "create text asset" API, + // and CreateAsset is for UnityEngine.Object instances, not source files. + File.WriteAllText(ToAbsolute(assetPath), source, new UTF8Encoding(false)); + AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate); + + // The MonoScript may already be loadable (its asset entry exists), but its compiled Type + // will not exist until the next domain reload — see the class doc. + var script = AssetDatabase.LoadAssetAtPath(assetPath); + var result = ObjectResolver.Describe(script) ?? new AuthoringResult { Type = "MonoScript" }; + result.AssetPath = assetPath; + return result; + } + + /// + /// Build the script source from the template, substituting the class name, optional namespace + /// and base class. When a namespace is supplied the class body is indented one extra level. + /// + private static string BuildSource(string className, string @namespace, string baseClass) + { + var usings = "using UnityEngine;\n\n"; + var classDecl = $"public class {className} : {baseClass}\n"; + + var sb = new StringBuilder(); + sb.Append(usings); + + if (!string.IsNullOrWhiteSpace(@namespace)) + { + sb.Append($"namespace {@namespace}\n{{\n"); + sb.Append(Indent(classDecl, " ")); + sb.Append(" {\n"); + sb.Append(Indent(DefaultBody, " ")); + sb.Append(" }\n"); + sb.Append("}\n"); + } + else + { + sb.Append(classDecl); + sb.Append("{\n"); + sb.Append(DefaultBody); + sb.Append("}\n"); + } + + return sb.ToString(); + } + + private static string Indent(string text, string prefix) + { + var sb = new StringBuilder(); + foreach (var line in text.Split('\n')) + sb.Append(line.Length == 0 ? "\n" : prefix + line + "\n"); + // Split adds a trailing empty element for a trailing newline; trim the extra newline we + // appended for it. + if (text.EndsWith("\n") && sb.Length > 0) + sb.Length -= 1; + return sb.ToString(); + } + + private static bool IsValidIdentifier(string value) + { + // A C# identifier: starts with a letter or underscore, then letters/digits/underscores. + return Regex.IsMatch(value, @"^[A-Za-z_][A-Za-z0-9_]*$"); + } + + private static string ToAbsolute(string assetPath) + { + // assetPath is project-relative ("Assets/..."); ProjectRoot is the folder containing Assets/. + return Path.Combine(ProjectPaths.ProjectRoot, assetPath).Replace('\\', '/'); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/CreateScriptCommand.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/CreateScriptCommand.cs.meta new file mode 100644 index 0000000..8884c31 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/CreateScriptCommand.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 34d285de0757475796fcecc889996421 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/RunScriptCommand.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/RunScriptCommand.cs new file mode 100644 index 0000000..6e2407c --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/RunScriptCommand.cs @@ -0,0 +1,664 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Compilation; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Models; +using Unity.Pipeline.Runtime.Commands; +using UnityEditor; +using UnityEngine; +using Debug = UnityEngine.Debug; +using Object = UnityEngine.Object; + +namespace Unity.Pipeline.Editor.Commands.Scripts +{ + /// + /// The run_script command (AUTHAPI-26): compile a single project .cs file in memory + /// via the shared and execute a NAMED static entry point — + /// with NO domain reload and NO code carried through the protocol. This formalizes the + /// "builder pattern": bulk construction lives in a versioned project script that is written to + /// disk (ideally OUTSIDE Assets/, so writing it triggers no asset import / domain reload) + /// and invoked here by name, instead of shipping escaped C# strings through eval. + /// + /// It composes the two halves the pipeline already had — eval_file (code from disk) and + /// reload_file (single-file in-memory Roslyn compile) — into one first-class command: + /// - ephemeral (default): compile to an in-memory assembly, run the entry point, discard. + /// - hotpatch: delegate to reload_file's in-place [CodeReload] semantics. + /// + /// This is still arbitrary code execution — only the carrier changes (a reviewable file on disk + /// instead of a protocol string). It is grouped under the same scripts/eval tag as + /// eval so a host that disables the eval family disables this too. + /// + static class RunScriptCommand + { + /// Upper bound on a single run's timeout — 24 hours, matching the eval cap (CLI-335). + private const int MaxTimeoutMs = 86_400_000; + + [CliCommand("run_script", + "Compile a project C# file in memory (no domain reload) and execute a named static entry point. " + + "The builder-pattern path for bulk construction. Still arbitrary code execution — shares eval's capability gate.", + MainThreadRequired = true, Tags = new[] { "scripts/eval" })] + public static async Task RunScript( + [CliArg("file", "Path to a .cs file to compile. Relative paths resolve against the PROJECT ROOT (the parent of Assets/), not the process working directory. May live OUTSIDE Assets/ (e.g. AgentScripts/) so writing it never triggers an asset import or domain reload.", Required = true)] string file, + [CliArg("entry", "Entry point as Namespace.Type.Method (or Type.Method, or a bare Method name). Default: the single public static method if unambiguous, else a method named Main. Static methods only in v1. Ephemeral mode only (rejected with mode=hotpatch, which never invokes an entry point).")] string entry = null, + [CliArg("args", "JSON array of arguments passed to the entry point, coerced to its parameter types: primitives, enum names, string[], and a string/object handle (ObjectRef) for UnityEngine.Object parameters. Ephemeral mode only (rejected with mode=hotpatch).")] JArray args = null, + [CliArg("mode", "ephemeral (default): compile to an in-memory assembly, run the entry, discard. hotpatch: apply [CodeReload] method replacements to already-loaded types (reload_file semantics).")] string mode = "ephemeral", + [CliArg("references", "Extra assembly name prefixes to reference beyond the auto-resolved set. In the Editor all loaded assemblies are already referenced, so this is effectively a no-op there. Ephemeral mode only; not applied by hotpatch (which delegates to reload_file's own compile).")] string[] references = null, + [CliArg("defines", "Extra scripting define symbols APPENDED to the project's active editor defines (UNITY_EDITOR etc. are already set) for the compilation's #if directives. Ephemeral mode only; not applied by hotpatch.")] string[] defines = null, + [CliArg("pdb", "Emit a portable PDB mapped to the source file so breakpoints bind and exception stack traces map to file:line. Compiles unoptimized.")] bool pdb = false, + [CliArg("timeout_ms", "Timeout in milliseconds. Bounds the main-thread dispatcher wait AND, for an async entry point, how long its Task is awaited (on expiry the task keeps running detached).")] int timeoutMs = 30000, + [CliArg("dry_run", "Compile only: return diagnostics; the emitted assembly is NOT loaded into the domain and nothing executes. Ephemeral mode only (rejected with mode=hotpatch, which would apply live method replacements).")] bool dryRun = false) + { + var total = Stopwatch.StartNew(); + + if (string.IsNullOrWhiteSpace(file)) + return RunScriptResponse.Fail("Bad Request", "The 'file' parameter is required and cannot be empty.", total.ElapsedMilliseconds); + + if (!file.EndsWith(".cs", StringComparison.OrdinalIgnoreCase)) + return RunScriptResponse.Fail("Bad Request", "The 'file' must have a .cs extension.", total.ElapsedMilliseconds); + + if (timeoutMs <= 0 || timeoutMs > MaxTimeoutMs) + return RunScriptResponse.Fail("Bad Request", $"'timeout_ms' must be between 1 and {MaxTimeoutMs}.", total.ElapsedMilliseconds); + + var normalizedMode = (mode ?? "ephemeral").Trim().ToLowerInvariant(); + + try + { + switch (normalizedMode) + { + case "ephemeral": + return await RunEphemeral(file, entry, args, references, defines, pdb, dryRun, timeoutMs, total); + case "hotpatch": + { + // hotpatch delegates wholesale to reload_file's [CodeReload] semantics: + // nothing is invoked, so entry/args are meaningless, and there is no + // compile-only path — a "dry run" would still apply live method + // replacements. Reject rather than silently ignore or, worse, apply. + if (dryRun) + { + return RunScriptResponse.Fail("Bad Request", + "'dry_run' is not supported with mode=hotpatch; it would apply live method replacements. " + + "Use mode=ephemeral (the default) for a compile-only check.", + total.ElapsedMilliseconds); + } + + var unsupported = new List(); + if (!string.IsNullOrWhiteSpace(entry)) unsupported.Add("'entry'"); + if (args != null && args.Count > 0) unsupported.Add("'args'"); + if (unsupported.Count > 0) + { + return RunScriptResponse.Fail("Bad Request", + $"{string.Join(" and ", unsupported)} {(unsupported.Count == 1 ? "is" : "are")} not supported with mode=hotpatch: " + + "it applies [CodeReload] method replacements in place and never invokes an entry point. " + + "Use mode=ephemeral to run an entry point.", + total.ElapsedMilliseconds); + } + + return RunHotpatch(file, pdb, timeoutMs, total); + } + default: + return RunScriptResponse.Fail("Bad Request", $"Unknown mode '{mode}'. Expected 'ephemeral' or 'hotpatch'.", total.ElapsedMilliseconds); + } + } + catch (Exception ex) + { + Debug.LogError($"Pipeline: run_script failed: {ex}"); + return RunScriptResponse.Fail("Execution Failed", ex.ToString(), total.ElapsedMilliseconds); + } + } + + /// + /// ephemeral mode: single-file in-memory compile → resolve the entry point → coerce args → + /// invoke → serialize. No AssetDatabase.Refresh and no domain reload occur. Async so + /// a Task-returning entry point can be awaited without blocking the main thread (see the + /// comment at the await); bounds that wait. + /// + private static async Task RunEphemeral( + string file, string entry, JArray args, string[] references, string[] defines, bool pdb, bool dryRun, int timeoutMs, Stopwatch total) + { + // Resolve the path: absolute as-is, else relative to the PROJECT ROOT (the parent of + // Assets/) — NOT the process working directory, which is usually but not guaranteed to + // be the project root. This deliberately accepts files outside Assets/. (hotpatch mode + // intentionally keeps reload_file's own resolution, which probes under Assets/.) + var projectRoot = Directory.GetParent(Application.dataPath)?.FullName ?? Directory.GetCurrentDirectory(); + var fullPath = Path.GetFullPath(Path.IsPathRooted(file) ? file : Path.Combine(projectRoot, file)); + if (!File.Exists(fullPath)) + return RunScriptResponse.Fail("File Not Found", $"Source file not found: {fullPath}", total.ElapsedMilliseconds); + + string source; + try + { + source = File.ReadAllText(fullPath); + } + catch (Exception ex) + { + return RunScriptResponse.Fail("Bad Request", $"Failed to read file: {ex.Message}", total.ElapsedMilliseconds); + } + + if (string.IsNullOrWhiteSpace(source)) + return RunScriptResponse.Fail("Bad Request", $"File is empty: {fullPath}", total.ElapsedMilliseconds); + + var assemblyName = $"PipelineRunScript_{Path.GetFileNameWithoutExtension(fullPath)}_{Guid.NewGuid():N}"; + + // Emit symbols mapped to the source file whenever we are going to execute, so that + // exception stack traces (and, with an attached debugger, breakpoints) map back to + // file:line in the original .cs. dry_run only needs symbols when explicitly requested. + var emitDebug = pdb || !dryRun; + + // Seed the compile with the project's ACTIVE editor defines (UNITY_EDITOR, the + // UNITY_ symbols, platform defines, project scripting symbols, …) so the + // source's #if directives behave like project code. The user's `defines` extend that + // set; they do not replace it. + var activeDefines = EditorUserBuildSettings.activeScriptCompilationDefines; + var effectiveDefines = defines == null || defines.Length == 0 + ? activeDefines + : activeDefines.Concat(defines).Distinct().ToArray(); + + var compileSw = Stopwatch.StartNew(); + var compilation = RoslynCompilationService.Compile(new CompilationRequest + { + SourceCode = source, + AssemblyName = assemblyName, + EmitDebugInformation = emitDebug, + DocumentPath = fullPath, + AdditionalAssemblyPrefixes = references, + PreprocessorSymbols = effectiveDefines, + // dry_run never executes, so don't load the emitted assembly into the domain — + // in-memory assemblies are not unloadable under Mono and would leak per call. + SkipLoad = dryRun + }); + compileSw.Stop(); + + if (!compilation.Success) + { + return RunScriptResponse.Fail( + "Compilation Failed", + "The script failed to compile. See diagnostics for line/column details.", + total.ElapsedMilliseconds, + compilation.Diagnostics, + compileSw.ElapsedMilliseconds, + 0, + assemblyName); + } + + if (dryRun) + { + // Emit-only: no assembly was loaded, so there is no assemblyName to report. + var dr = RunScriptResponse.Ok(null, null, compileSw.ElapsedMilliseconds, 0, total.ElapsedMilliseconds, compilation.Diagnostics); + dr.Message = "Compiled successfully (dry run; nothing was loaded or executed)."; + return dr; + } + + // Resolve the entry point. + var method = ResolveEntryPoint(compilation.Assembly, entry, Path.GetFileName(fullPath), out var entryError); + if (method == null) + { + return RunScriptResponse.Fail("Entry Point Not Found", entryError, total.ElapsedMilliseconds, + compilation.Diagnostics, compileSw.ElapsedMilliseconds, 0, assemblyName); + } + + // Coerce JSON args to the entry point's parameter types. + if (!TryCoerceArguments(method, args, out var callArgs, out var argError)) + { + return RunScriptResponse.Fail("Bad Request", argError, total.ElapsedMilliseconds, + compilation.Diagnostics, compileSw.ElapsedMilliseconds, 0, assemblyName); + } + + // Execute. + var execSw = Stopwatch.StartNew(); + object returnValue = null; + try + { + returnValue = method.Invoke(null, callArgs); + + // A Task/Task-returning entry point must be awaited — otherwise the call + // reports success the moment the first await yields, and any exception in the + // async work is never observed. Awaited ASYNCHRONOUSLY (never a blocking + // GetResult()): this command runs on the main thread, and an entry point's awaits + // resume on the Unity SynchronizationContext — i.e. this same thread — so a + // blocking wait here deadlocks the whole Editor permanently. Awaiting instead + // returns control to the editor loop at this point (the server unwraps the + // command's own Task off the main thread), letting those continuations pump. + // The wait is bounded by what remains of timeout_ms; on expiry the task keeps + // running detached, like an abandoned eval. Task exposes Result via reflection + // (an `async Task` materializes as Task, whose Result carries no + // value — treat it as null). + if (returnValue is Task task) + { + var remainingMs = (int)Math.Max(0, timeoutMs - total.ElapsedMilliseconds); + var completed = await Task.WhenAny(task, Task.Delay(remainingMs)); + if (completed != task) + { + execSw.Stop(); + return RunScriptResponse.Fail( + "Timeout", + $"The entry point's Task did not complete within the {timeoutMs}ms budget " + + $"({remainingMs}ms remained after the synchronous part). The task keeps running detached and " + + "its effects may still land; raise timeout_ms if it legitimately needs longer.", + total.ElapsedMilliseconds, + compilation.Diagnostics, + compileSw.ElapsedMilliseconds, + execSw.ElapsedMilliseconds, + assemblyName); + } + + await task; // a faulted task throws the entry point's own exception here + var resultProperty = task.GetType().GetProperty("Result"); + returnValue = resultProperty != null && resultProperty.PropertyType.FullName != "System.Threading.Tasks.VoidTaskResult" + ? resultProperty.GetValue(task) + : null; + } + } + catch (Exception ex) when (ex is TargetInvocationException || returnValue is Task) + { + execSw.Stop(); + // Reflection wraps a synchronous throw in a TargetInvocationException; a faulted + // task rethrows the entry point's own exception from the await. Normalize both + // to the entry point's exception. With the PDB emitted above and DocumentPath set + // to the source file, the stack trace carries "... in :line ", so the + // failure maps back to the original source. + var inner = (ex as TargetInvocationException)?.InnerException ?? ex; + return RunScriptResponse.Fail( + "Runtime Error", + $"{inner.GetType().Name}: {inner.Message}\n{inner.StackTrace}", + total.ElapsedMilliseconds, + compilation.Diagnostics, + compileSw.ElapsedMilliseconds, + execSw.ElapsedMilliseconds, + assemblyName); + } + execSw.Stop(); + + return RunScriptResponse.Ok( + SerializeResult(returnValue), + assemblyName, + compileSw.ElapsedMilliseconds, + execSw.ElapsedMilliseconds, + total.ElapsedMilliseconds, + compilation.Diagnostics); + } + + /// + /// hotpatch mode: apply in-place [CodeReload] method replacements to already-loaded + /// types, delegating to the existing reload_file command so its behavior/tests are + /// preserved. The result is re-shaped into a . + /// + private static RunScriptResponse RunHotpatch(string file, bool pdb, int timeoutMs, Stopwatch total) + { + var hr = CodeReloadCommands.ReloadFile(file, timeoutMs, null, pdb); + + // reload_file reports a single duration for the whole reload (compile + apply); surface + // it as executeMs rather than mislabeling it compile time. compileMs stays 0 here. + var reloadMs = hr.ExecutionTimeMs ?? 0L; + + if (hr.Success) + { + // reload_file can succeed with advisory diagnostics (e.g. partially-skipped + // overrides) — keep them, as "warning" entries in the same shape the failure + // path uses, instead of dropping them on the floor. + var warnings = (hr.Diagnostics ?? new List()) + .Select(d => new DiagnosticInfo { Severity = "warning", Message = d }) + .ToList(); + var ok = RunScriptResponse.Ok(hr.Items, hr.AssemblyName, 0, reloadMs, total.ElapsedMilliseconds, warnings); + ok.Message = hr.Message; + return ok; + } + + var diagnostics = (hr.Diagnostics ?? new List()) + .Select(d => new DiagnosticInfo { Severity = "error", Message = d }) + .ToList(); + return RunScriptResponse.Fail(hr.Error ?? "Code Reload Failed", hr.ErrorDetails, total.ElapsedMilliseconds, + diagnostics, 0, reloadMs, hr.AssemblyName); + } + + /// + /// Resolve the static entry method from a compiled assembly. + /// - "Namespace.Type.Method" / "Type.Method": split on the last dot; find the type, then the + /// static method by name (public or non-public). Nested types may be written with dots + /// ("Outer.Inner.Method") — the '+' reflection form is retried automatically. + /// - bare "Method": the single static method with that name across all types. + /// - null/empty: the single public static method if unambiguous, else a method named "Main". + /// Generic methods are never candidates (no type arguments to close them with). + /// Returns null and sets when it cannot resolve unambiguously. + /// + private static MethodInfo ResolveEntryPoint(Assembly assembly, string entry, string fileName, out string error) + { + error = null; + + // Skip compiler-generated types (e.g. ). + var types = assembly.GetTypes().Where(t => !t.Name.Contains("<") && !t.Name.Contains(">")).ToArray(); + + const BindingFlags AnyStatic = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly; + const BindingFlags PublicStatic = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly; + + if (!string.IsNullOrWhiteSpace(entry)) + { + entry = entry.Trim(); + var lastDot = entry.LastIndexOf('.'); + + if (lastDot > 0) + { + var typeName = entry.Substring(0, lastDot); + var methodName = entry.Substring(lastDot + 1); + + var type = assembly.GetType(typeName) + ?? types.FirstOrDefault(t => t.FullName == typeName || t.Name == typeName); + if (type == null && typeName.IndexOf('.') >= 0) + { + // Nested types use '+' in reflection names ("Outer+Inner"), while callers + // naturally write dots ("Outer.Inner.Method"). Retry with the last dot of + // the type part replaced. + var nestedDot = typeName.LastIndexOf('.'); + var nestedName = typeName.Substring(0, nestedDot) + "+" + typeName.Substring(nestedDot + 1); + type = assembly.GetType(nestedName) + ?? types.FirstOrDefault(t => t.FullName == nestedName); + } + if (type == null) + { + error = $"No type '{typeName}' in compiled file '{fileName}'. Types: [{string.Join(", ", types.Select(t => t.FullName))}]."; + return null; + } + + var named = type + .GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static) + .Where(m => m.Name == methodName && !m.IsSpecialName) + .ToList(); + var candidates = named.Where(m => !m.ContainsGenericParameters).ToList(); + if (candidates.Count == 1) + return candidates[0]; + if (candidates.Count > 1) + { + error = $"Entry '{entry}' is overloaded ({candidates.Count} static overloads); overloaded entry points are not supported in v1."; + return null; + } + if (named.Count > 0) + { + error = $"Entry '{entry}' only resolves to generic method(s); generic entry points are not supported."; + return null; + } + + var instance = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) + .FirstOrDefault(m => m.Name == methodName && !m.IsSpecialName); + error = instance != null + ? $"Entry '{entry}' is an instance method; only static methods are supported in v1." + : $"No static method '{methodName}' on type '{type.FullName}'."; + return null; + } + + // Bare method name — search every type for a static method with that name. + var byNameAll = types.SelectMany(t => t.GetMethods(AnyStatic)) + .Where(m => m.Name == entry && !m.IsSpecialName) + .ToList(); + var byName = byNameAll.Where(m => !m.ContainsGenericParameters).ToList(); + if (byName.Count == 1) + return byName[0]; + if (byName.Count == 0) + { + error = byNameAll.Count > 0 + ? $"Static method '{entry}' in '{fileName}' is generic; generic entry points are not supported." + : $"No static method named '{entry}' found in '{fileName}'."; + return null; + } + + error = $"Multiple static methods named '{entry}' found in '{fileName}'; qualify the entry as Namespace.Type.Method."; + return null; + } + + // No entry specified — auto-detect. Generic methods can't be invoked without type + // arguments, so they are never entry-point candidates. + var publicStatic = types.SelectMany(t => t.GetMethods(PublicStatic)) + .Where(m => !m.IsSpecialName && !m.ContainsGenericParameters) + .ToList(); + + if (publicStatic.Count == 1) + return publicStatic[0]; + + var mains = types.SelectMany(t => t.GetMethods(AnyStatic)) + .Where(m => m.Name == "Main" && !m.IsSpecialName && !m.ContainsGenericParameters) + .ToList(); + if (mains.Count == 1) + return mains[0]; + + if (publicStatic.Count == 0) + { + error = $"No public static entry point found in '{fileName}'. Add a public static method or specify 'entry'."; + return null; + } + + error = $"Ambiguous entry point in '{fileName}': {publicStatic.Count} public static methods and no unique 'Main'. " + + $"Specify 'entry' as Namespace.Type.Method. Candidates: [{string.Join(", ", publicStatic.Select(m => (m.DeclaringType?.FullName ?? "?") + "." + m.Name))}]."; + return null; + } + + /// + /// Coerce the JSON array to the entry point's parameter types using + /// the shared converters: primitives / enum names / string[] via Newtonsoft, and a + /// string-or-object handle ( + ) for + /// UnityEngine.Object parameters. Omitted trailing args fall back to C# default values. + /// An explicit JSON null is only valid for reference-type and Nullable<T> parameters — + /// for a non-nullable value type it is a coercion error, never a silent default(T). + /// + private static bool TryCoerceArguments(MethodInfo method, JArray args, out object[] callArgs, out string error) + { + error = null; + var parameters = method.GetParameters(); + callArgs = new object[parameters.Length]; + var provided = args?.Count ?? 0; + + if (provided > parameters.Length) + { + error = $"Entry point '{method.DeclaringType?.FullName}.{method.Name}' expects {parameters.Length} argument(s) but {provided} were provided."; + return false; + } + + for (int i = 0; i < parameters.Length; i++) + { + var p = parameters[i]; + var pt = p.ParameterType; + + if (i >= provided) + { + if (p.HasDefaultValue) + { + callArgs[i] = p.DefaultValue; + continue; + } + + error = $"Missing required argument #{i} for parameter '{p.Name}' ({pt.Name})."; + return false; + } + + var token = args[i]; + + if (typeof(Object).IsAssignableFrom(pt)) + { + if (token == null || token.Type == JTokenType.Null) + { + callArgs[i] = null; + continue; + } + + ObjectRef handle; + try + { + handle = token.ToObject(); + } + catch (Exception ex) + { + error = $"Argument #{i} ('{p.Name}'): not a valid object reference: {ex.Message}"; + return false; + } + + if (handle == null || handle.IsEmpty) + { + error = $"Argument #{i} ('{p.Name}'): empty object reference."; + return false; + } + + if (!ObjectResolver.TryResolve(handle, out var resolved, out var resolveError)) + { + error = $"Argument #{i} ('{p.Name}'): {resolveError}"; + return false; + } + + if (!pt.IsInstanceOfType(resolved)) + { + // Convenience: a GameObject handle can satisfy a Component parameter (and vice versa). + Object coerced = null; + if (resolved is GameObject go && typeof(Component).IsAssignableFrom(pt)) + coerced = go.GetComponent(pt); + else if (resolved is Component c && pt == typeof(GameObject)) + coerced = c.gameObject; + + if (coerced != null && pt.IsInstanceOfType(coerced)) + { + resolved = coerced; + } + else + { + error = $"Argument #{i} ('{p.Name}') resolved to a {resolved.GetType().Name}, which is not assignable to {pt.Name}."; + return false; + } + } + + callArgs[i] = resolved; + continue; + } + + if (token == null || token.Type == JTokenType.Null) + { + // null has no representation in a non-nullable value type — silently passing + // default(T) would hide the caller's mistake. Nullable (and reference + // types) accept null as-is. + if (pt.IsValueType && Nullable.GetUnderlyingType(pt) == null) + { + error = $"Argument #{i} ('{p.Name}'): null cannot be converted to value type {pt.Name}; pass a value, or make the parameter nullable ({pt.Name}?)."; + return false; + } + + callArgs[i] = null; + continue; + } + + try + { + callArgs[i] = token.ToObject(pt); + } + catch (Exception ex) + { + error = $"Argument #{i} ('{p.Name}'): cannot convert to {pt.Name}: {ex.Message}"; + return false; + } + } + + return true; + } + + /// + /// Serialize the entry point's return value for the JSON response. Mirrors + /// EvalCodeCompiler.SerializeResult so run_script results look like eval results: + /// primitives pass through, Unity objects go via JsonUtility, everything else via Newtonsoft, + /// with a ToString() fallback. + /// + private static object SerializeResult(object value) + { + if (value == null) return null; + + if (value is string || value is bool || value is int || value is long || value is float || value is double) + return value; + + if (value is Object unityObj) + { + try + { + return JsonConvert.DeserializeObject(JsonUtility.ToJson(unityObj)); + } + catch + { + return value.ToString(); + } + } + + try + { + return JsonConvert.DeserializeObject(JsonConvert.SerializeObject(value)); + } + catch + { + return value.ToString(); + } + } + } + + /// + /// Response for run_script. Result shape: { result, diagnostics, compileMs, executeMs, + /// assemblyName } on top of the standard command envelope. Deliberately carries no echo of the + /// source (path + diagnostics only), so MCP results stay small and reviewable. + /// + [Serializable] + class RunScriptResponse : CommandExecutionResponse + { + /// Compilation diagnostics (errors, warnings) from Roslyn, with line/column. + [JsonProperty("diagnostics")] + public List Diagnostics { get; set; } = new List(); + + /// + /// Milliseconds spent compiling the file to an in-memory assembly. 0 for hotpatch, whose + /// compile is inside reload_file and not reported separately (see ). + /// + [JsonProperty("compileMs")] + public long CompileMs { get; set; } + + /// + /// Milliseconds spent executing the entry point (0 for dry_run). For hotpatch this is the + /// whole reload duration — compile + apply — since reload_file does not split the two. + /// + [JsonProperty("executeMs")] + public long ExecuteMs { get; set; } + + /// Name of the generated in-memory assembly. + [JsonProperty("assemblyName")] + public string AssemblyName { get; set; } + + public static RunScriptResponse Ok(object result, string assemblyName, long compileMs, long executeMs, long executionTimeMs, List diagnostics) + { + return new RunScriptResponse + { + Success = true, + Command = "run_script", + Result = result, + AssemblyName = assemblyName, + CompileMs = compileMs, + ExecuteMs = executeMs, + ExecutionTimeMs = executionTimeMs, + Diagnostics = diagnostics ?? new List(), + ExecutedAt = DateTime.UtcNow + }; + } + + public static RunScriptResponse Fail(string error, string errorDetails, long executionTimeMs, + List diagnostics = null, long compileMs = 0, long executeMs = 0, string assemblyName = null) + { + return new RunScriptResponse + { + Success = false, + Command = "run_script", + Error = error, + ErrorDetails = errorDetails, + AssemblyName = assemblyName, + CompileMs = compileMs, + ExecuteMs = executeMs, + ExecutionTimeMs = executionTimeMs, + Diagnostics = diagnostics ?? new List(), + ExecutedAt = DateTime.UtcNow + }; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/RunScriptCommand.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/RunScriptCommand.cs.meta new file mode 100644 index 0000000..cd149dd --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/RunScriptCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2b6f31ba780d4489823da503b4329157 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/ScriptTypeResolver.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/ScriptTypeResolver.cs new file mode 100644 index 0000000..e0cf76f --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/ScriptTypeResolver.cs @@ -0,0 +1,161 @@ +using System; +using System.Linq; +using System.Reflection; +using UnityEditor; +using UnityEngine; + +namespace Unity.Pipeline.Editor.Commands.Scripts +{ + /// + /// Resolves an agent-supplied type name (or a reference) to a compiled + /// , searching the currently-loaded assemblies. + /// + /// This is the heart of the compile-aware behaviour for CLI-195: a script that was just created + /// has no compiled type until a domain reload runs, so resolution here will fail until the agent + /// recompiles. Callers translate that failure into a clear, recoverable error rather than a crash. + /// + static class ScriptTypeResolver + { + /// + /// Try to resolve a MonoBehaviour-derived type by its name. Accepts either a bare class name + /// ("PlayerController") or a fully-qualified name ("Game.Player.PlayerController"). When a + /// bare name is ambiguous across namespaces the first match wins; callers should prefer the + /// fully-qualified name. Returns false with a human-readable when no + /// loaded type matches (typically: not yet compiled). + /// + public static bool TryResolveComponentType(string typeName, out Type type, out string error) + { + type = null; + error = null; + + if (string.IsNullOrWhiteSpace(typeName)) + { + error = "Type name is required."; + return false; + } + + var name = typeName.Trim(); + var match = FindType(name); + + if (match == null) + { + error = + $"Type '{name}' was not found in any loaded assembly. " + + "If you just created this script it is not compiled yet: run 'recompile', poll " + + "'recompile_status' until it reports completed/up_to_date, then retry attach_script. " + + "If it should already exist, check the class name (and namespace) and that the file compiled without errors."; + return false; + } + + if (!typeof(MonoBehaviour).IsAssignableFrom(match)) + { + error = $"Type '{match.FullName}' does not derive from MonoBehaviour and cannot be added as a component."; + return false; + } + + if (match.IsAbstract) + { + error = $"Type '{match.FullName}' is abstract and cannot be instantiated as a component."; + return false; + } + + type = match; + return true; + } + + /// + /// Resolve the compiled backing a asset reference + /// (e.g. one returned by create_script). Returns false when the script has no class yet + /// (uncompiled) or the asset is not a MonoScript. + /// + public static bool TryResolveFromMonoScript(MonoScript script, out Type type, out string error) + { + type = null; + error = null; + + if (script == null) + { + error = "MonoScript reference is null."; + return false; + } + + var scriptClass = script.GetClass(); + if (scriptClass == null) + { + error = + $"Script '{script.name}' has no compiled class. It is likely not compiled yet: run 'recompile', " + + "poll 'recompile_status', then retry."; + return false; + } + + type = scriptClass; + return true; + } + + /// + /// Search all loaded assemblies for a type by full name first, then by bare class name. Done + /// over rather than TypeCache so it also finds types in + /// non-Unity-managed assemblies and matches what Activator/AddComponent can actually load. + /// + private static Type FindType(string name) + { + var assemblies = PipelineUtils.GetLoadedAssemblies(); + + // 1. Fully-qualified name (exact). + foreach (var asm in assemblies) + { + var t = asm.GetType(name, throwOnError: false, ignoreCase: false); + if (t != null) + return t; + } + + // 2. Bare class name — match on Name across loaded types. GetTypes() is expensive, so skip + // dynamic and system/Unity assemblies (which never hold user MonoBehaviours). This mirrors + // CommandRegistry.IsSystemAssembly's predicate (replicated locally rather than shared so we + // don't widen that internal helper's surface). + foreach (var asm in assemblies) + { + if (IsSkippableAssembly(asm)) + continue; + + Type[] types; + try + { + types = asm.GetTypes(); + } + catch (ReflectionTypeLoadException ex) + { + types = ex.Types.Where(t => t != null).ToArray(); + } + + var hit = types.FirstOrDefault(t => t != null && t.Name == name); + if (hit != null) + return hit; + } + + return null; + } + + /// + /// Assemblies we never need to scan for a user MonoBehaviour: dynamic (in-memory, can't be + /// reflected for types reliably) and core system/Unity assemblies. Mirrors the predicate in + /// CommandRegistry.IsSystemAssembly. + /// + private static bool IsSkippableAssembly(Assembly assembly) + { + if (assembly.IsDynamic) + return true; + + var name = assembly.GetName().Name; + if (string.IsNullOrEmpty(name)) + return false; + + return name.StartsWith("System.", StringComparison.Ordinal) || + name.StartsWith("Microsoft.", StringComparison.Ordinal) || + name.StartsWith("mscorlib", StringComparison.Ordinal) || + name.StartsWith("netstandard", StringComparison.Ordinal) || + name.Equals("UnityEngine", StringComparison.Ordinal) || + name.Equals("UnityEditor", StringComparison.Ordinal); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/ScriptTypeResolver.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/ScriptTypeResolver.cs.meta new file mode 100644 index 0000000..79f3338 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/ScriptTypeResolver.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 6b1131a6a27648b1829e78c8c0bd69a7 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/SerializedFieldCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/SerializedFieldCommands.cs new file mode 100644 index 0000000..7f6acf5 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/SerializedFieldCommands.cs @@ -0,0 +1,239 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Newtonsoft.Json.Linq; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Editor.Commands.GameObjects; +using Unity.Pipeline.Models; +using UnityEditor; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace Unity.Pipeline.Editor.Commands.Scripts +{ + /// + /// Read and write serialized ([SerializeField] / public) fields on a component or asset through + /// Unity's model (CLI-195). + /// + /// Why SerializedObject and not plain reflection: it honours Unity's serialization rules (private + /// [SerializeField] fields, property drawers, prefab overrides), marks the object dirty correctly, + /// and integrates with Undo. Writes are wrapped in an so an + /// agent's change reverts as one step. + /// + /// Field addressing uses Unity's native SerializedProperty path syntax, so array elements are + /// reachable directly: "myArray.Array.data[2]" sets the third element; "myArray.Array.size" sets + /// the array length. Nested fields use dotted paths ("settings.speed"). + /// + static class SerializedFieldCommands + { + [CliCommand("set_serialized_field", + "Set a serialized field on a component/asset. Supports primitives, enums, Vector/Color/Rect/Bounds, " + + "object references (value = an ObjectRef: asset by guid/fileId/path or scene object by instanceId/hierarchyPath), " + + "and array elements via 'name.Array.data[i]' (or 'name.Array.size' to resize).", + Tags = new[] { "scripts", "gameobjects/components" })] + public static AuthoringResult SetSerializedField( + [CliArg("target", "Reference to the component or asset to modify (globalId/path/guid/instanceId/hierarchyPath). May be a GameObject when 'component' is given.", Required = true)] ObjectRef target, + [CliArg("field", "SerializedProperty path, e.g. 'speed', 'settings.speed', or 'waypoints.Array.data[0]'.", Required = true)] string field, + [CliArg("value", "JSON value to assign. For object references pass an ObjectRef object (or null to clear). For enums pass the value name.", Required = true)] JToken value, + [CliArg("component", "Component type name on the target GameObject (e.g. 'Rigidbody'). Use when 'target' is a GameObject; omit when 'target' is already a component handle.")] string component = null) + { + if (target == null || target.IsEmpty) + throw new ArgumentException("set_serialized_field 'target' is required."); + if (string.IsNullOrWhiteSpace(field)) + throw new ArgumentException("set_serialized_field 'field' is required."); + + var obj = ResolveSerializable(target, component); + + using (new AuthoringUndoScope($"Set {field}")) + { + // RegisterCompleteObjectUndo captures the pre-change state for revert; the + // SerializedObject below then records the change for prefab/asset dirtying. + Undo.RegisterCompleteObjectUndo(obj, $"Set {field}"); + + var so = new SerializedObject(obj); + var prop = so.FindProperty(field); + if (prop == null) + throw new ArgumentException( + $"Field '{field}' was not found on '{obj.GetType().Name}'. " + + "Use a SerializedProperty path (e.g. 'speed', 'settings.speed', 'items.Array.data[0]')."); + + SerializedPropertyConverter.SetValue(prop, value); + so.ApplyModifiedProperties(); + EditorUtility.SetDirty(obj); + } + + var result = ObjectResolver.Describe(obj) ?? new AuthoringResult { Type = obj.GetType().Name }; + return result; + } + + [CliCommand("get_serialized_fields", + "Read serialized fields of a component/asset. Returns each top-level field's name, type and value " + + "(object references are returned as re-usable handles). Pass 'field' to read a single SerializedProperty path. " + + "Pass format='value' to return just the value(s) — a token-efficient read for scalars.", + Tags = new[] { "scripts", "gameobjects/components" })] + public static object GetSerializedFields( + [CliArg("target", "Reference to the component or asset to read (globalId/path/guid/instanceId/hierarchyPath). May be a GameObject when 'component' is given.", Required = true)] ObjectRef target, + [CliArg("field", "Optional single SerializedProperty path to read (e.g. 'speed' or 'items.Array.data[0]'). Omit to read all top-level fields.")] string field = null, + [CliArg("component", "Component type name on the target GameObject (e.g. 'Rigidbody'). Use when 'target' is a GameObject; omit when 'target' is already a component handle.")] string component = null, + [CliArg("format", "Output shape. Omit (default) for a full descriptor per field {name,path,propertyType,isArray,arrayLength,value}; 'value' returns just the value(s): the raw value for a single 'field', or a {name: value} map for all fields.")] string format = null) + { + if (target == null || target.IsEmpty) + throw new ArgumentException("get_serialized_fields 'target' is required."); + + // Value projection (AUTHAPI-21): drop the per-field descriptor and return only the value(s) + // so a scalar read costs bytes, not an envelope. Anything other than 'value' is the default + // descriptor form, so existing callers are unaffected. + var valueOnly = string.Equals(format, "value", StringComparison.OrdinalIgnoreCase); + + var obj = ResolveSerializable(target, component); + var so = new SerializedObject(obj); + + if (!string.IsNullOrWhiteSpace(field)) + { + var prop = so.FindProperty(field); + if (prop == null) + throw new ArgumentException($"Field '{field}' was not found on '{obj.GetType().Name}'."); + + if (valueOnly) + return SerializedPropertyConverter.GetValue(prop); + + return new + { + type = obj.GetType().Name, + fields = new[] { DescribeProperty(prop) } + }; + } + + // Each mode gets only its own container (the other stays null). + var fields = valueOnly ? null : new List(); + var values = valueOnly ? new Dictionary() : null; + var iterator = so.GetIterator(); + // enterChildren=true on the first MoveNext to step into the top level; then false to stay + // at the top level and skip nested children (callers drill in via an explicit 'field'). + var enterChildren = true; + while (iterator.NextVisible(enterChildren)) + { + enterChildren = false; + + // m_Script is Unity's hidden back-reference to the MonoScript; not a user field. + if (iterator.propertyPath == "m_Script") + continue; + + if (valueOnly) + { + // Degrade per-field rather than failing the whole map read (mirrors + // get_component_properties' per-property guard in ComponentCommands). + try { values[iterator.name] = SerializedPropertyConverter.GetValue(iterator); } + catch (Exception ex) { values[iterator.name] = $""; } + } + else + { + fields.Add(DescribeProperty(iterator)); + } + } + + return valueOnly ? (object)values : new { type = obj.GetType().Name, fields }; + } + + /// + /// Resolve a handle to an object that a SerializedObject can wrap: a Component or an asset. + /// + /// Two addressing forms (CLI-225): + /// * The handle already points at a Component (or asset) → use it directly. An optional + /// type name is validated against it as a guard. + /// * The handle points at a GameObject AND is given → look up + /// the matching component(s) on that GameObject. Exactly one match is used; MULTIPLE + /// same-type components are an error that lists each instanceId so the agent can re-address + /// by instanceId; zero matches is a clear error. + /// + /// A GameObject with no is rejected (a GameObject's "fields" are + /// its components), with a hint to pass --component or a specific component handle. + /// + /// This mirrors 's GO-path+type pattern, but + /// deliberately errors on MULTIPLE matches (that helper returns the first) so a set/get never + /// silently targets the wrong instance. + /// + private static Object ResolveSerializable(ObjectRef target, string component = null) + { + if (!ObjectResolver.TryResolve(target, out var obj, out var error)) + throw new ArgumentException($"Could not resolve target: {error}"); + + // The handle already points at a specific Component: honour it directly. A 'component' here + // is only a constraint to validate against, never a reason to re-fetch (which could pick a + // different same-type instance and ignore the handle). + if (obj is Component directComponent) + { + if (!string.IsNullOrWhiteSpace(component)) + { + var requestedType = TypeResolver.ResolveComponentType(component); + if (requestedType == null) + throw new ArgumentException($"Could not resolve component type '{component}'."); + if (!requestedType.IsInstanceOfType(directComponent)) + throw new ArgumentException( + $"Target resolves to a {directComponent.GetType().Name}, which is not a '{requestedType.Name}'."); + } + + return directComponent; + } + + if (obj is GameObject go) + { + if (string.IsNullOrWhiteSpace(component)) + throw new ArgumentException( + $"Target '{target}' is a GameObject. Pass --component to pick a component on it, " + + "or target a specific component directly (use its instanceId/globalId), " + + "to read or set serialized fields."); + + var componentType = TypeResolver.ResolveComponentType(component); + if (componentType == null) + throw new ArgumentException($"Could not resolve component type '{component}'."); + + var matches = go.GetComponents(componentType).Where(c => c != null).ToArray(); + if (matches.Length == 0) + throw new ArgumentException( + $"GameObject '{go.name}' has no component of type '{componentType.Name}'."); + + if (matches.Length > 1) + { + var sb = new StringBuilder(); + sb.Append($"GameObject '{go.name}' has {matches.Length} components of type '{componentType.Name}'. ") + .Append("Re-target a specific one by its instanceId: "); + for (int i = 0; i < matches.Length; i++) + { + if (i > 0) sb.Append(", "); + sb.Append($"instanceId {PipelineUtils.GetObjectId(matches[i])}"); + } + sb.Append('.'); + throw new ArgumentException(sb.ToString()); + } + + return matches[0]; + } + + // Not a Component, not a GameObject — an asset (e.g. ScriptableObject) handled directly. + // A 'component' filter is meaningless for an asset; reject it rather than silently ignore it + // (a supplied component here signals a misrouted or misspelled request). + if (!string.IsNullOrWhiteSpace(component)) + throw new ArgumentException( + $"Target '{target}' resolved to a {obj.GetType().Name} (an asset), which has no components. " + + "Omit --component when targeting an asset directly."); + + return obj; + } + + private static object DescribeProperty(SerializedProperty prop) + { + return new + { + name = prop.name, + path = prop.propertyPath, + propertyType = prop.propertyType.ToString(), + isArray = prop.isArray && prop.propertyType != SerializedPropertyType.String, + arrayLength = (prop.isArray && prop.propertyType != SerializedPropertyType.String) ? prop.arraySize : (int?)null, + value = SerializedPropertyConverter.GetValue(prop) + }; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/SerializedFieldCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/SerializedFieldCommands.cs.meta new file mode 100644 index 0000000..161e82f --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/SerializedFieldCommands.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 974b8c0dcec74d388bbf2061fc3aa3dc diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/SerializedPropertyConverter.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/SerializedPropertyConverter.cs new file mode 100644 index 0000000..9fc1ccb --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/SerializedPropertyConverter.cs @@ -0,0 +1,237 @@ +using System; +using Newtonsoft.Json.Linq; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Models; +using UnityEditor; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace Unity.Pipeline.Editor.Commands.Scripts +{ + /// + /// Bridges agent-supplied JSON values and Unity's model for the + /// set_serialized_field / get_serialized_fields commands (CLI-195). + /// + /// Supported property kinds: integers, floats, bools, strings, enums, Vector2/3/4, Color, + /// Quaternion, Rect, Bounds, and object references. Object references accept an + /// handle (resolved via ) — assets by GUID/fileId or path, and scene + /// objects by instanceId/hierarchyPath. Arrays are addressed element-by-element via a path like + /// "myArray.Array.data[2]" (Unity's native SerializedProperty path syntax) — see the commands. + /// + static class SerializedPropertyConverter + { + /// + /// Assign a JSON value to a serialized property, converting by the property's type. Throws + /// with a clear message when the value can't be coerced or the + /// property type isn't supported. The caller is responsible for ApplyModifiedProperties. + /// + public static void SetValue(SerializedProperty prop, JToken value) + { + // Whole-array assignment: an array/list field (Generic + isArray) set from a JSON array — + // resize, then recurse per element (handles primitive and object-reference arrays alike). + // Element-by-element addressing via "field.Array.data[i]" / "field.Array.size" still works. + if (prop.isArray && prop.propertyType != SerializedPropertyType.String) + { + if (!(value is JArray array)) + throw new ArgumentException( + $"Field '{prop.propertyPath}' is an array; provide a JSON array of elements."); + + prop.arraySize = array.Count; + for (int i = 0; i < array.Count; i++) + SetValue(prop.GetArrayElementAtIndex(i), array[i]); + return; + } + + switch (prop.propertyType) + { + case SerializedPropertyType.Integer: + prop.longValue = value.ToObject(); + break; + case SerializedPropertyType.Boolean: + prop.boolValue = value.ToObject(); + break; + case SerializedPropertyType.Float: + prop.doubleValue = value.ToObject(); + break; + case SerializedPropertyType.String: + prop.stringValue = value.ToObject(); + break; + case SerializedPropertyType.Enum: + SetEnum(prop, value); + break; + case SerializedPropertyType.Vector2: + prop.vector2Value = ToVector2(value); + break; + case SerializedPropertyType.Vector3: + prop.vector3Value = ToVector3(value); + break; + case SerializedPropertyType.Vector4: + prop.vector4Value = ToVector4(value); + break; + case SerializedPropertyType.Quaternion: + var v4 = ToVector4(value); + prop.quaternionValue = new Quaternion(v4.x, v4.y, v4.z, v4.w); + break; + case SerializedPropertyType.Color: + prop.colorValue = ToColor(value); + break; + case SerializedPropertyType.Rect: + prop.rectValue = ToRect(value); + break; + case SerializedPropertyType.Bounds: + prop.boundsValue = ToBounds(value); + break; + case SerializedPropertyType.ObjectReference: + prop.objectReferenceValue = ResolveObjectReference(value); + break; + case SerializedPropertyType.ArraySize: + // Resizing an array via ".Array.size" — the property is an int under the hood. + prop.intValue = value.ToObject(); + break; + default: + throw new ArgumentException( + $"Field '{prop.propertyPath}' has unsupported type '{prop.propertyType}'. " + + "Supported: int, float, bool, string, enum, Vector2/3/4, Quaternion, Color, Rect, Bounds, object reference, array size."); + } + } + + /// + /// Read a serialized property into a plain object suitable for JSON serialization. Object + /// references are described via so the agent gets a + /// re-usable handle; arrays are returned as a length plus per-element values. + /// + public static object GetValue(SerializedProperty prop) + { + // Array/list fields are returned as a JSON array of their elements so they round-trip with + // SetValue. (String also reports isArray, hence the exclusion.) + if (prop.isArray && prop.propertyType != SerializedPropertyType.String) + { + var elements = new JArray(); + for (int i = 0; i < prop.arraySize; i++) + { + var v = GetValue(prop.GetArrayElementAtIndex(i)); + elements.Add(v == null ? JValue.CreateNull() : JToken.FromObject(v)); + } + + return elements; + } + + switch (prop.propertyType) + { + case SerializedPropertyType.Integer: + return prop.longValue; + case SerializedPropertyType.Boolean: + return prop.boolValue; + case SerializedPropertyType.Float: + return prop.doubleValue; + case SerializedPropertyType.String: + return prop.stringValue; + case SerializedPropertyType.Enum: + return prop.enumValueIndex >= 0 && prop.enumValueIndex < prop.enumNames.Length + ? prop.enumNames[prop.enumValueIndex] + : (object)prop.intValue; + case SerializedPropertyType.Vector2: + return new { x = prop.vector2Value.x, y = prop.vector2Value.y }; + case SerializedPropertyType.Vector3: + return new { x = prop.vector3Value.x, y = prop.vector3Value.y, z = prop.vector3Value.z }; + case SerializedPropertyType.Vector4: + return new { x = prop.vector4Value.x, y = prop.vector4Value.y, z = prop.vector4Value.z, w = prop.vector4Value.w }; + case SerializedPropertyType.Quaternion: + return new { x = prop.quaternionValue.x, y = prop.quaternionValue.y, z = prop.quaternionValue.z, w = prop.quaternionValue.w }; + case SerializedPropertyType.Color: + return new { r = prop.colorValue.r, g = prop.colorValue.g, b = prop.colorValue.b, a = prop.colorValue.a }; + case SerializedPropertyType.Rect: + return new { x = prop.rectValue.x, y = prop.rectValue.y, width = prop.rectValue.width, height = prop.rectValue.height }; + case SerializedPropertyType.Bounds: + var b = prop.boundsValue; + return new { center = new { x = b.center.x, y = b.center.y, z = b.center.z }, size = new { x = b.size.x, y = b.size.y, z = b.size.z } }; + case SerializedPropertyType.ObjectReference: + return ObjectResolver.Describe(prop.objectReferenceValue); + case SerializedPropertyType.ArraySize: + return prop.intValue; + default: + // Unknown/unsupported types are reported by kind rather than failing a whole read. + return new { unsupported = prop.propertyType.ToString() }; + } + } + + private static void SetEnum(SerializedProperty prop, JToken value) + { + // Accept either the enum name (preferred, stable across reordering) or the numeric index. + if (value.Type == JTokenType.String) + { + var name = value.ToObject(); + var idx = Array.IndexOf(prop.enumNames, name); + if (idx < 0) + idx = Array.IndexOf(prop.enumDisplayNames, name); + if (idx < 0) + throw new ArgumentException( + $"Enum '{name}' is not a valid value for '{prop.propertyPath}'. Valid: {string.Join(", ", prop.enumNames)}."); + prop.enumValueIndex = idx; + } + else + { + var idx = value.ToObject(); + if (idx < 0 || idx >= prop.enumNames.Length) + throw new ArgumentException( + $"Enum index {idx} is out of range for '{prop.propertyPath}' (valid 0..{prop.enumNames.Length - 1}). " + + $"Valid values: {string.Join(", ", prop.enumNames)}."); + prop.enumValueIndex = idx; + } + } + + private static Object ResolveObjectReference(JToken value) + { + // An explicit null clears the reference; anything else MUST resolve — never silently no-op + // (an unresolved handle used to be dropped, so the command reported success while assigning + // nothing). + if (value == null || value.Type == JTokenType.Null) + return null; + + var handle = value.ToObject(); + if (handle == null || handle.IsEmpty) + throw new ArgumentException( + $"'{value}' is not a recognized object reference handle. " + + "Provide a path, guid, globalId, or instanceId (or null to clear)."); + + if (!ObjectResolver.TryResolve(handle, out var obj, out var error)) + throw new ArgumentException($"Could not resolve object reference: {error}"); + + return obj; + } + + private static float F(JToken t, string key, float fallback = 0f) + { + // Indexing a non-object token (e.g. the agent passed a number or array for a Vector3/Color) + // with a string key throws an opaque InvalidOperationException — validate first so the + // caller gets a clear, actionable ArgumentException instead. + if (!(t is JObject obj)) + throw new ArgumentException( + $"Expected a JSON object with named components (e.g. {{ \"{key}\": 0 }}) " + + $"but received a '{t?.Type.ToString() ?? "null"}'."); + + var token = obj[key]; + return token != null ? token.ToObject() : fallback; + } + + private static Vector2 ToVector2(JToken t) => new Vector2(F(t, "x"), F(t, "y")); + private static Vector3 ToVector3(JToken t) => new Vector3(F(t, "x"), F(t, "y"), F(t, "z")); + private static Vector4 ToVector4(JToken t) => new Vector4(F(t, "x"), F(t, "y"), F(t, "z"), F(t, "w")); + + private static Color ToColor(JToken t) => new Color(F(t, "r"), F(t, "g"), F(t, "b"), F(t, "a", 1f)); + + private static Rect ToRect(JToken t) => new Rect(F(t, "x"), F(t, "y"), F(t, "width"), F(t, "height")); + + private static Bounds ToBounds(JToken t) + { + if (!(t is JObject obj)) + throw new ArgumentException( + $"Expected a JSON object with 'center' and 'size' components but received a " + + $"'{t?.Type.ToString() ?? "null"}'."); + + var center = obj["center"] != null ? ToVector3(obj["center"]) : Vector3.zero; + var size = obj["size"] != null ? ToVector3(obj["size"]) : Vector3.zero; + return new Bounds(center, size); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/SerializedPropertyConverter.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/SerializedPropertyConverter.cs.meta new file mode 100644 index 0000000..35a6b3d --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/Scripts/SerializedPropertyConverter.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: ce4000d573a64d76a63e42b2b40c60a5 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/TestCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/TestCommands.cs new file mode 100644 index 0000000..8c425b4 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/TestCommands.cs @@ -0,0 +1,219 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor.Testing; +using Unity.Pipeline.Models; +using UnityEditor.TestTools.TestRunner.Api; +using UnityEngine; + +namespace Unity.Pipeline.Editor.Commands +{ + /// + /// Commands for running Unity tests programmatically + /// + static class TestCommands + { + /// + /// Execute Unity tests with filtering options. + /// Synchronous by default (blocks until completion), async mode available with --async-tests flag. + /// + [CliCommand("run_tests", "Execute Unity tests with filtering options", MainThreadRequired = true, Tags = new[] { "tests" })] + public static async Task RunTests( + [CliArg("mode", "Test mode: all, editor, playmode (default: all)")] string mode = "all", + [CliArg("filter", "Test name filter pattern (case-insensitive partial match)")] string filter = "", + [CliArg("filter_type", "Filter type: testName, assembly, category (default: testName)")] string filterType = "testName", + [CliArg("include_explicit", "Include tests marked with [Explicit] attribute")] bool includeExplicit = false, + [CliArg("async_tests", "Run asynchronously - return immediately, poll /test-status for results")] bool asyncTests = false, + [CliArg("timeout", "Test execution timeout in seconds (default: 300)")] int timeout = 300) + { + // Return the full structured response (including failures and the Error field on a + // failed run) rather than throwing: the server now awaits this Task and serializes the + // unwrapped response, so the client receives complete, structured reporting. Throwing + // would only surface an opaque message and discard the per-test results. + return await PipelineTestRunner.ExecuteTestsAsync( + mode, + filter, + filterType, + includeExplicit, + asyncTests, + timeout); + } + + /// + /// List all available tests without executing any of them. + /// Enumerates the test tree via TestRunnerApi.RetrieveTestList for the requested mode(s). + /// + [CliCommand("list_tests", "List all available tests (EditMode and/or PlayMode) without running them", MainThreadRequired = true, Tags = new[] { "tests" })] + public static async Task ListTests( + [CliArg("mode", "Test mode: all, editor, playmode (default: all)")] string mode = "all") + { + try + { + if (!TryGetModes(mode, out var modes)) + { + return new TestListResponse + { + Success = false, + Command = "list_tests", + Error = $"Invalid mode '{mode}'. Use 'editor', 'playmode', or 'all'.", + ExecutedAt = DateTime.UtcNow + }; + } + + var tests = new List(); + foreach (var testMode in modes) + { + tests.AddRange(await RetrieveTestsAsync(testMode)); + } + + return new TestListResponse + { + Success = true, + Command = "list_tests", + Mode = modes.Count == 2 ? "All" : modes[0].ToString(), + Count = tests.Count, + Tests = tests, + Message = $"Found {tests.Count} test(s).", + ExecutedAt = DateTime.UtcNow + }; + } + catch (Exception ex) + { + Debug.LogError($"[TestCommands] list_tests failed: {ex.Message}"); + return new TestListResponse + { + Success = false, + Command = "list_tests", + Error = "Failed to list tests", + ErrorDetails = ex.ToString(), + ExecutedAt = DateTime.UtcNow + }; + } + } + + /// + /// Get current test status for async test execution + /// + [CliCommand("test_status", "Get status of running async test execution", MainThreadRequired = false, Tags = new[] { "tests" })] + public static string GetTestStatus() + { + var status = PipelineTestRunner.GetTestStatus(); + return status ?? "{\"status\":\"no_tests\",\"message\":\"No test run in progress\"}"; + } + + /// + /// Cancel running test execution + /// + [CliCommand("cancel_tests", "Cancel running test execution", MainThreadRequired = true, Tags = new[] { "tests" })] + public static object CancelTests() + { + return PipelineTestRunner.CancelTests(); + } + + /// + /// Resolve a mode string to the concrete TestMode(s) to enumerate. + /// + private static bool TryGetModes(string mode, out List modes) + { + switch (mode?.ToLowerInvariant()) + { + case null: + case "": + case "all": + modes = new List { TestMode.EditMode, TestMode.PlayMode }; + return true; + case "editor": + case "editmode": + modes = new List { TestMode.EditMode }; + return true; + case "playmode": + case "play": + modes = new List { TestMode.PlayMode }; + return true; + default: + modes = null; + return false; + } + } + + /// + /// Retrieve the test list for a single mode. RetrieveTestList enumerates the test tree (no + /// execution) and invokes the callback on the main thread; we bridge it to a Task. + /// + private static Task> RetrieveTestsAsync(TestMode testMode) + { + var api = ScriptableObject.CreateInstance(); + var tcs = new TaskCompletionSource>(); + + api.RetrieveTestList(testMode, root => + { + try + { + var items = new List(); + CollectLeafTests(root, testMode, items); + tcs.SetResult(items); + } + catch (Exception ex) + { + tcs.SetException(ex); + } + }); + + return tcs.Task; + } + + /// + /// Walk the test tree and collect leaf tests (actual test methods, not suites/fixtures). + /// + private static void CollectLeafTests(ITestAdaptor test, TestMode testMode, List items) + { + if (test == null) + return; + + if (!test.HasChildren && !test.IsSuite) + { + items.Add(new TestListItem + { + FullName = test.FullName, + Mode = testMode.ToString(), + Assembly = test.TypeInfo?.Assembly?.GetName()?.Name, + Categories = test.Categories?.ToList() ?? new List(), + Explicit = test.RunState == RunState.Explicit + }); + return; + } + + if (test.Children != null) + { + foreach (var child in test.Children) + CollectLeafTests(child, testMode, items); + } + } + } + + /// + /// Response for the list_tests command: the available tests, without execution results. + /// + [Serializable] + class TestListResponse : CommandExecutionResponse + { + public string Mode { get; set; } // EditMode, PlayMode, or All + public int Count { get; set; } + public List Tests { get; set; } = new List(); + } + + /// + /// A single available test (no run state / outcome — this is a listing, not a result). + /// + [Serializable] + class TestListItem + { + public string FullName { get; set; } + public string Mode { get; set; } + public string Assembly { get; set; } + public List Categories { get; set; } = new List(); + public bool Explicit { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/TestCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/TestCommands.cs.meta new file mode 100644 index 0000000..e43426e --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/TestCommands.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 00cbe51faaafd2d488d88f72394a97d3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/WaitConditionEvaluator.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/WaitConditionEvaluator.cs new file mode 100644 index 0000000..139e591 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/WaitConditionEvaluator.cs @@ -0,0 +1,786 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Newtonsoft.Json.Linq; +using Unity.Pipeline; +using Unity.Pipeline.Editor.Authoring; +using UnityEditor; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace Unity.Pipeline.Editor.Commands +{ + /// + /// Thrown when a wait condition cannot be resolved or evaluated (bad member path, unresolved + /// target, unreadable member, un-coercible operand). Distinct from a timeout: the wait reports + /// these as a failed result with this message, never as a spurious timedOut + /// (unless tolerate_missing is set, in which case resolution failures are retried as + /// condition-not-met until the wait's own budget expires) — UNLESS is + /// set, for a failure no amount of retrying can ever resolve (a malformed member path, a + /// findType naming a non- type, a member that does not exist on + /// the resolved type): those fail fast even under tolerate_missing, whose contract is "does not + /// exist YET", not "will never exist". + /// + internal sealed class WaitEvaluationException : Exception + { + internal bool IsPermanent { get; } + + public WaitEvaluationException(string message, bool isPermanent = false) : base(message) + { + IsPermanent = isPermanent; + } + } + + /// + /// Cached resolution state for one wait's condition. The expensive part of member resolution — + /// 's whole-appdomain type scan — is cached here + /// instead of running once per poll: a successful scan never repeats, and a failed one is only + /// retried after the loaded-assembly set changes (relevant to tolerate_missing waits on + /// not-yet-loadable paths). A findType instance binds once and re-scans + /// only when the bound instance is destroyed; an explicit target handle is re-resolved + /// every poll, because it can legitimately change mid-wait. Member lookups are + /// memoized per encountered runtime type, so steady-state polls perform dictionary hits, not + /// reflection walks. + /// + /// Created when the wait is registered (pure reflection state — safe off the main thread); + /// afterwards it is only touched by on the main thread. + /// + internal sealed class WaitConditionPlan + { + internal readonly WaitConditionInput Condition; + internal readonly string[] Segments; + + /// Resolved type of a static member path's leading prefix (cached after the first successful scan). + internal Type StaticType; + + /// Number of leading segments consumed by . + internal int StaticSplit; + + /// Resolved findType (cached after the first successful scan). + internal Type FindTypeResolved; + + /// The live instance a findType wait is bound to; re-resolved only when it + /// has been destroyed (never silently re-bound while alive). + internal Object BoundInstance; + + /// The ambiguity note captured when was bound, + /// re-surfaced on every poll for the wait result. + internal string BoundNote; + + /// Ambiguity note from type resolution (a bare type name matching several loaded + /// types), captured once when the scan resolves and re-surfaced on every poll. + internal string TypeNote; + + /// + /// Signature of the loaded-assembly SET observed by the last FAILED type-resolution scan + /// (combines identity hashes, not just Count — an unload-and-load-of-a-different- + /// assembly can leave the count unchanged while still making a previously-unresolvable name + /// resolvable). A failed scan is only re-attempted once this changes: within a wait's + /// lifetime (waits don't survive domain reloads) the only way an unresolvable name becomes + /// resolvable is a newly loaded assembly (e.g. run_script/eval loading one). + /// Without this, a tolerate_missing wait on a never-resolving path would repeat the + /// whole-appdomain scan every poll. Null means "never scanned" — distinct from any signature + /// value, including a coincidental 0 — so the very first call always rescans. + /// + internal long? FailedScanAssemblySignature; + + /// Non-fatal note from the latest resolution (e.g. an ambiguous findType match), surfaced on the wait result. + internal string ResolutionNote; + + private readonly Dictionary<(Type Lookup, int Segment, bool IsStatic), MemberInfo> m_Members = + new Dictionary<(Type, int, bool), MemberInfo>(); + + internal WaitConditionPlan(WaitConditionInput condition) + { + Condition = condition; + Segments = (condition?.Member ?? string.Empty).Trim().Split('.'); + } + + internal bool TryGetCachedMember(Type lookup, int segment, bool isStatic, out MemberInfo member) + => m_Members.TryGetValue((lookup, segment, isStatic), out member); + + internal void CacheMember(Type lookup, int segment, bool isStatic, MemberInfo member) + => m_Members[(lookup, segment, isStatic)] = member; + } + + /// + /// Reads and compares a member value for the wait_for command (AUTHAPI-25). + /// + /// Member resolution mirrors the rules AUTHAPI-16's invoke/query surface will use (that shared + /// resolver does not exist yet, so this is a self-contained implementation the two can later + /// converge on — see PR notes): + /// - target (an ) resolves via + /// ; the member path then walks instance members from it. + /// - findType resolves a UnityEngine.Object type and walks from a live (non-persistent, + /// unhidden) instance — prefab assets and hidden editor internals are filtered out, scene + /// instances are preferred, and an ambiguous match binds deterministically to the lowest + /// instance id with a note on the result. + /// - Otherwise the member path is a fully-qualified static path (Ns.Type.StaticMember.Nested). + /// + /// Only readable fields and properties are resolved — write-only members and methods are rejected, + /// so the surface is read-only by construction. + /// + internal static class WaitConditionEvaluator + { + // PUBLIC members only, deliberately: wait conditions observe the same surface any C# + // consumer of the API sees. Reading private/internal state by name would let the `wait` + // tag expose internals below eval's capability gate (a host can disable eval but allow + // wait) — anyone who genuinely needs private state has eval/run_script on this server. + private const BindingFlags MemberFlags = BindingFlags.Public; + + /// Convenience overload for one-shot reads (tests): builds a throwaway plan. + internal static object ReadMember(WaitConditionInput condition, out Type memberType) + => ReadMember(new WaitConditionPlan(condition), out memberType); + + /// + /// Resolve the plan's member path and return the current value plus its declared type (used + /// to coerce the comparison operand). Type resolution results are cached on + /// so repeated polls never repeat the appdomain scan; only the live + /// instance (target / findType) is re-resolved per call. Throws + /// on any resolution failure. + /// + internal static object ReadMember(WaitConditionPlan plan, out Type memberType) + { + memberType = typeof(object); + if (plan == null || plan.Condition == null) + throw new WaitEvaluationException("condition is required.", isPermanent: true); + + plan.ResolutionNote = null; + var condition = plan.Condition; + var path = (condition.Member ?? string.Empty).Trim(); + if (path.Length == 0) + throw new WaitEvaluationException("condition.member is required.", isPermanent: true); + + var segments = plan.Segments; + + object current; + Type staticType = null; + int start; + var isFindTypeInstance = false; + + if (condition.Target != null && !condition.Target.IsEmpty) + { + // A malformed globalId is a property of the input STRING itself — no amount of + // retrying ever makes it parseable, unlike every other TryResolve failure below + // (empty/unknown/not-yet-loaded), which can legitimately resolve once the + // referenced object appears — the same "wait for a spawned object" story `target` + // shares with `findType`. Checked locally rather than widening ObjectResolver's + // public TryResolve (20+ call sites) with a permanence flag it has no other use for. + if (!string.IsNullOrEmpty(condition.Target.GlobalId) && + !GlobalObjectId.TryParse(condition.Target.GlobalId, out _)) + throw new WaitEvaluationException( + $"Invalid condition.target.globalId '{condition.Target.GlobalId}'.", isPermanent: true); + + // Re-resolved every poll on purpose: the referenced object can appear/change mid-wait. + if (!ObjectResolver.TryResolve(condition.Target, out var obj, out var err)) + throw new WaitEvaluationException($"Could not resolve condition.target: {err}"); + current = obj; + start = 0; + } + else if (!string.IsNullOrEmpty(condition.FindType)) + { + // The type scan is cached (failures too, until a new assembly loads); the instance + // lookup stays per-poll (it can legitimately change). + var type = plan.FindTypeResolved; + if (type == null && ShouldRescan(plan)) + { + type = plan.FindTypeResolved = ResolveType(condition.FindType, out var typeNote); + if (type != null) + plan.TypeNote = typeNote; + } + if (type == null) + throw new WaitEvaluationException($"Unknown findType '{condition.FindType}'."); + if (plan.BoundInstance is Object boundInstance && boundInstance) + { + // Bound once, reused until destroyed: re-scanning every loaded object on every + // poll (up to ~60/s at the minimum interval) scales with scene size for no + // benefit — the bind is deterministic anyway. Destruction of the bound + // instance triggers a re-scan, so the spawn-wait and replaced-after-destroy + // stories keep working. + current = boundInstance; + } + else + { + current = FindInstance(type, out var note) + ?? throw new WaitEvaluationException($"No live instance of type '{type.FullName}' (persistent assets and hidden objects are excluded)."); + plan.BoundInstance = (Object)current; + plan.BoundNote = note; + } + plan.ResolutionNote = plan.BoundNote; + start = 0; + isFindTypeInstance = true; + } + else + { + // Static path: find the longest leading dotted prefix that resolves to a type, + // leaving at least one trailing member segment. Resolved once, then cached. + if (segments.Length < 2) + // A property of the input STRING, not of anything that could load later — + // permanent regardless of tolerate_missing. + throw new WaitEvaluationException( + $"Static member path '{path}' must be 'Type.Member'; supply 'target' or 'findType' for instance members.", + isPermanent: true); + + if (plan.StaticType == null && ShouldRescan(plan)) + { + for (var k = segments.Length - 1; k >= 1; k--) + { + var prefix = string.Join(".", segments, 0, k); + var t = ResolveType(prefix, out var typeNote); + if (t != null) + { + plan.StaticType = t; + plan.StaticSplit = k; + plan.TypeNote = typeNote; + break; + } + } + } + + if (plan.StaticType == null) + throw new WaitEvaluationException( + $"Could not resolve a type from static path '{path}'. Supply 'target' or 'findType' for instance members."); + + staticType = plan.StaticType; + current = null; + start = plan.StaticSplit; + } + + object value = current; + var firstStatic = current == null; + + for (var i = start; i < segments.Length; i++) + { + var segment = segments[i]; + var isStatic = value == null && firstStatic; + + if (value == null && !firstStatic) + throw new WaitEvaluationException($"Member path '{path}' hit null before segment '{segment}'."); + + // An object-typed `== null` misses UnityEngine.Object's fake-null: a destroyed + // object would pass and the next getter would throw a raw + // MissingReferenceException instead of a structured evaluation failure. + if (value is Object destroyedCheck && !destroyedCheck) + throw new WaitEvaluationException( + $"Member path '{path}' hit a destroyed Unity object before segment '{segment}'."); + + var lookup = value?.GetType() ?? staticType; + if (lookup == null) + throw new WaitEvaluationException($"Could not determine a type to resolve segment '{segment}'.", isPermanent: true); + + // TryReadMember's failures (no such readable member, write-only, indexer) are + // ordinarily properties of the resolved TYPE's shape, which cannot change without + // a domain reload — and a wait does not survive one. Permanent: never worth + // retrying. EXCEPT the very first segment off a findType-bound instance: which + // concrete subtype got bound is a deterministic-but-arbitrary tie-break among + // whichever live candidates exist right now (FindInstance's lowest-instance-id + // pick), not a fixed property of the wait's target the way `target`/static paths + // are — a sibling instance of a different subtype (already alive, or not yet + // spawned) might have this member even though the one we happened to bind doesn't. + // Failing fast here would defeat tolerate_missing's "wait for the right kind of + // spawned object" story; retrying until timeout is the honest answer instead. + var ambiguousCandidate = isFindTypeInstance && i == start; + if (!TryReadMember(plan, i, lookup, segment, isStatic, value, out var next, out var nextType, out var readError)) + throw new WaitEvaluationException(readError, isPermanent: !ambiguousCandidate); + + value = next; + memberType = nextType; + firstStatic = false; + } + + if (plan.TypeNote != null) + plan.ResolutionNote = plan.ResolutionNote == null + ? plan.TypeNote + : plan.TypeNote + " " + plan.ResolutionNote; + + // A destroyed Unity object as the TERMINAL value is observed as null — Unity's own + // == semantics — so a condition can express "wait until destroyed" as + // { op: "equals", value: null }. (Traversal THROUGH a destroyed object still throws + // the structured error above; only the leaf value normalizes.) + if (value is Object terminalUnityObject && !terminalUnityObject) + value = null; + + if (memberType == typeof(object) && value != null) + memberType = value.GetType(); + + return value; + } + + /// + /// Evaluate an operator against a freshly read value. For + /// changed, compares against (the first observed value) + /// and never needs an operand. All other operators coerce the JSON operand to + /// first. Sets (and returns false) when + /// the operator or operand cannot be applied. + /// + internal static bool Evaluate(string op, object current, object operandRaw, Type memberType, + object initialValue, bool haveInitial, out string error) + { + error = null; + // Mirrors WaitForCommands.ValidateCondition's normalization exactly: an empty string is + // as much "not specified" as a null, and the two must agree, or a condition that passed + // validation as a legal equals-wait (op:"") would fail every poll on "Unknown op ''". + op = string.IsNullOrEmpty(op) ? "equals" : op.Trim(); + + if (op == "changed") + return haveInitial && !ValuesEqual(current, initialValue); + + var operandIsNull = operandRaw == null + || (operandRaw is JToken nullToken && nullToken.Type == JTokenType.Null); + if (operandIsNull && (op == "equals" || op == "notEquals")) + { + // A null operand is meaningful for (in)equality — including "wait until + // destroyed", since ReadMember observes a destroyed leaf as null. Bypass coercion + // (there is no type to coerce null to) and compare null-ness directly, + // fake-null-aware for direct evaluator calls. + var isNull = current == null || (current is Object unityCurrent && !unityCurrent); + return op == "equals" ? isNull : !isNull; + } + + if (!TryCoerceOperand(operandRaw, memberType, out var operand, out error)) + return false; + + switch (op) + { + case "equals": + return ValuesEqual(current, operand); + case "notEquals": + return !ValuesEqual(current, operand); + case "greaterThan": + case "lessThan": + if (!TryCompareNumeric(current, operand, out var comparison, out error)) + return false; + return op == "greaterThan" ? comparison > 0 : comparison < 0; + case "contains": + if (!(current is string s)) + { + error = "op 'contains' requires a string member."; + return false; + } + var sub = operand as string ?? operand?.ToString() ?? string.Empty; + return s.IndexOf(sub, StringComparison.Ordinal) >= 0; + default: + error = $"Unknown op '{op}'."; + return false; + } + } + + /// + /// Resolve a type by assembly-qualified name, full name, or simple name across loaded + /// assemblies. This is the expensive whole-appdomain scan — callers cache the result on the + /// wait's so it runs at most once per wait, not per poll. + /// + internal static Type ResolveType(string name) => ResolveType(name, out _); + + internal static Type ResolveType(string name, out string ambiguityNote) + { + ambiguityNote = null; + if (string.IsNullOrEmpty(name)) + return null; + + var direct = Type.GetType(name, throwOnError: false); + if (direct != null) + return direct; + + foreach (var asm in PipelineUtils.GetLoadedAssemblies()) + { + var t = asm.GetType(name, throwOnError: false); + if (t != null) + return t; + } + + // A dotted name can never equal a simple Type.Name (which never contains '.') — skip + // the whole-appdomain scan below for it. This matters: ReadMember's static-path prefix + // loop calls ResolveType once per FAILING dotted prefix (e.g. "Ns.Type.Nested", "Ns.Type" + // for a 4-segment path), and without this guard every one of those burns a full scan that + // can never succeed. + if (name.IndexOf('.') >= 0) + return null; + + // Simple-name fallback: a bare name can match several loaded types (e.g. "Debug" in + // UnityEngine and System.Diagnostics). Bind DETERMINISTICALLY (lowest full name + // ordinally) instead of assembly-enumeration order, and surface the ambiguity as a + // note so the caller learns to fully qualify. + Type chosen = null; + List matches = null; + foreach (var asm in PipelineUtils.GetLoadedAssemblies()) + { + foreach (var candidate in SafeGetTypes(asm)) + { + // No FullName check here: the asm.GetType(name) pass above already covered + // every exact-full-name match, so by this point only simple names can hit. + if (candidate.Name != name) + continue; + if (chosen == null || string.CompareOrdinal(candidate.FullName, chosen.FullName) < 0) + chosen = candidate; + (matches ?? (matches = new List())).Add(candidate.FullName); + } + } + + if (matches != null && matches.Count > 1) + { + matches.Sort(StringComparer.Ordinal); + ambiguityNote = $"Type name '{name}' matched {matches.Count} loaded types " + + $"({string.Join(", ", matches.GetRange(0, Math.Min(matches.Count, 4)))}" + + (matches.Count > 4 ? ", ..." : "") + + $"); bound to '{chosen.FullName}'. Use the fully-qualified name to disambiguate."; + } + + return chosen; + } + + /// + /// Gate for retrying a previously failed type-resolution scan: true only when the set of + /// loaded assemblies has changed since the last attempt (recording a signature of the + /// current set, so the next failure waits for the next actual change). If the scan succeeds + /// the positive cache on the plan short-circuits all later polls and the recorded signature + /// is never consulted again. + /// + private static bool ShouldRescan(WaitConditionPlan plan) + { + var signature = AssemblySetSignature(PipelineUtils.GetLoadedAssemblies()); + if (signature == plan.FailedScanAssemblySignature) + return false; + plan.FailedScanAssemblySignature = signature; + return true; + } + + /// + /// Identity-based signature of a loaded-assembly set: combines each assembly's own + /// (identity) hash code, not just the set's Count. An unload-and-load-of-a-different- + /// assembly (e.g. a hot-reloaded script assembly) can leave the count unchanged while + /// swapping every member of the set — a count-only gate would then never re-attempt a scan + /// that just became resolvable. + /// + private static long AssemblySetSignature(IReadOnlyList assemblies) + { + unchecked + { + long hash = 17; + for (var i = 0; i < assemblies.Count; i++) + hash = hash * 31 + assemblies[i].GetHashCode(); + return hash; + } + } + + private static Type[] SafeGetTypes(Assembly assembly) + { + try + { + return assembly.GetTypes(); + } + catch (ReflectionTypeLoadException ex) + { + return ex.Types?.Where(t => t != null).ToArray() ?? Array.Empty(); + } + catch + { + return Array.Empty(); + } + } + + /// + /// Pick the live instance a findType wait binds to. Persistent objects + /// (prefab/asset files on disk — ) and hidden + /// editor internals (hideFlags != None) are excluded so the wait observes the live + /// instance, never the asset. Scene instances are preferred over loose runtime objects; + /// if several candidates still remain, the lowest instance id wins deterministically and + /// the ambiguity is reported via on the wait result. + /// + private static Object FindInstance(Type type, out string note) + { + note = null; + if (!typeof(Object).IsAssignableFrom(type)) + // A property of the resolved TYPE, not of whether an instance exists yet — + // permanent regardless of tolerate_missing. + throw new WaitEvaluationException( + $"findType '{type.FullName}' is not a UnityEngine.Object type; use a static member path or a 'target' handle.", + isPermanent: true); + + var all = Resources.FindObjectsOfTypeAll(type); + if (all == null || all.Length == 0) + return null; + + var candidates = new List(); + foreach (var o in all) + { + if (o == null) + continue; + if (EditorUtility.IsPersistent(o)) + continue; // a prefab or other asset on disk, not the live instance + if (o.hideFlags != HideFlags.None) + continue; // hidden editor internals / preview objects + candidates.Add(o); + } + + if (candidates.Count == 0) + return null; + if (candidates.Count == 1) + return candidates[0]; + + var sceneInstances = candidates.Where(IsSceneInstance).ToList(); + var pool = sceneInstances.Count > 0 ? sceneInstances : candidates; + // Version-stable ids: GetInstanceID() is obsolete-as-error from 6000.4. + var chosen = pool.OrderBy(o => PipelineUtils.GetObjectId(o).RawValue).First(); + if (pool.Count > 1) + note = $"findType '{type.FullName}' matched {pool.Count} live instances; bound to instanceId {PipelineUtils.GetObjectId(chosen).RawValue} (lowest). Use 'target' to select one explicitly."; + return chosen; + } + + private static bool IsSceneInstance(Object o) + { + var go = o as GameObject ?? (o as Component)?.gameObject; + return go != null && go.scene.IsValid(); + } + + /// + /// Read a single named field or property. The member lookup is memoized on the plan per + /// encountered runtime type, so only the first poll pays for reflection resolution. + /// Rejects write-only properties, indexers, and anything that is not a readable field/property. + /// + private static bool TryReadMember(WaitConditionPlan plan, int segmentIndex, Type lookup, string name, + bool isStatic, object instance, out object value, out Type type, out string error) + { + value = null; + type = null; + error = null; + + if (!plan.TryGetCachedMember(lookup, segmentIndex, isStatic, out var member)) + { + if (!TryResolveMember(lookup, name, isStatic, out member, out error)) + return false; + plan.CacheMember(lookup, segmentIndex, isStatic, member); + } + + if (member is PropertyInfo property) + { + value = property.GetValue(isStatic ? null : instance); + type = property.PropertyType; + return true; + } + + var field = (FieldInfo)member; + value = field.GetValue(isStatic ? null : instance); + type = field.FieldType; + return true; + } + + /// Resolve a named field or property, walking base types for inherited PUBLIC + /// members. Public-only is a deliberate security boundary (see ) — + /// the base walk exists because Type.GetField/GetProperty with declared-only semantics + /// would miss inherited members, not to reach private state. + private static bool TryResolveMember(Type lookup, string name, bool isStatic, + out MemberInfo member, out string error) + { + member = null; + error = null; + + var flags = MemberFlags | (isStatic ? BindingFlags.Static : BindingFlags.Instance) | BindingFlags.DeclaredOnly; + + for (var t = lookup; t != null; t = t.BaseType) + { + var property = t.GetProperty(name, flags); + if (property != null) + { + if (!property.CanRead) + { + error = $"Member '{name}' on '{lookup.FullName}' is write-only and cannot be observed."; + return false; + } + if (property.GetIndexParameters().Length > 0) + { + error = $"Member '{name}' on '{lookup.FullName}' is an indexer and cannot be observed."; + return false; + } + + member = property; + return true; + } + + var field = t.GetField(name, flags); + if (field != null) + { + member = field; + return true; + } + } + + error = $"No readable field or property '{name}' on type '{lookup.FullName}' " + + $"({(isStatic ? "static" : "instance")} members only; methods and write-only members are rejected)."; + return false; + } + + /// Coerce a JSON operand (JToken or boxed primitive/string) to the member's runtime type. + private static bool TryCoerceOperand(object raw, Type targetType, out object coerced, out string error) + { + coerced = null; + error = null; + + if (raw == null) + { + error = "condition.value is required for this operator."; + return false; + } + + try + { + var underlying = Nullable.GetUnderlyingType(targetType) ?? targetType; + + if (underlying.IsEnum) + { + var text = RawToString(raw); + if (!string.IsNullOrEmpty(text) && !LooksNumeric(text)) + { + coerced = Enum.Parse(underlying, text, ignoreCase: true); + return true; + } + var numeric = Convert.ToInt64(RawToScalar(raw)); + coerced = Enum.ToObject(underlying, numeric); + return true; + } + + var token = raw as JToken ?? JToken.FromObject(raw); + coerced = token.ToObject(underlying); + return true; + } + catch (Exception ex) + { + error = $"Could not coerce value '{RawToString(raw)}' to {targetType.Name}: {ex.Message}"; + return false; + } + } + + private static string RawToString(object raw) + { + if (raw is JToken token) + return token.Type == JTokenType.Null ? null : token.ToObject(); + return raw?.ToString(); + } + + private static object RawToScalar(object raw) + { + if (raw is JValue value) + return value.Value; + return raw; + } + + private static bool LooksNumeric(string text) + { + return long.TryParse(text, out _) || double.TryParse(text, out _); + } + + private static bool ValuesEqual(object a, object b) + { + if (a == null && b == null) + return true; + if (a == null || b == null) + return false; + + if (IsNumeric(a) && IsNumeric(b)) + { + // A float member must be compared at float precision: widening float to double + // manufactures noise digits (0.9f -> 0.90000003576...) that never equal the double + // operand parsed from JSON, so 'equals' on a float would never match. + if (a is float || b is float) + return Convert.ToSingle(a).Equals(Convert.ToSingle(b)); + if (a is double || b is double) + return Convert.ToDouble(a).Equals(Convert.ToDouble(b)); + // Both integral/decimal: compare exactly via decimal — a double round-trip + // collapses distinct values above 2^53 (9007199254740993 == 9007199254740992.0d). + return Convert.ToDecimal(a).Equals(Convert.ToDecimal(b)); + } + + if (a.Equals(b)) + return true; + + // Enum-vs-name / cross-type tolerance (e.g. an enum compared to its string name). + return string.Equals(a.ToString(), b.ToString(), StringComparison.Ordinal); + } + + /// + /// Ordering comparison that stays exact for integral/decimal operands (decimal compare — + /// double collapses distinct values above 2^53) and uses double only when a floating-point + /// side or an enum is genuinely involved. + /// + private static bool TryCompareNumeric(object a, object b, out int comparison, out string error) + { + comparison = 0; + if (IsExactNumeric(a) && IsExactNumeric(b)) + { + try + { + comparison = Convert.ToDecimal(a).CompareTo(Convert.ToDecimal(b)); + error = null; + return true; + } + catch (Exception ex) + { + error = $"Values '{a}' and '{b}' are not comparable: {ex.Message}"; + return false; + } + } + + if (!TryToDouble(a, out var da, out error)) + return false; + if (!TryToDouble(b, out var db, out error)) + return false; + comparison = da.CompareTo(db); + return true; + } + + private static bool IsExactNumeric(object value) => + value is sbyte || value is byte || value is short || value is ushort || + value is int || value is uint || value is long || value is ulong || value is decimal; + + private static bool TryToDouble(object value, out double result, out string error) + { + result = 0; + error = null; + + if (value == null) + { + error = "Cannot compare a null value numerically."; + return false; + } + + if (IsNumeric(value) || value is Enum) + { + try + { + result = Convert.ToDouble(value); + return true; + } + catch (Exception ex) + { + error = $"Value '{value}' is not numeric: {ex.Message}"; + return false; + } + } + + error = $"greaterThan/lessThan require a numeric member; got '{value.GetType().Name}'."; + return false; + } + + private static bool IsNumeric(object value) + { + switch (value) + { + case sbyte _: + case byte _: + case short _: + case ushort _: + case int _: + case uint _: + case long _: + case ulong _: + case float _: + case double _: + case decimal _: + return true; + default: + return false; + } + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/WaitConditionEvaluator.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/WaitConditionEvaluator.cs.meta new file mode 100644 index 0000000..82f921a --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/WaitConditionEvaluator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 949ea7e65d634f2fa4d4667fa6ec0794 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/WaitForCommands.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/WaitForCommands.cs new file mode 100644 index 0000000..ce2a19e --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/WaitForCommands.cs @@ -0,0 +1,515 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Unity.Pipeline; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor.Commands.Capture; +using Unity.Pipeline.Models; + +namespace Unity.Pipeline.Editor.Commands +{ + /// + /// Server-side condition waiting (AUTHAPI-25): wait_for blocks until a runtime/editor + /// member condition holds — evaluated per editor frame on the main thread — then optionally acts + /// in that same frame (on_met.capture/pause). This replaces the dominant agent + /// anti-pattern of client-side polling loops (read a value via eval, sleep in the client, repeat), + /// which is slow and can miss short-lived states across client round-trips. + /// + /// The wait runs off the main thread (MainThreadRequired = false) and marshals each poll + /// onto the main thread via the server dispatcher between sleeps, so the editor itself never + /// freezes. BUT a synchronous wait holds the exec gate for its whole duration: /api/exec + /// serializes commands, so every other command — including one whose effect the condition is + /// waiting for — queues behind it until it resolves (a self-deadlock that only breaks at the + /// timeout). Synchronous waits are therefore only for SHORT, self-contained conditions; pass + /// async=true for anything else to get a wait_id back immediately and poll + /// wait_status / cancel with wait_cancel while other commands keep executing. + /// + static class WaitForCommands + { + /// Poll interval clamp: below ~a frame is pointless, above 5s risks missing states and starves the timeout check. + internal const double MinPollIntervalMs = 16; + internal const double MaxPollIntervalMs = 5000; + + private static readonly string[] s_ValidOps = + { "equals", "notEquals", "greaterThan", "lessThan", "contains", "changed" }; + + /// + /// The action used for on_met.capture, indirected so tests can observe that it runs in + /// the same frame the condition holds without requiring a GPU (the real capture path needs + /// one). Mirrors RecompileCommand.s_FocusAction. + /// + internal static Func s_CaptureAction = DefaultCapture; + + /// Grace budget for the never-observed final look on a sync timeout (see the loop). + private const int FinalLookGraceMs = 1000; + + [CliCommand("wait_for", + "Wait server-side until a member condition holds, then optionally act in the same frame. Sync waits hold the exec queue (every other command waits behind them, including one the condition may depend on) — keep them short and self-contained; set async=true and poll wait_status for anything else.", + MainThreadRequired = false, Tags = new[] { "wait" })] + public static object WaitFor( + [CliArg("condition", "Condition to wait for: { member, target?, findType?, op, value }. member is a dotted path (static, or instance under target/findType); op is equals|notEquals|greaterThan|lessThan|contains|changed.", Required = true)] + WaitConditionInput condition = null, + [CliArg("timeout_s", "Maximum seconds to wait (default 30, clamped to 0-600; must be finite).")] + double timeoutS = 30, + [CliArg("poll_interval_ms", "How often to re-check the condition, in milliseconds (default 100, clamped to 16-5000; must be finite).")] + double pollIntervalMs = 100, + [CliArg("on_met", "Follow-up run in the same editor frame the condition first holds: { capture: { view, source, save_path, width, height, include_image }, pause }.")] + WaitOnMetInput onMet = null, + [CliArg("return_history", "Include the observed value/timestamp samples (a ring buffer of the last 200, so the tail near the transition is kept).")] + bool returnHistory = false, + [CliArg("tolerate_missing", "Treat resolution failures (type/member/instance not found) as condition-not-met and retry until timeout, instead of failing fast. Enables waiting for something to exist (e.g. a spawned object via findType).")] + bool tolerateMissing = false, + [CliArg("async", "Return a wait_id immediately and evaluate in the background; poll wait_status and cancel with wait_cancel. Use this for long waits and whenever the condition depends on a command you still need to issue — a sync wait blocks it.")] + bool async = false) + { + var validationError = ValidateCondition(condition); + if (validationError != null) + throw new ArgumentException(validationError); + + if (double.IsNaN(timeoutS) || double.IsInfinity(timeoutS)) + throw new ArgumentException("timeout_s must be a finite number of seconds (0-600)."); + if (double.IsNaN(pollIntervalMs) || double.IsInfinity(pollIntervalMs)) + throw new ArgumentException($"poll_interval_ms must be a finite number of milliseconds ({MinPollIntervalMs}-{MaxPollIntervalMs})."); + + var timeoutMs = Clamp(timeoutS, 0, 600) * 1000.0; + var interval = Clamp(pollIntervalMs, MinPollIntervalMs, MaxPollIntervalMs); + + var job = new WaitJob + { + Id = Guid.NewGuid().ToString("N"), + Condition = condition, + Plan = new WaitConditionPlan(condition), + OnMet = onMet, + ReturnHistory = returnHistory, + TolerateMissing = tolerateMissing, + IsAsync = async, + TimeoutMs = timeoutMs, + PollIntervalMs = interval, + StartedAt = DateTime.UtcNow + }; + + if (!WaitRegistry.TryRegister(job, out var registerError)) + throw new InvalidOperationException(registerError); + + if (async) + return job.ToResult(includeWaitId: true); + + try + { + while (true) + { + if (PipelineCancellation.IsCancellationRequested) + { + // A detached ("job": true) sync wait stays cancelable via /api/job/cancel. + job.MarkCanceled("Wait canceled by job cancellation request."); + break; + } + + try + { + // Bound the per-poll marshal by the wait's own remaining budget (min 1 ms, + // capped at the dispatcher default) instead of inheriting the dispatcher's + // 60s default: a stalled main thread must not hold the exec gate for 60s + // when this wait's whole timeout_s is shorter. + var marshalBudgetMs = (int)Math.Max(1, Math.Min(timeoutMs - job.ElapsedMs, 60000)); + RunOnMainThread(job.PollOnce, marshalBudgetMs); + } + catch (TimeoutException) + { + // A long main-thread stall (import, modal bake, ...) timed out the per-poll + // marshal after the dispatcher's default budget. That is a missed poll, not + // a failed wait — keep going until the wait's own budget expires. + } + catch (OperationCanceledException) + { + // The dispatcher is shutting down; never fall back to evaluating Unity + // state on this pool thread. + job.MarkInterrupted("Wait interrupted: the server is stopping."); + break; + } + + if (job.IsTerminal) + break; + + var remainingMs = timeoutMs - job.ElapsedMs; + if (remainingMs <= 0) + { + // Never resolve timedOut having observed NOTHING: if every earlier poll + // missed (main thread busy, tight budget), grant one final look with a + // small grace so the result carries a real value/framesObserved — parity + // with the Tick path's final look. + if (job.FramesObserved == 0) + { + try { RunOnMainThread(job.PollOnce, FinalLookGraceMs); } + catch (TimeoutException) { /* still stalled; report the bare timeout */ } + catch (OperationCanceledException) { job.MarkInterrupted("Wait interrupted: the server is stopping."); break; } + } + if (!job.IsTerminal) + job.MarkTimedOut(); + break; + } + + // Never sleep past the remaining budget (a large interval must not stretch a + // short timeout), and wake early if the surrounding job is canceled. + if (!SleepUnlessCanceled(Math.Min(interval, remainingMs), job)) + { + job.MarkCanceled("Wait canceled by job cancellation request."); + break; + } + } + + return job.ToResult(includeWaitId: false); + } + finally + { + // A synchronous wait is fully reported in its own response; do not retain it. + WaitRegistry.Remove(job.Id); + } + } + + /// + /// Sleep for in short slices, returning false as soon as cooperative + /// job cancellation is requested, and returning early (true) the moment + /// turns terminal — a domain-reload/play-mode interruption landing + /// mid-sleep must not wait out the rest of a poll interval (up to 5s) before the caller + /// notices; the loop re-checks IsTerminal at its top. + /// + private static bool SleepUnlessCanceled(double ms, WaitJob job) + { + var remaining = ms; + while (remaining > 0) + { + if (PipelineCancellation.IsCancellationRequested) + return false; + if (job.IsTerminal) + return true; + // Ceiling, never truncation: a fractional remaining (e.g. timeout_s=32.3 ends + // as ...999.9996 ms) would truncate to a 0 slice that never decrements + // `remaining` — an infinite spin that never releases the exec gate. + var slice = (int)Math.Ceiling(Math.Min(100.0, remaining)); + Thread.Sleep(slice); + remaining -= slice; + } + return !PipelineCancellation.IsCancellationRequested; + } + + [CliCommand("wait_status", + "Get the status/result of an async wait started with wait_for (async=true).", + MainThreadRequired = false, Tags = new[] { "wait" })] + public static object WaitStatus( + [CliArg("wait_id", "The wait id returned by wait_for when async=true.", Required = true)] + string waitId = null) + { + if (string.IsNullOrEmpty(waitId)) + throw new ArgumentException("wait_id is required."); + + if (!WaitRegistry.TryGet(waitId, out var job)) + return new WaitResult + { + WaitId = waitId, + State = "not_found", + Error = "No wait with that id (async waits do not survive domain reloads; completed waits are retained up to a bounded count and pruned oldest-first when a new wait is submitted)." + }; + + return job.ToResult(includeWaitId: true); + } + + [CliCommand("wait_cancel", + "Cancel an async wait started with wait_for (async=true).", + MainThreadRequired = false, Tags = new[] { "wait" })] + public static object WaitCancel( + [CliArg("wait_id", "The wait id to cancel.", Required = true)] + string waitId = null) + { + if (string.IsNullOrEmpty(waitId)) + throw new ArgumentException("wait_id is required."); + + if (!WaitRegistry.Cancel(waitId, out var job)) + return new WaitResult + { + WaitId = waitId, + State = "not_found", + Error = "No wait with that id." + }; + + return job.ToResult(includeWaitId: true); + } + + /// Validate the condition's shape up front so bad parameters fail fast as a 400 (not a wait result). + internal static string ValidateCondition(WaitConditionInput condition) + { + if (condition == null) + return "condition is required."; + if (string.IsNullOrWhiteSpace(condition.Member)) + return "condition.member is required."; + if (condition.Target != null && !condition.Target.IsEmpty && !string.IsNullOrEmpty(condition.FindType)) + return "condition.target and condition.findType are mutually exclusive — set one or the other " + + "(the evaluator would otherwise silently prefer target and observe the wrong object)."; + + var op = string.IsNullOrEmpty(condition.Op) ? "equals" : condition.Op.Trim(); + if (Array.IndexOf(s_ValidOps, op) < 0) + return $"condition.op '{op}' is invalid. Use one of: {string.Join(", ", s_ValidOps)}."; + + // Value is a JToken precisely so an OMITTED key (null reference) is distinguishable + // from an EXPLICIT JSON null (JTokenType.Null): omitting the operand is always an + // error outside op=changed (a forgotten value must not silently become an + // equals-null wait that can resolve immediately), while an explicit null is a + // meaningful equality operand — "wait until destroyed/null". + if (op != "changed" && condition.Value == null) + return $"condition.value is required for op '{op}' (send an explicit null to compare against null)."; + if ((op == "greaterThan" || op == "lessThan" || op == "contains") + && condition.Value != null && condition.Value.Type == JTokenType.Null) + return $"condition.value cannot be null for op '{op}'."; + + return null; + } + + /// + /// Run on the editor main thread via the executing server's + /// dispatcher (or directly when already on it / no server, e.g. a direct unit-test call), + /// waiting at most for the marshal — callers bound it by the + /// wait's own remaining budget so a stalled main thread cannot hold the exec gate past + /// this wait's timeout_s (the resulting is a missed poll). + /// Throws when the dispatcher is shut down instead + /// of falling back to evaluating Unity state on this pool thread — the caller resolves the + /// wait as interrupted ("server stopping"). + /// + private static void RunOnMainThread(Action action, int timeoutMs) + { + var server = BasePipelineServer.CurrentServer; + if (server == null) + { + // Direct in-process invocation (unit tests) on the test's main thread. + action(); + return; + } + + if (server.Dispatcher.IsMainThread()) + { + action(); + return; + } + + if (!server.Dispatcher.IsInitialized) + throw new OperationCanceledException("The server's main-thread dispatcher is shut down (server stopping)."); + + try + { + server.Dispatcher.Invoke(action, timeoutMs); + } + catch (InvalidOperationException) + { + // Shutdown() can flip Dispatcher.IsInitialized to false in the window between the + // check above and this call; Invoke then throws InvalidOperationException instead + // of running. Same outcome as catching it above: report as interrupted, not an + // unhandled fault escaping the command. + throw new OperationCanceledException("The server's main-thread dispatcher is shut down (server stopping)."); + } + } + + /// Reduce an observed value to a small, JSON-friendly form (enum names, primitives, or ToString()). + internal static object Jsonify(object value) + { + if (value == null) + return null; + if (value is Enum e) + return e.ToString(); + if (value is string || value is bool || value is decimal || value.GetType().IsPrimitive) + return value; + if (value is UnityEngine.Object unityObject) + // A cached LastValue/InitialValue can hold a reference that was alive when read + // but has since been destroyed (e.g. a retained terminal job's value re-serialized + // by a later wait_status call) — `!= null` misses Unity's fake-null and .ToString() + // on a destroyed native object throws instead of serializing. + return unityObject ? unityObject.ToString() : null; + return value.ToString(); + } + + internal static WaitCaptureResult RunCapture(WaitCaptureInput capture) => s_CaptureAction(capture); + + /// Test hook: restore the real capture action after a test swaps in a stub. + internal static void ResetCaptureActionForTests() => s_CaptureAction = DefaultCapture; + + private static WaitCaptureResult DefaultCapture(WaitCaptureInput capture) + { + var view = (capture.View ?? "game").Trim().ToLowerInvariant(); + if (view != "game" && view != "scene") + throw new ArgumentException( + $"Unknown view '{capture.View}' for on_met.capture. Use 'game' or 'scene'."); + var width = capture.Width <= 0 ? 1280 : capture.Width; + var height = capture.Height <= 0 ? 720 : capture.Height; + var source = string.IsNullOrWhiteSpace(capture.Source) ? "camera" : capture.Source.Trim().ToLowerInvariant(); + if (source != "camera" && source != "screen") + throw new ArgumentException( + $"Unknown source '{capture.Source}' for on_met.capture. Use 'camera' or 'screen'."); + + CaptureResult result = view == "scene" + ? CaptureCommands.CaptureSceneView(width, height, capture.SavePath, capture.IncludeImage, 0) + : CaptureCommands.CaptureGameView(width, height, null, capture.SavePath, capture.IncludeImage, 0, source); + + return new WaitCaptureResult + { + SavedPath = result.SavedPath, + Base64 = result.Base64, + Bytes = result.Bytes, + Source = result.Source, + Width = result.Width, + Height = result.Height + }; + } + + private static double Clamp(double value, double min, double max) + { + if (value < min) return min; + if (value > max) return max; + return value; + } + } + + /// The condition wait_for polls: which member to read, on which object, and how to compare it. + class WaitConditionInput : IStructuredCommandInput + { + [CliArg("member", "Dotted member path. With no target/findType it is a fully-qualified static path (e.g. \"UnityEditor.EditorApplication.isPlaying\"); with target/findType it walks instance members (e.g. \"State\" or \"Health.CurrentHealth\"). Read-only members only.", Required = true)] + public string Member { get; set; } + + [CliArg("target", "Object handle (instanceId / hierarchyPath / guid / path / globalId) to read instance members from. Omit for a static member path or to use findType.")] + public ObjectRef Target { get; set; } + + [CliArg("findType", "Fully-qualified UnityEngine.Object type name; the member walks from its first loaded instance. Alternative to target.")] + public string FindType { get; set; } + + [CliArg("op", "Comparison: equals (default) | notEquals | greaterThan | lessThan | contains (strings) | changed (met on first change from the initially observed value; needs no value). changed is for value-like members (primitives/enums/strings); content mutations inside a reference-typed member are not detected.")] + public string Op { get; set; } = "equals"; + + [CliArg("value", "Comparison operand, coerced to the member's type (primitive, enum name, or string). Required for every op except 'changed'. equals/notEquals accept an EXPLICIT null (e.g. wait-until-destroyed: a destroyed leaf value observes as null); omitting the key entirely is rejected.")] + public JToken Value { get; set; } + } + + /// Follow-up actions run in the same editor frame the condition first holds. + class WaitOnMetInput : IStructuredCommandInput + { + [CliArg("capture", "Capture the game or scene view the moment the condition holds (reuses the capture command internals).")] + public WaitCaptureInput Capture { get; set; } + + [CliArg("pause", "Pause play mode on the frame the condition holds (no-op outside play mode).")] + public bool Pause { get; set; } + } + + /// Capture options for on_met.capture (mirrors the capture commands' parameters). + class WaitCaptureInput : IStructuredCommandInput + { + [CliArg("view", "Which view to capture: game (default) or scene.")] + public string View { get; set; } = "game"; + + [CliArg("source", "Game view only: 'camera' (default) renders a camera and misses Screen Space - Overlay UI; 'screen' captures the composited game view incl. overlay canvases (HUDs), Play Mode only.")] + public string Source { get; set; } + + [CliArg("save_path", "Project-relative path to write the PNG (e.g. Screenshots/victory.png).")] + public string SavePath { get; set; } + + [CliArg("width", "Output width in px (default 1280).")] + public int Width { get; set; } = 1280; + + [CliArg("height", "Output height in px (default 720).")] + public int Height { get; set; } = 720; + + [CliArg("include_image", "Also return the PNG inline as base64 (default false: path-only when save_path is set).")] + public bool IncludeImage { get; set; } + } + + /// Result of a wait_for (sync response, or a snapshot from wait_status/wait_cancel). + [Serializable] + class WaitResult + { + /// Async wait id (present for async submissions and status/cancel snapshots). + [JsonProperty("waitId", NullValueHandling = NullValueHandling.Ignore)] + public string WaitId { get; set; } + + /// pending | met | timedOut | interrupted | canceled | failed | not_found. + [JsonProperty("state")] + public string State { get; set; } + + [JsonProperty("met")] + public bool Met { get; set; } + + [JsonProperty("timedOut")] + public bool TimedOut { get; set; } + + [JsonProperty("interrupted", NullValueHandling = NullValueHandling.Ignore)] + public bool? Interrupted { get; set; } + + [JsonProperty("member", NullValueHandling = NullValueHandling.Ignore)] + public string Member { get; set; } + + [JsonProperty("op", NullValueHandling = NullValueHandling.Ignore)] + public string Op { get; set; } + + /// The most recently observed value (the value at the moment the wait resolved). + [JsonProperty("value")] + public object Value { get; set; } + + /// The first observed value (baseline for op=changed). + [JsonProperty("initialValue")] + public object InitialValue { get; set; } + + [JsonProperty("elapsedMs")] + public long ElapsedMs { get; set; } + + [JsonProperty("framesObserved")] + public int FramesObserved { get; set; } + + [JsonProperty("error", NullValueHandling = NullValueHandling.Ignore)] + public string Error { get; set; } + + /// Set when the condition HELD but the on_met follow-up (capture/pause) threw — + /// the wait is still met; check this before trusting capture. + [JsonProperty("onMetError", NullValueHandling = NullValueHandling.Ignore)] + public string OnMetError { get; set; } + + /// Non-fatal resolution note (e.g. an ambiguous findType match bound deterministically). + [JsonProperty("note", NullValueHandling = NullValueHandling.Ignore)] + public string Note { get; set; } + + [JsonProperty("capture", NullValueHandling = NullValueHandling.Ignore)] + public WaitCaptureResult Capture { get; set; } + + [JsonProperty("history", NullValueHandling = NullValueHandling.Ignore)] + public List History { get; set; } + } + + /// The PNG written / rendered by an on_met.capture. + [Serializable] + class WaitCaptureResult + { + [JsonProperty("savedPath", NullValueHandling = NullValueHandling.Ignore)] + public string SavedPath { get; set; } + + [JsonProperty("base64", NullValueHandling = NullValueHandling.Ignore)] + public string Base64 { get; set; } + + [JsonProperty("bytes")] + public int Bytes { get; set; } + + [JsonProperty("source", NullValueHandling = NullValueHandling.Ignore)] + public string Source { get; set; } + + [JsonProperty("width")] + public int Width { get; set; } + + [JsonProperty("height")] + public int Height { get; set; } + } + + /// One observed sample (value + elapsed time) recorded when return_history is set. + [Serializable] + class WaitHistorySample + { + [JsonProperty("value")] + public object Value { get; set; } + + [JsonProperty("elapsedMs")] + public long ElapsedMs { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/WaitForCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/WaitForCommands.cs.meta new file mode 100644 index 0000000..2239cd0 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/WaitForCommands.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9d2d80c9117f4850977762fcabcec65d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/WaitRegistry.cs b/AIClient/Packages/com.unity.pipeline/Editor/Commands/WaitRegistry.cs new file mode 100644 index 0000000..2be1886 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/WaitRegistry.cs @@ -0,0 +1,596 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Unity.Pipeline; +using UnityEditor; +using UnityEngine; + +namespace Unity.Pipeline.Editor.Commands +{ + /// + /// One active or completed wait tracked by (AUTHAPI-25). + /// + /// The condition is evaluated by , which MUST run on the main thread: the + /// synchronous wait_for path marshals it there via the server dispatcher between sleeps + /// (so the main thread is never held hostage), while an async=true wait is polled by + /// on EditorApplication.update. Any follow-up action + /// (on_met.capture/pause) runs inside the same call that + /// first observes the condition true, so it acts in that same editor frame. + /// + internal sealed class WaitJob + { + internal const int MaxHistorySamples = 200; + + public string Id; + public WaitConditionInput Condition; + public WaitConditionPlan Plan; + public WaitOnMetInput OnMet; + public bool ReturnHistory; + public bool IsAsync; + public bool TolerateMissing; + public double PollIntervalMs; + public double TimeoutMs; + public DateTime StartedAt; + + /// Guards mutable state below; read from the request/background thread, mutated on the main thread. + public readonly object Gate = new object(); + + // --- guarded by Gate --- + /// Single source of truth for the lifecycle. Every public view (the five + /// booleans, the wire string, IsTerminal) derives from it, so a state transition can never + /// be half-applied and the terminal guard lives in exactly one place. + private WaitState m_State = WaitState.Pending; + /// Set while still-Pending but already committed to running the on_met + /// follow-up (its pause/capture side effects are about to happen for real, off the lock). + /// Blocks the same way a non-Pending state does, so a + /// concurrent cancel/interrupt/timeout cannot claim the job mid-follow-up: the follow-up's + /// side effects have already fired and must not be reported as if they never happened. + private bool m_Resolving; + public object InitialValue; + public bool HaveInitial; + public object LastValue; + public string Error; + public string ResolutionNote; + public int FramesObserved; + + /// Error from the on_met follow-up (capture/pause) when the condition held but the + /// follow-up threw — reported as onMetError, distinct from . + public string FollowupError; + public WaitCaptureResult Capture; + public readonly List History = new List(); + public DateTime? LastPollAt; + /// UTC time of the terminal transition; freezes so a + /// completed wait's elapsed time stops growing while it sits retained for wait_status. + private DateTime? m_TerminalAtUtc; + // --- end guarded --- + + /// NOTE: terminal transitions must go through — + /// it also checks (committed-to-on_met, not yet Met); a path + /// testing only m_State != Pending would reopen the cancel-vs-met race. + internal enum WaitState { Pending, Met, TimedOut, Interrupted, Canceled, Failed } + + public bool Met => ReadState() == WaitState.Met; + public bool TimedOut => ReadState() == WaitState.TimedOut; + public bool Interrupted => ReadState() == WaitState.Interrupted; + public bool Canceled => ReadState() == WaitState.Canceled; + public bool Failed => ReadState() == WaitState.Failed; + public bool IsTerminal => ReadState() != WaitState.Pending; + + /// Wire form: "pending" | "met" | "timedOut" | "interrupted" | "canceled" | "failed". + public string State => StateName(ReadState()); + + private WaitState ReadState() + { + lock (Gate) { return m_State; } + } + + private static string StateName(WaitState state) + { + switch (state) + { + case WaitState.Met: return "met"; + case WaitState.TimedOut: return "timedOut"; + case WaitState.Interrupted: return "interrupted"; + case WaitState.Canceled: return "canceled"; + case WaitState.Failed: return "failed"; + default: return "pending"; + } + } + + /// Milliseconds since the wait started, frozen at the terminal transition. + public long ElapsedMs + { + get + { + lock (Gate) + { + var end = m_TerminalAtUtc ?? DateTime.UtcNow; + return (long)(end - StartedAt).TotalMilliseconds; + } + } + } + + /// Record the terminal timestamp. Must be called with held. + private void MarkTerminalLocked() + { + if (m_TerminalAtUtc == null) + m_TerminalAtUtc = DateTime.UtcNow; + } + + /// UTC time this wait became terminal, or null while still pending. Set atomically + /// with the state transition (see ), so any job observed as + /// already has this set — used to prune the OLDEST-COMPLETED jobs + /// first, not the oldest-SUBMITTED ones (a long-running wait can have the earliest + /// in the registry yet be the most recently finished). + public DateTime? TerminalAtUtc + { + get { lock (Gate) { return m_TerminalAtUtc; } } + } + + /// + /// Evaluate the condition once on the main thread. Reads the member, records the observation, + /// and — on the first frame the condition holds — runs the follow-up action and transitions + /// to met. Resolution failures transition to failed (never to timedOut) + /// unless tolerate_missing is set, in which case they are recorded as the last error + /// and retried as condition-not-met (enables "wait until X exists"). No-op once the job is + /// already terminal. + /// + internal void PollOnce() + { + lock (Gate) + { + if (m_State != WaitState.Pending) + return; + LastPollAt = DateTime.UtcNow; + } + + var plan = Plan ?? (Plan = new WaitConditionPlan(Condition)); + + object value; + Type memberType; + try + { + value = WaitConditionEvaluator.ReadMember(plan, out memberType); + } + catch (Exception ex) + { + // WaitEvaluationException is the evaluator's own structured failure; anything else + // is a member getter throwing (reflection wraps those in TargetInvocationException) + // — a property body that throws, a MissingReferenceException, etc. Both must + // resolve the wait (or be tolerated), never escape: in the async Tick path an + // escaped exception is swallowed by Unity's event dispatch and the job would just + // time out with no cause; in the sync path it would propagate out of WaitFor raw. + var inner = (ex as System.Reflection.TargetInvocationException)?.InnerException ?? ex; + var resolutionFailure = inner as WaitEvaluationException; + var isResolutionFailure = resolutionFailure != null; + var message = isResolutionFailure + ? inner.Message + : $"Condition read threw {inner.GetType().Name}: {inner.Message}"; + lock (Gate) + { + if (m_State != WaitState.Pending) + return; // canceled/interrupted while the poll was reading + FramesObserved++; + if (TolerateMissing && isResolutionFailure && !resolutionFailure.IsPermanent) + { + // tolerate_missing is scoped to the evaluator's STRUCTURED resolution + // failures (type/member/instance not found) — its documented contract. + // A member getter that THROWS is a real failure, not "does not exist + // yet": retrying it would leave the wait pending until timeout and + // bury the actual exception. Nor is a PERMANENT resolution failure (a + // malformed path, a findType naming a non-Object type, a member that + // doesn't exist on the resolved type) — no amount of retrying makes those + // resolvable, so tolerating them would just bury a real misconfiguration + // until the timeout instead of failing fast. + Error = message; + return; + } + m_State = WaitState.Failed; + Error = message; + MarkTerminalLocked(); + } + return; + } + + object initialSnapshot; + bool haveInitial; + lock (Gate) + { + if (m_State != WaitState.Pending) + return; // canceled/interrupted while the poll was reading + FramesObserved++; + // A successful read supersedes any tolerated resolution error recorded above. + Error = null; + ResolutionNote = plan.ResolutionNote; + if (!HaveInitial) + { + InitialValue = value; + HaveInitial = true; + } + LastValue = value; + initialSnapshot = InitialValue; + haveInitial = HaveInitial; + + if (ReturnHistory) + { + // Ring buffer keeping the LAST samples: the tail near the transition is what + // diagnoses a wait, not the first 200 identical pre-transition observations. + if (History.Count >= MaxHistorySamples) + History.RemoveAt(0); + History.Add(new WaitHistorySample { Value = WaitForCommands.Jsonify(value), ElapsedMs = ElapsedMs }); + } + } + + bool met; + string evalError; + try + { + met = WaitConditionEvaluator.Evaluate(Condition.Op, value, Condition.Value, memberType, + initialSnapshot, haveInitial, out evalError); + } + catch (Exception ex) + { + met = false; + evalError = ex.Message; + } + + if (!string.IsNullOrEmpty(evalError)) + { + lock (Gate) + { + if (m_State != WaitState.Pending) + return; + if (TolerateMissing) + { + // Same contract as tolerated resolution failures: "cannot compare YET" + // (e.g. greaterThan while a nullable field is still null) retries until + // the budget expires, with the last error surfaced on timeout. The + // permanently-misconfigured variant (contains on a non-string member) + // spins the budget instead of failing fast — the same indistinguishable + // transient-vs-permanent tradeoff as null intermediates, accepted and + // documented. Getter exceptions still fail immediately (handled above). + Error = evalError; + return; + } + m_State = WaitState.Failed; + Error = evalError; + MarkTerminalLocked(); + } + return; + } + + if (!met) + return; + + // wait_cancel/MarkInterrupted/MarkTimedOut run on a different thread and can land any + // time from here on. Claim the job now (still Pending, so a status read in this window + // sees "pending") BEFORE running the on_met follow-up's side effects: this claim, not a + // state check either side of the follow-up, is what must be atomic with "am I about to + // pause/capture for real". Checking-then-running-then-checking-again left a window + // where a cancel could land IN BETWEEN — the pause/screenshot would still fire for + // real, but the job would then commit to canceled, silently discarding all trace that a + // real side effect happened (see review round 5). Once claimed, MarkCanceled / + // MarkInterrupted / MarkTimedOut all no-op (see TryEnterTerminal) for the rest of this + // poll, so the final commit below needs no re-check. + lock (Gate) + { + if (m_State != WaitState.Pending) + return; + m_Resolving = true; + } + + // Same-frame follow-up: this runs on the main thread within the poll that first saw the + // condition true, so a capture reflects that frame and a pause takes effect immediately. + WaitCaptureResult capture = null; + string followupError = null; + if (OnMet != null) + { + try + { + if (OnMet.Pause && Application.isPlaying) + EditorApplication.isPaused = true; + if (OnMet.Capture != null) + capture = WaitForCommands.RunCapture(OnMet.Capture); + } + catch (Exception ex) + { + followupError = $"on_met action failed: {ex.Message}"; + } + } + + lock (Gate) + { + m_State = WaitState.Met; + m_Resolving = false; + Capture = capture; + // The CONDITION held — the wait is met; a failed follow-up (capture/pause) is + // reported on its own field, never in Error: docs define error as the reason a + // wait FAILED, and stashing it there made a met-with-broken-capture reply look + // like a documented failure shape while state said otherwise. + FollowupError = followupError; + MarkTerminalLocked(); + } + } + + /// + /// Claim the terminal transition to , running + /// (e.g. to stamp ) under the same lock before freezing . + /// No-ops once the job is already terminal, OR mid-on_met-follow-up (see + /// ) — a wait that already committed to running real side effects + /// must finish committing to met, never be re-claimed as canceled/interrupted/timedOut. + /// + private void TryEnterTerminal(WaitState state, Action onClaimed = null) + { + lock (Gate) + { + if (m_State != WaitState.Pending || m_Resolving) + return; + m_State = state; + onClaimed?.Invoke(); + MarkTerminalLocked(); + } + } + + internal void MarkTimedOut() => TryEnterTerminal(WaitState.TimedOut); + + internal void MarkCanceled(string reason = null) => TryEnterTerminal(WaitState.Canceled, () => + { + if (!string.IsNullOrEmpty(reason)) + Error = reason; + }); + + internal void MarkInterrupted(string reason = null) => TryEnterTerminal(WaitState.Interrupted, () => + { + // The interruption cause always wins: a stale tolerated-resolution message left by + // an earlier poll must not masquerade as the reason the wait ended. + Error = !string.IsNullOrEmpty(reason) + ? reason + : "Wait interrupted by a domain reload or exiting play mode."; + }); + + internal WaitResult ToResult(bool includeWaitId) + { + lock (Gate) + { + return new WaitResult + { + WaitId = includeWaitId ? Id : null, + State = State, + Met = Met, + TimedOut = TimedOut, + Interrupted = Interrupted ? (bool?)true : null, + Member = Condition?.Member, + Op = string.IsNullOrEmpty(Condition?.Op) ? "equals" : Condition.Op, + Value = HaveInitial ? WaitForCommands.Jsonify(LastValue) : null, + InitialValue = HaveInitial ? WaitForCommands.Jsonify(InitialValue) : null, + ElapsedMs = ElapsedMs, + FramesObserved = FramesObserved, + Error = Error, + OnMetError = FollowupError, + Note = ResolutionNote, + Capture = Capture, + History = (ReturnHistory && History.Count > 0) + ? new List(History) + : null + }; + } + } + } + + /// + /// Process-wide registry of s (AUTHAPI-25). Async waits are polled here on + /// EditorApplication.update; synchronous waits register too (so the concurrency cap and + /// interruption hooks cover them) but are driven by their own command loop. A domain reload or + /// exiting play mode interrupts every active wait so it resolves to a structured + /// interrupted result rather than hanging or leaking. ENTERING play mode does not + /// interrupt: with domain reload disabled a wait survives into play mode; with reload enabled, + /// beforeAssemblyReload interrupts it anyway. + /// + /// PROCESS-WIDE by design — deliberately unlike , which is + /// per-server so one server's command results never cross into another. A wait has no + /// per-server state to isolate: it observes process-global editor state, is polled by the + /// single EditorApplication.update pump, and is interrupted by process-level events + /// (domain reload, play-mode exit). Ids are GUIDs, so waits from different servers cannot + /// collide, and intentionally bounds the shared update pump + /// rather than acting as a per-server quota. If true per-server isolation ever becomes a + /// requirement, scope this like JobRegistry at that point. + /// + /// In-memory: a domain reload discards pending waits the same way it discards every other + /// static — a poller then gets a clear "not found / does not survive domain reloads" result. + /// + internal static class WaitRegistry + { + /// Maximum simultaneously-active (non-terminal) waits; a further submission is rejected. + internal const int MaxConcurrentWaits = 8; + + /// Completed async jobs retained (for wait_status) beyond this count are pruned oldest-first. + internal const int MaxRetainedTerminal = 32; + + private static readonly Dictionary s_Jobs = new Dictionary(); + private static readonly object s_Gate = new object(); + + /// + /// Register a job, unless waits are already active (returns + /// false with a message the caller surfaces as a structured error). + /// + internal static bool TryRegister(WaitJob job, out string error) + { + lock (s_Gate) + { + PruneTerminal(); + + var active = s_Jobs.Values.Count(j => !j.IsTerminal); + if (active >= MaxConcurrentWaits) + { + error = $"Too many concurrent waits: {active} active (max {MaxConcurrentWaits}). Cancel one with wait_cancel or wait for one to complete."; + return false; + } + + s_Jobs[job.Id] = job; + } + + error = null; + return true; + } + + internal static bool TryGet(string id, out WaitJob job) + { + lock (s_Gate) + { + return s_Jobs.TryGetValue(id ?? string.Empty, out job); + } + } + + /// + /// Cancel a tracked wait by id. Returns true whenever the id is known — including when the + /// job had already reached a terminal state before this call: + /// no-ops in that case, so 's state stays whatever it actually resolved + /// to (never forced to "canceled") — see the honest-cancel-result note in wait.md. + /// + internal static bool Cancel(string id, out WaitJob job) + { + if (!TryGet(id, out job)) + return false; + job.MarkCanceled(); + return true; + } + + internal static void Remove(string id) + { + lock (s_Gate) + { + s_Jobs.Remove(id ?? string.Empty); + } + } + + internal static int ActiveCount + { + get + { + lock (s_Gate) + { + return s_Jobs.Values.Count(j => !j.IsTerminal); + } + } + } + + /// + /// Poll all active async waits whose poll interval has elapsed, and time out any that have + /// exceeded their budget. Subscribed to EditorApplication.update; also callable + /// directly from tests to drive async waits deterministically. + /// + internal static void Tick() + { + List pending = null; + lock (s_Gate) + { + foreach (var job in s_Jobs.Values) + { + if (job.IsAsync && !job.IsTerminal) + (pending ?? (pending = new List())).Add(job); + } + } + + if (pending != null) + { + foreach (var job in pending) + { + if (job.ElapsedMs >= job.TimeoutMs) + { + // Final look, unconditionally — full parity with the sync loop, which polls + // before every deadline check. A condition that flipped true between the + // last scheduled poll and the deadline must resolve met, not timedOut (and + // a never-polled job still reports a real value/framesObserved). + job.PollOnce(); + if (!job.IsTerminal) + job.MarkTimedOut(); + continue; + } + + double sincePoll; + lock (job.Gate) + { + sincePoll = job.LastPollAt.HasValue + ? (DateTime.UtcNow - job.LastPollAt.Value).TotalMilliseconds + : double.MaxValue; + } + + if (sincePoll >= job.PollIntervalMs) + job.PollOnce(); + } + } + + } + + /// + /// Subscriptions are installed unconditionally once per domain load, on the main thread — + /// the same idiom as every other EditorApplication.update poller in this package + /// (bake status, build, target switch). and + /// no-op when nothing is registered, so the permanent hooks cost one delegate call per + /// update. This replaces a lazy install/uninstall state machine whose main-thread marshal + /// could fail while the very jobs that needed the pump sat frozen. + /// + [InitializeOnLoadMethod] + private static void HookOnDomainLoad() + { + EditorApplication.update += Tick; + AssemblyReloadEvents.beforeAssemblyReload += InterruptAll; + EditorApplication.playModeStateChanged += OnPlayModeStateChanged; + } + + private static void OnPlayModeStateChanged(PlayModeStateChange change) + { + // Interrupt only when LEAVING play mode: the objects a wait observes are torn down + // then. Entering play mode does not interrupt — with domain reload disabled the wait + // survives into play mode (the common wait-for-gameplay-state case); with reload + // enabled, beforeAssemblyReload interrupts it anyway. + if (change == PlayModeStateChange.ExitingPlayMode) + InterruptAll(); + } + + private static void InterruptAll() + { + List active; + lock (s_Gate) + { + active = s_Jobs.Values.Where(j => !j.IsTerminal).ToList(); + } + foreach (var job in active) + job.MarkInterrupted(); + } + + private static void PruneTerminal() + { + // Oldest-COMPLETED first, not oldest-submitted: a long-running wait can have the + // earliest StartedAt of any job in the registry yet be the most recently finished, and + // sorting by StartedAt would evict it the instant it resolves while far-shorter waits + // that finished long ago (but were submitted later) survive. + var terminal = s_Jobs.Values + .Where(j => j.IsTerminal) + .OrderBy(j => j.TerminalAtUtc) + .ToList(); + + var excess = terminal.Count - MaxRetainedTerminal; + for (var i = 0; i < excess; i++) + s_Jobs.Remove(terminal[i].Id); + } + + /// Test hook: forget every tracked wait (main thread). The editor hooks installed + /// by are permanent by design and deliberately NOT removed — + /// do not re-subscribe them from tests. + internal static void ResetForTests() + { + lock (s_Gate) + { + s_Jobs.Clear(); + } + } + + /// Test hook: exercise the domain-reload/play-mode interruption transition without a live reload. + internal static void InterruptAllForTests() => InterruptAll(); + + /// Test hook: exercise the play-mode filter (interrupt on exit only) without entering play mode. + internal static void SimulatePlayModeChangeForTests(PlayModeStateChange change) => OnPlayModeStateChanged(change); + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Commands/WaitRegistry.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Commands/WaitRegistry.cs.meta new file mode 100644 index 0000000..8092d92 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Commands/WaitRegistry.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ba4fd5fb7e174b82ba6ca03266b31357 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Console.meta b/AIClient/Packages/com.unity.pipeline/Editor/Console.meta new file mode 100644 index 0000000..6b510e3 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Console.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 98aa20a2d767cba16cc6922b9e5bb32b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Console/EditorConsoleCaptureBootstrap.cs b/AIClient/Packages/com.unity.pipeline/Editor/Console/EditorConsoleCaptureBootstrap.cs new file mode 100644 index 0000000..75d3819 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Console/EditorConsoleCaptureBootstrap.cs @@ -0,0 +1,76 @@ +using System.Globalization; +using UnityEditor; +using Unity.Pipeline.Console; + +namespace Unity.Pipeline.Editor.Console +{ + /// + /// Editor-only bootstrap for . The capture itself (the shared + /// buffer and the log-callback subscription) lives in the runtime assembly so it also works in + /// player builds; this type adds the things that only make sense in the Editor: + /// + /// - [InitializeOnLoad] starts capture on every editor load and after every domain reload. + /// - Persistence to a Temp file across domain reloads, so entries and the cursor survive a + /// recompile. Players have no domain reloads, so the runtime path skips persistence. + /// - Re-subscribing on every play-mode transition: Unity clears + /// 's subscribers on play-mode + /// exit even though exiting play mode does not reload the domain, so capture would otherwise go + /// dead until the next recompile. + /// - A session identifier and a sequence floor in , so a client can + /// tell a cursor this editor session issued from one an earlier session did. + /// + /// The static constructor restores the persisted buffer first, then starts capture, so logs are + /// never appended ahead of a restore. + /// + [InitializeOnLoad] + public static class EditorConsoleCaptureBootstrap + { + // Lives under Temp/ like the recompile status file: cleared by Unity on project-level cleanup, + // survives domain reloads, and never committed. + internal const string PersistencePath = "Temp/pipeline_console_log.json"; + + // SessionState survives domain reloads and is cleared when the Editor restarts, which is + // exactly the lifetime of the Temp file the buffer persists to. Both therefore start over + // together, and the session identifier is what tells a client that happened. + internal const string SessionKey = "pipeline.console.session"; + internal const string SeqFloorKey = "pipeline.console.seq"; + + static EditorConsoleCaptureBootstrap() + { + var session = SessionState.GetString(SessionKey, string.Empty); + if (string.IsNullOrEmpty(session)) + { + session = System.Guid.NewGuid().ToString("N"); + SessionState.SetString(SessionKey, session); + } + + ConsoleLogCapture.Buffer.SetSession(session); + + // Restore before capture starts so restored entries precede any newly captured ones, and + // load before raising the floor: the floor is the same value the snapshot recorded, so + // raising it first would make every snapshot entry look already-issued and drop it. + ConsoleLogCapture.Buffer.Load(PersistencePath); + if (long.TryParse(SessionState.GetString(SeqFloorKey, "0"), NumberStyles.Integer, CultureInfo.InvariantCulture, out var floor)) + ConsoleLogCapture.Buffer.RaiseLastSeq(floor); + + ConsoleLogCapture.EnsureCapturing(); + + AssemblyReloadEvents.beforeAssemblyReload -= Persist; + AssemblyReloadEvents.beforeAssemblyReload += Persist; + + EditorApplication.quitting -= Persist; + EditorApplication.quitting += Persist; + + EditorApplication.playModeStateChanged -= OnPlayModeStateChanged; + EditorApplication.playModeStateChanged += OnPlayModeStateChanged; + } + + static void Persist() + { + ConsoleLogCapture.Buffer.Save(PersistencePath); + SessionState.SetString(SeqFloorKey, ConsoleLogCapture.Buffer.LastSeq.ToString(CultureInfo.InvariantCulture)); + } + + static void OnPlayModeStateChanged(PlayModeStateChange state) => ConsoleLogCapture.EnsureCapturing(); + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Console/EditorConsoleCaptureBootstrap.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Console/EditorConsoleCaptureBootstrap.cs.meta new file mode 100644 index 0000000..623e933 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Console/EditorConsoleCaptureBootstrap.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 1fb443a79f9bd099f5894c23de206319 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Console/EditorConsoleEntries.cs b/AIClient/Packages/com.unity.pipeline/Editor/Console/EditorConsoleEntries.cs new file mode 100644 index 0000000..3a654cb --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Console/EditorConsoleEntries.cs @@ -0,0 +1,224 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using UnityEngine; + +namespace Unity.Pipeline.Editor.Console +{ + /// + /// Reads the Editor console's own entry store through UnityEditor.LogEntries. + /// + /// This is the only way to see entries the package's log-callback capture never received. + /// Editor compile errors are logged with a sticky flag, and the console's Clear skips sticky + /// entries, so they survive the Clear button, Clear on Play, Clear on Build and Clear on + /// Recompile — only the next completed compile removes them. They can therefore stand in the + /// console long after the callback-fed buffer evicted them or was never subscribed. + /// + /// Reflection rather than a direct reference, because LogEntries is internal. Any failure + /// disables this permanently for the session and callers report the console as unseeded. + /// + static class EditorConsoleEntries + { + // ConsoleMode bits from Unity's native EditorMonoConsole (mirrored by the internal + // ConsoleWindow.ConsoleFlags): the three level toggles the console filter checks, and + // Collapse, which folds identical entries into a single row. + const int LevelFlags = (1 << 7) | (1 << 8) | (1 << 9); + const int CollapseFlag = 1 << 0; + + // LogMessageFlags bits, grouped exactly as Unity's own LogModeToLogType groups them. + const int ModeScriptingException = 1 << 17; + const int ModeErrors = (1 << 0) | (1 << 4) | (1 << 8) | (1 << 11) | (1 << 6); + const int ModeAsserts = (1 << 1) | (1 << 21); + const int ModeWarnings = (1 << 9) | (1 << 12) | (1 << 7); + + static readonly MethodInfo k_StartGettingEntries; + static readonly MethodInfo k_EndGettingEntries; + static readonly MethodInfo k_GetEntryInternal; + static readonly MethodInfo k_GetFilteringText; + static readonly MethodInfo k_SetFilteringText; + static readonly MethodInfo k_GetConsoleFlags; + static readonly MethodInfo k_SetConsoleFlags; + static readonly Type k_LogEntryType; + static readonly FieldInfo k_MessageField; + static readonly FieldInfo k_ModeField; + static readonly FieldInfo k_CallstackStartField; + + static bool s_Disabled; + + /// An entry as it stands in the Editor console. + internal struct Entry + { + public LogType Type; + public string Message; + public string StackTrace; + } + + static EditorConsoleEntries() + { + // LogEntries and LogEntry are internal, and LogEntries' members are static and + // non-public, so NonPublic is mandatory in the binding flags — GetMethod without it + // silently returns null. + const BindingFlags statics = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static; + + var logEntries = Type.GetType("UnityEditor.LogEntries,UnityEditor"); + k_LogEntryType = Type.GetType("UnityEditor.LogEntry,UnityEditor"); + if (logEntries == null || k_LogEntryType == null) + return; + + k_StartGettingEntries = logEntries.GetMethod("StartGettingEntries", statics); + k_EndGettingEntries = logEntries.GetMethod("EndGettingEntries", statics); + k_GetEntryInternal = logEntries.GetMethod("GetEntryInternal", statics); + k_GetFilteringText = logEntries.GetMethod("GetFilteringText", statics); + k_SetFilteringText = logEntries.GetMethod("SetFilteringText", statics); + + var consoleFlags = logEntries.GetProperty("consoleFlags", statics); + k_GetConsoleFlags = consoleFlags?.GetGetMethod(true); + k_SetConsoleFlags = consoleFlags?.GetSetMethod(true); + + const BindingFlags fields = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; + k_MessageField = k_LogEntryType.GetField("message", fields); + k_ModeField = k_LogEntryType.GetField("mode", fields); + k_CallstackStartField = k_LogEntryType.GetField("callstackTextStartUTF16", fields); + } + + /// + /// True when every member this reads was found and no read has failed yet. + /// + internal static bool Available => + !s_Disabled + && k_StartGettingEntries != null && k_EndGettingEntries != null && k_GetEntryInternal != null + && k_GetFilteringText != null && k_SetFilteringText != null + && k_GetConsoleFlags != null && k_SetConsoleFlags != null + && k_MessageField != null && k_ModeField != null && k_CallstackStartField != null; + + /// + /// Read up to most recent console entries, oldest first. Returns + /// false when the internal API is unavailable or the read failed, in which case + /// is left untouched. Main thread only. + /// + /// Maximum number of entries to read, taken from the end of the console. + /// Receives the entries read. + /// True when entries were read. + internal static bool TryReadRecent(int max, List into) + { + if (!Available || max <= 0) + return false; + + var flags = 0; + var filter = string.Empty; + var flagsMutated = false; + var filterMutated = false; + + try + { + flags = (int)k_GetConsoleFlags.Invoke(null, null); + filter = (string)k_GetFilteringText.Invoke(null, null) ?? string.Empty; + + // The console's row list is filtered by the level toggles and the search box, and + // Collapse folds repeats into one row, so a user who has any of them set would + // otherwise hide entries from this read. Open the view only when it is actually + // restricted: in the default state this mutates nothing and avoids two native + // re-filter passes. + // + // Collapse matters because the caller counts occurrences to work out what it missed; + // a collapsed row reports one where the console holds several. + // + // Both must happen outside the StartGettingEntries bracket: setting them rebuilds + // the filtered index, and reordering it under a live snapshot invalidates the row + // indices the read below uses. + var opened = (flags | LevelFlags) & ~CollapseFlag; + if (opened != flags) + { + k_SetConsoleFlags.Invoke(null, new object[] { opened }); + flagsMutated = true; + } + + if (!string.IsNullOrEmpty(filter)) + { + k_SetFilteringText.Invoke(null, new object[] { string.Empty }); + filterMutated = true; + } + + // StartGettingEntries returns the row count and pins it for the duration; GetCount + // would report that same pinned value, so there is no reason to ask twice. + var total = (int)k_StartGettingEntries.Invoke(null, null); + try + { + var entry = Activator.CreateInstance(k_LogEntryType); + var args = new object[2]; + for (var row = Math.Max(0, total - max); row < total; row++) + { + args[0] = row; + args[1] = entry; + if (!(bool)k_GetEntryInternal.Invoke(null, args)) + continue; + + into.Add(ToEntry(entry)); + } + } + finally + { + // Leaving the snapshot open pins the console's row count for every other reader + // and makes Unity warn on the next StartGettingEntries. + k_EndGettingEntries.Invoke(null, null); + } + + return true; + } + catch (Exception ex) + { + s_Disabled = true; + Debug.LogWarning($"[Pipeline] Cannot read the Editor console store; console entries logged before capture started will not be reported: {ex.Message}"); + return false; + } + finally + { + if (filterMutated) + TryRestore(k_SetFilteringText, filter); + if (flagsMutated) + TryRestore(k_SetConsoleFlags, flags); + } + } + + static Entry ToEntry(object logEntry) + { + var message = (string)k_MessageField.GetValue(logEntry) ?? string.Empty; + var mode = (int)k_ModeField.GetValue(logEntry); + + // A console entry stores its message and callstack in one string, split at this index. + var split = Mathf.Clamp((int)k_CallstackStartField.GetValue(logEntry), 0, message.Length); + + return new Entry + { + Type = ToLogType(mode), + Message = message.Substring(0, split), + StackTrace = message.Substring(split) + }; + } + + static LogType ToLogType(int mode) + { + if ((mode & ModeScriptingException) != 0) + return LogType.Exception; + if ((mode & ModeErrors) != 0) + return LogType.Error; + if ((mode & ModeAsserts) != 0) + return LogType.Assert; + if ((mode & ModeWarnings) != 0) + return LogType.Warning; + return LogType.Log; + } + + static void TryRestore(MethodInfo setter, object value) + { + try + { + setter.Invoke(null, new[] { value }); + } + catch (Exception ex) + { + Debug.LogWarning($"[Pipeline] Failed to restore Editor console filtering state: {ex.Message}"); + } + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Console/EditorConsoleEntries.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Console/EditorConsoleEntries.cs.meta new file mode 100644 index 0000000..6c1cf5d --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Console/EditorConsoleEntries.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 39378305cb7fde44aaae3a307420ac51 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Console/EditorConsoleGroundTruth.cs b/AIClient/Packages/com.unity.pipeline/Editor/Console/EditorConsoleGroundTruth.cs new file mode 100644 index 0000000..8f1c412 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Console/EditorConsoleGroundTruth.cs @@ -0,0 +1,254 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using Unity.Pipeline.Console; +using Unity.Pipeline.Models; +using UnityEditor; +using UnityEngine; + +namespace Unity.Pipeline.Editor.Console +{ + /// + /// Samples what the Editor knows about the console — the compile-failure flag and the console's + /// own entry counts — and publishes it for the console and recompile_status + /// commands. Those commands are deliberately not main-thread commands, because clients poll + /// them while the Editor is blocked compiling or importing, so they cannot read this state + /// themselves; sampling it here and handing over an immutable snapshot is what lets them report + /// it at all. + /// + /// The same pass does two more jobs that need the same main-thread tick: + /// - Backfills the buffer from the console's own store once per session, so sticky compile + /// errors logged before capture started are visible (see ). + /// - Watches for the console gaining entries while the buffer's cursor stands still, which is + /// the only observable symptom of the log-callback subscription having been dropped, and + /// re-arms capture when it sees it. + /// + /// Sampling runs on rather than + /// , because that event is raised from + /// ConsoleWindow.LogChanged, which returns early when no Console window exists — precisely the + /// case this targets. The event is subscribed only to shorten the wait when a window is open. + /// + [InitializeOnLoad] + static class EditorConsoleGroundTruth + { + const string SeededKey = "pipeline.console.seeded"; + const double SampleIntervalSeconds = 0.25; + const double ReseedCooldownSeconds = 5.0; + + static double s_NextSampleTime; + static double s_NextReseedTime; + static int s_LastConsoleTotal = -1; + static long s_LastBufferSeq = -1; + static bool s_GapPending; + static long s_GapSeq; + static bool s_Seeded; + + static EditorConsoleGroundTruth() + { + s_Seeded = SessionState.GetBool(SeededKey, false); + + EditorApplication.update -= Sample; + EditorApplication.update += Sample; + +#if UNITY_6000_0_OR_NEWER + // consoleLogsChanged is Unity 6+; on older editors sampling via update alone is enough. + ConsoleWindowUtility.consoleLogsChanged -= OnConsoleLogsChanged; + ConsoleWindowUtility.consoleLogsChanged += OnConsoleLogsChanged; +#endif + + AssemblyReloadEvents.afterAssemblyReload -= OnAfterAssemblyReload; + AssemblyReloadEvents.afterAssemblyReload += OnAfterAssemblyReload; + } + + /// + /// Console entry counts. Unity 6 exposes ConsoleWindowUtility.GetConsoleLogCounts; + /// Unity 2022 falls back to internal LogEntries.GetCountsByType via reflection. + /// + static void GetConsoleLogCounts(out int errors, out int warnings, out int logs) + { +#if UNITY_6000_0_OR_NEWER + ConsoleWindowUtility.GetConsoleLogCounts(out errors, out warnings, out logs); +#else + errors = warnings = logs = 0; + try + { + var logEntries = Type.GetType("UnityEditor.LogEntries,UnityEditor"); + var method = logEntries?.GetMethod( + "GetCountsByType", + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + if (method == null) + return; + + object[] args = { 0, 0, 0 }; + method.Invoke(null, args); + errors = (int)args[0]; + warnings = (int)args[1]; + logs = (int)args[2]; + } + catch + { + errors = warnings = logs = 0; + } +#endif + } + + static void Sample() + { + if (EditorApplication.timeSinceStartup < s_NextSampleTime) + return; + s_NextSampleTime = EditorApplication.timeSinceStartup + SampleIntervalSeconds; + + // Seed before publishing, so the first snapshot a client sees already reports whether + // the backfill happened. + if (!s_Seeded) + TrySeed(); + + GetConsoleLogCounts(out var errors, out var warnings, out var logs); + var total = errors + warnings + logs; + var seq = ConsoleLogCapture.Buffer.LastSeq; + + // The console gained entries while the buffer's cursor stood still. Unity unregisters + // the native log callback on domain unload and on play-mode exit, while the managed + // event keeps its subscriber list, so capture can be dead with nothing to test directly. + // + // A gap is confirmed by the cursor still sitting where it was one sample later, not by + // the console count growing again: a dead subscription that missed a single burst — a + // failed compile, say — would otherwise be spotted once and then forgotten. Waiting for + // the second sample keeps a console entry that legitimately never reaches the managed + // callback from re-arming on its own. A Clear lowers the counts, so it can never be + // mistaken for a gap. + if (s_GapPending && seq == s_GapSeq) + { + if (EditorApplication.timeSinceStartup >= s_NextReseedTime) + { + ConsoleLogCapture.EnsureCapturing(); + Reseed(); + seq = ConsoleLogCapture.Buffer.LastSeq; + s_NextReseedTime = EditorApplication.timeSinceStartup + ReseedCooldownSeconds; + s_GapPending = false; + } + } + else if (s_LastConsoleTotal >= 0 && total > s_LastConsoleTotal && seq == s_LastBufferSeq) + { + s_GapSeq = seq; + s_GapPending = true; + } + else + { + // The buffer caught up on its own. + s_GapPending = false; + } + + s_LastConsoleTotal = total; + s_LastBufferSeq = seq; + + ConsoleLogCapture.GroundTruth = new ConsoleGroundTruth + { + SampledUtc = DateTime.UtcNow, + CompilationFailed = EditorUtility.scriptCompilationFailed, + Compiling = EditorApplication.isCompiling, + ConsoleErrors = errors, + ConsoleWarnings = warnings, + ConsoleLogs = logs, + Seeded = s_Seeded + }; + } + + // Only shortens the wait for the next sample; never a correctness dependency, since it is + // not raised while the Console window is closed. +#if UNITY_6000_0_OR_NEWER + static void OnConsoleLogsChanged() => s_NextSampleTime = 0; +#endif + + static void OnAfterAssemblyReload() + { + ConsoleLogCapture.EnsureCapturing(); + + // The snapshot describes the domain that just went away, and on 6000.5+ it survives the + // reload with the rest of the statics. Drop it so nothing reads it as current until the + // next sample replaces it. + ConsoleLogCapture.GroundTruth = null; + + // Let the next sample establish a fresh baseline instead of comparing against counts + // and a cursor from before the reload, which would look like a gap. + s_LastConsoleTotal = -1; + s_LastBufferSeq = -1; + s_GapPending = false; + s_GapSeq = 0; + } + + static void TrySeed() + { + if (!Reseed()) + return; + + s_Seeded = true; + SessionState.SetBool(SeededKey, true); + } + + /// + /// Copy console entries the buffer does not already hold into it. Entries are matched on type + /// and message, the only fields both sides record identically. A log type never contains "|", + /// so the first one always terminates it and the key is unambiguous. + /// + /// Matching counts occurrences rather than presence, because the console holds repeated + /// messages by design. Treating a key as seen-or-not lets a row the buffer already has cancel + /// out an identical row it missed, and that row is then never recovered. + /// + static bool Reseed() + { + var entries = new List(); + if (!EditorConsoleEntries.TryReadRecent(ConsoleLogBuffer.Capacity, entries)) + return false; + + var held = new Dictionary(); + foreach (var entry in ConsoleLogCapture.Buffer.Query(-1, 0, ConsoleLogBuffer.SeverityLog).Entries) + { + var key = Key(entry.LogType, entry.Message); + held.TryGetValue(key, out var count); + held[key] = count + 1; + } + + var now = DateTime.UtcNow; + foreach (var entry in entries) + { + var key = Key(entry.Type.ToString(), entry.Message); + + // Consume one occurrence the buffer already holds; whatever the console has beyond + // that is what capture missed. + if (held.TryGetValue(key, out var remaining) && remaining > 0) + { + held[key] = remaining - 1; + continue; + } + + ConsoleLogCapture.Buffer.Add(entry.Type, entry.Message, entry.StackTrace, now, seeded: true); + } + + return true; + } + + static string Key(string logType, string message) => logType + "|" + message; + + /// Sample immediately, ignoring the throttle. For tests. + internal static void SampleForTests() + { + s_NextSampleTime = 0; + s_NextReseedTime = 0; + Sample(); + } + + /// Forget the baselines and the seeded flag, so the next sample starts over. For tests. + internal static void ResetForTests() + { + s_NextSampleTime = 0; + s_NextReseedTime = 0; + s_LastConsoleTotal = -1; + s_LastBufferSeq = -1; + s_GapPending = false; + s_GapSeq = 0; + s_Seeded = false; + SessionState.EraseBool(SeededKey); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Console/EditorConsoleGroundTruth.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Console/EditorConsoleGroundTruth.cs.meta new file mode 100644 index 0000000..bcb044e --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Console/EditorConsoleGroundTruth.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 132898ab39f8aaa4dbc6c7685e1214d6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/EditorCodeReloadWatcher.cs b/AIClient/Packages/com.unity.pipeline/Editor/EditorCodeReloadWatcher.cs new file mode 100644 index 0000000..4885840 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/EditorCodeReloadWatcher.cs @@ -0,0 +1,694 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Unity.Pipeline.Editor.Commands; +using Unity.Pipeline.CodeReload; +using UnityEditor; +using UnityEngine; + +namespace Unity.Pipeline.Editor +{ + /// + /// Watches a file or folder for .cs saves and re-applies the affected [CodeReload] + /// methods. The target is resolved automatically at each save: any connected development player + /// wins (broadcast push via ), + /// otherwise the reload applies in this editor process via . + /// Both paths run on the interpreter backend. Folder mode watches recursively, + /// only touching files that opt into code reload; the settings UI always watches the project's + /// Assets folder (StartWatch itself accepts any file or folder). + /// + /// Change detection is event-driven () — polling a whole tree every + /// editor tick would be prohibitive. The watcher can silently miss saves (macOS kqueue fd + /// exhaustion, atomic rename-based saves), so a low-rate poll of the .cs files' last-write + /// times backstops it; both paths feed the same debounce map, so a change seen by both applies once. + /// + /// Watches also re-push the watched state to any player that connects mid-watch: + /// pushed overrides live only in the player's memory, so a restarted player boots the original AOT + /// code. Standalone owner so the watch survives domain + /// reloads (state persisted in ); the Pipeline Settings inspector only + /// drives Start/Stop. + /// + [InitializeOnLoad] + static class EditorCodeReloadWatcher + { + private const double DebounceSeconds = 0.3; + // Reconciliation poll period; each poll only stats the watched .cs files, so it stays cheap. + private const double ReconcileIntervalSeconds = 2.0; + // PlayerConnection attaches early in player boot but the reload receiver only registers in + // RuntimePipelineDriver.Start(); an immediate push would go unheard. + private const double ReconnectPushDelaySeconds = 2.0; + + // Persisted so an active watch survives editor domain reloads. + private const string PkPath = "Pipeline.CodeReloadWatch.Path"; + private const string PkIsFolder = "Pipeline.CodeReloadWatch.IsFolder"; + // Prior values of the two auto-refresh prefs, persisted while a watch holds them at 0; -1 = we didn't change that key. + private const string PkPrevAutoRefresh = "Pipeline.CodeReloadWatch.PrevAutoRefresh"; + private const string PkPrevAutoRefreshMode = "Pipeline.CodeReloadWatch.PrevAutoRefreshMode"; + // Unity reads kAutoRefreshMode (0=disabled, 1=enabled, 2=enabled outside play mode) since 2021.2; + // kAutoRefresh is the pre-2021.2 bool. Set both — writing only the legacy key is a no-op on Unity 6. + private const string AutoRefreshPref = "kAutoRefresh"; + private const string AutoRefreshModePref = "kAutoRefreshMode"; + + private static bool s_Watching; + private static string s_WatchPath; + private static bool s_IsFolder; + private static int s_PrevAutoRefresh = -1; + private static int s_PrevAutoRefreshMode = -1; + + private static FileSystemWatcher s_Fsw; + // Set from the watcher's background thread when it faults (buffer overflow, backend failure); + // OnEditorUpdate recreates the watcher on the main thread — otherwise it dies silently while + // IsWatching keeps reporting true. + private static volatile bool s_WatcherFaulted; + private static string s_WatcherFaultMessage; + // FileSystemWatcher fires on background threads → enqueue here, drain on the main thread. + private static readonly ConcurrentQueue s_Changed = new ConcurrentQueue(); + // Main-thread-only: path → last-seen editor time, for per-file debounce. + private static readonly Dictionary s_Pending = new Dictionary(); + // Main-thread-only: path → last-write ticks the watch has accounted for. The reconciliation + // poll enqueues any .cs whose mtime differs (a save the FileSystemWatcher missed). Entries for + // deleted files linger until the next Start; bounded by .cs count, harmless. + private static readonly Dictionary s_KnownWriteTimes = new Dictionary(StringComparer.OrdinalIgnoreCase); + private static double s_NextReconcile; + + // Re-pushes due to players that connected mid-watch. Main-thread only; entries are + // (due time, player id). + private static readonly List<(double due, int playerId)> s_PendingReconnectPushes = new List<(double, int)>(); + private static bool s_ConnectHooked; + private static bool s_SuppressConnectCallbacks; + + /// Whether an in-editor watch is currently active. + public static bool IsWatching => s_Watching; + /// The file or folder being watched, or null when not watching. + public static string WatchPath => s_Watching ? s_WatchPath : null; + /// Whether the active watch is a folder (recursive) rather than a single file. + public static bool IsFolder => s_IsFolder; + /// Development players currently connected via PlayerConnection. This decides where a + /// save applies: any connected player wins (broadcast push), otherwise the reload runs in this + /// editor process. Initializes the connection so the count is accurate even before a watch + /// starts (Initialize is idempotent). + public static int ConnectedPlayerCount + { + get + { + try + { + var conn = UnityEditor.Networking.PlayerConnection.EditorConnection.instance; + conn.Initialize(); + return conn.ConnectedPlayers.Count; + } + catch { return 0; } + } + } + + // Liveness telemetry for the settings inspector: saves applying while the event count stays + // flat means the FileSystemWatcher is dead and the reconcile poll is carrying the watch. + // Session-only (reset by domain reloads and Start). + private static int s_FsEventCount; + private static long s_LastFsEventTicks; // DateTime.UtcNow ticks; written on the watcher thread + private static string s_LastApplyFile; // main thread only + private static long s_LastApplyTicks; + + /// Raw FileSystemWatcher events seen since the watch (re)started this session. + public static int FsEventCount => s_FsEventCount; + /// UTC time of the last raw watcher event, or null if none yet. + public static DateTime? LastFsEventUtc => TicksToUtc(System.Threading.Interlocked.Read(ref s_LastFsEventTicks)); + /// File name of the last reload attempt (either detection path), or null. + public static string LastApplyFile => s_LastApplyFile; + /// UTC time of the last reload attempt, or null if none yet. + public static DateTime? LastApplyUtc => TicksToUtc(s_LastApplyTicks); + + private static DateTime? TicksToUtc(long ticks) => + ticks == 0 ? (DateTime?)null : new DateTime(ticks, DateTimeKind.Utc); + + static EditorCodeReloadWatcher() + { + // Editor may not be fully ready at [InitializeOnLoad] time; resume on the next tick. + EditorApplication.delayCall += ResumeWatchIfPersisted; + // The FileSystemWatcher is unmanaged-backed; drop it before a domain reload and recreate on resume. + AssemblyReloadEvents.beforeAssemblyReload += DisposeWatcher; + } + + /// Start watching (a file, or a folder when ). + /// File mode applies once up front; folder mode only reacts to subsequent saves. No-op-with-error if the + /// path doesn't exist. + public static void StartWatch(string path, bool isFolder) + { + if (string.IsNullOrEmpty(path) || (isFolder ? !Directory.Exists(path) : !File.Exists(path))) + { + Debug.LogError($"[CodeReloadWatch] Cannot watch — {(isFolder ? "folder" : "file")} not found: {path}"); + return; + } + + s_WatchPath = Path.GetFullPath(path); + s_IsFolder = isFolder; + s_Watching = true; + s_Pending.Clear(); + while (s_Changed.TryDequeue(out _)) { } + BaselineWriteTimes(); + var baselines = CaptureMethodBaselines(); + ClearAppliedFilesJournal(); + s_FsEventCount = 0; + s_LastFsEventTicks = 0; + s_LastApplyFile = null; + s_LastApplyTicks = 0; + + // Turn auto-refresh off so saving a watched .cs doesn't domain-reload the editor (which would wipe + // the registered overrides and interrupt the watch). Restore only what we changed. + DisableAutoRefresh(); + + CreateWatcher(); + EditorApplication.update -= OnEditorUpdate; + EditorApplication.update += OnEditorUpdate; + HookPlayerConnect(); + + EditorPrefs.SetString(PkPath, s_WatchPath); + EditorPrefs.SetBool(PkIsFolder, isFolder); + EditorPrefs.SetInt(PkPrevAutoRefresh, s_PrevAutoRefresh); + EditorPrefs.SetInt(PkPrevAutoRefreshMode, s_PrevAutoRefreshMode); + + // Single file: apply once up front so its current state is live. Folder: don't bulk-compile the + // tree — only react to saves. + if (!isFolder) + Apply(s_WatchPath); + + Debug.Log($"[CodeReloadWatch] Watching {(isFolder ? "folder " : "")}{s_WatchPath} " + + $"[{DescribeTarget()}]; auto-refresh off" + (baselines != null ? $"; {baselines}" : "") + + ". Stop from Pipeline Settings."); + } + + /// Stop the active watch and restore auto-refresh. + public static void StopWatch() + { + if (!s_Watching) return; + s_Watching = false; + DisposeWatcher(); + UnhookPlayerConnect(); + EditorApplication.update -= OnEditorUpdate; + s_Pending.Clear(); + s_KnownWriteTimes.Clear(); + while (s_Changed.TryDequeue(out _)) { } + ClearAppliedFilesJournal(); + CodeReloadBaseline.Clear(); + SessionState.EraseString(SkMethodBaselines); + + RestoreAutoRefresh(); + + EditorPrefs.DeleteKey(PkPath); + EditorPrefs.DeleteKey(PkIsFolder); + EditorPrefs.DeleteKey(PkPrevAutoRefresh); + EditorPrefs.DeleteKey(PkPrevAutoRefreshMode); + Debug.Log("[CodeReloadWatch] Watch stopped; auto-refresh restored."); + } + + private static void ResumeWatchIfPersisted() + { + if (s_Watching) return; + var path = EditorPrefs.GetString(PkPath, null); + if (string.IsNullOrEmpty(path)) return; + + bool isFolder = EditorPrefs.GetBool(PkIsFolder, false); + bool exists = isFolder ? Directory.Exists(path) : File.Exists(path); + if (!exists) + { + EditorPrefs.DeleteKey(PkPath); + return; + } + + s_WatchPath = path; + s_IsFolder = isFolder; + s_PrevAutoRefresh = EditorPrefs.GetInt(PkPrevAutoRefresh, -1); + s_PrevAutoRefreshMode = EditorPrefs.GetInt(PkPrevAutoRefreshMode, -1); + s_Watching = true; + s_Pending.Clear(); + BaselineWriteTimes(); + + CreateWatcher(); + EditorApplication.update -= OnEditorUpdate; + EditorApplication.update += OnEditorUpdate; + HookPlayerConnect(); + + // Method baselines mirror the re-apply split below: an edit-mode reload means a real + // recompile ran, so disk is the compiled state again — recapture. A play-mode reload + // recompiled nothing (auto-refresh is off) and disk may already carry edits, so + // recapturing would bless those edits as "compiled"; restore the watch-start snapshot. + string baselines = null; + if (EditorApplication.isPlaying) + CodeReloadBaseline.Restore(SessionState.GetString(SkMethodBaselines, "")); + else + baselines = CaptureMethodBaselines(); + + // Edit-mode resume: don't re-apply — the reload came from a real recompile, so the + // compiled code already matches disk. Play-mode resume (entering play, or a mid-play + // reload) is different: the reload wiped CodeReloadRegistry's overrides but recompiled + // nothing (auto-refresh is off), so re-enqueue every file this watch had applied. + // Routing through s_Pending reuses the debounce, by which time the + // RuntimePipelineDriver has re-registered the reload targets (it runs in Awake). + var reapply = ComputeResumeReapplies(EditorApplication.isPlaying, GetJournaledAppliedFiles()); + if (reapply.Count > 0) + { + double now = EditorApplication.timeSinceStartup; + foreach (var f in reapply) + s_Pending[f] = now; + } + // One line per domain reload: what is watched, plus what this resume does about it. + Debug.Log($"[CodeReloadWatch] Resumed watching {path} after domain reload" + + (reapply.Count > 0 ? $"; re-applying {reapply.Count} code-reload override(s) the play-mode reload wiped" : "") + + (baselines != null ? $"; {baselines}" : "") + "."); + } + + /// Set both auto-refresh prefs to 0, remembering each prior value so Stop restores + /// exactly what the user had (the mode key is an enum — it may have been 2, not 1). + private static void DisableAutoRefresh() + { + int prev = EditorPrefs.GetInt(AutoRefreshPref, 1); + s_PrevAutoRefresh = prev == 0 ? -1 : prev; + if (s_PrevAutoRefresh >= 0) + EditorPrefs.SetInt(AutoRefreshPref, 0); + + int prevMode = EditorPrefs.GetInt(AutoRefreshModePref, 1); + s_PrevAutoRefreshMode = prevMode == 0 ? -1 : prevMode; + if (s_PrevAutoRefreshMode >= 0) + EditorPrefs.SetInt(AutoRefreshModePref, 0); + } + + private static void RestoreAutoRefresh() + { + if (s_PrevAutoRefresh >= 0) + EditorPrefs.SetInt(AutoRefreshPref, s_PrevAutoRefresh); + if (s_PrevAutoRefreshMode >= 0) + EditorPrefs.SetInt(AutoRefreshModePref, s_PrevAutoRefreshMode); + s_PrevAutoRefresh = -1; + s_PrevAutoRefreshMode = -1; + } + + private static void CreateWatcher() + { + DisposeWatcher(); + s_WatcherFaulted = false; // before enabling: a fault firing mid-create must not be wiped + try + { + var dir = s_IsFolder ? s_WatchPath : Path.GetDirectoryName(s_WatchPath); + s_Fsw = new FileSystemWatcher(dir) + { + Filter = s_IsFolder ? "*.cs" : Path.GetFileName(s_WatchPath), + IncludeSubdirectories = s_IsFolder, + NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName, + InternalBufferSize = 64 * 1024, + }; + s_Fsw.Changed += OnFsEvent; + s_Fsw.Created += OnFsEvent; + s_Fsw.Renamed += OnFsEvent; + s_Fsw.Error += OnFsError; + s_Fsw.EnableRaisingEvents = true; + } + catch (Exception ex) + { + Debug.LogError($"[CodeReloadWatch] Failed to start file watcher on {s_WatchPath}: {ex.Message}"); + } + } + + private static void HookPlayerConnect() + { + if (s_ConnectHooked) return; + try + { + // RegisterConnection replays the callback synchronously for players that are already + // connected; suppress those — folder watches deliberately don't bulk-push on start, + // and an already-running player still has whatever was pushed to it. Only players + // that connect *after* this (i.e. fresh boots with no overrides) need catching up. + s_SuppressConnectCallbacks = true; + UnityEditor.Networking.PlayerConnection.EditorConnection.instance.Initialize(); + UnityEditor.Networking.PlayerConnection.EditorConnection.instance.RegisterConnection(OnPlayerConnected); + s_ConnectHooked = true; + } + catch (Exception ex) + { + Debug.LogWarning($"[CodeReloadWatch] Could not hook player connections (reconnect re-push disabled): {ex.Message}"); + } + finally + { + s_SuppressConnectCallbacks = false; + } + } + + private static void UnhookPlayerConnect() + { + s_PendingReconnectPushes.Clear(); + if (!s_ConnectHooked) return; + try { UnityEditor.Networking.PlayerConnection.EditorConnection.instance.UnregisterConnection(OnPlayerConnected); } + catch { /* connection may be gone during teardown */ } + s_ConnectHooked = false; + } + + // Main thread (EditorConnection dispatches connection events there). + private static void OnPlayerConnected(int playerId) + { + if (s_SuppressConnectCallbacks || !s_Watching) return; + + // Read the setting at event time so an inspector toggle applies to the next connection + // without restarting the watch. No settings asset (CLI-driven watch) = enabled. + if (!(EditorPipelineManager.Load()?.CodeReloadRepushOnConnect ?? true)) + { + // Nothing happens until the next save, so this is first-reload-summary material, + // not a console entry of its own on every connect. + CodeReloadRegistry.NoteForFirstReload($"player {playerId} connected, not re-pushed " + + "(Re-push On Connect is off in Pipeline Settings; it catches up on the next save)"); + return; + } + + s_PendingReconnectPushes.Add((EditorApplication.timeSinceStartup + ReconnectPushDelaySeconds, playerId)); + Debug.Log($"[CodeReloadWatch] Player {playerId} connected — re-pushing watched code-reload state " + + $"in {ReconnectPushDelaySeconds:0}s (a restarted player has none of the previously pushed overrides)."); + } + + private static void OnFsEvent(object sender, FileSystemEventArgs e) + { + System.Threading.Interlocked.Increment(ref s_FsEventCount); + System.Threading.Interlocked.Exchange(ref s_LastFsEventTicks, DateTime.UtcNow.Ticks); + s_Changed.Enqueue(e.FullPath); + } + + // Background thread: only record the fault; the recreate must happen on the main thread. + private static void OnFsError(object sender, ErrorEventArgs e) + { + s_WatcherFaultMessage = e.GetException()?.Message ?? "unknown error"; + s_WatcherFaulted = true; + } + + private static void DisposeWatcher() + { + if (s_Fsw == null) return; + try { s_Fsw.EnableRaisingEvents = false; s_Fsw.Dispose(); } catch { /* best effort */ } + s_Fsw = null; + } + + private static void OnEditorUpdate() + { + if (!s_Watching) return; + + if (s_WatcherFaulted) + { + s_WatcherFaulted = false; + Debug.LogWarning($"[CodeReloadWatch] File watcher faulted ({s_WatcherFaultMessage}); " + + "recreating it. Changes saved in the meantime may have been missed — save again to re-apply."); + CreateWatcher(); + } + + double now = EditorApplication.timeSinceStartup; + + for (int i = s_PendingReconnectPushes.Count - 1; i >= 0; i--) + { + if (now < s_PendingReconnectPushes[i].due) continue; + int playerId = s_PendingReconnectPushes[i].playerId; + s_PendingReconnectPushes.RemoveAt(i); + PushReloadCommand.RepushAll(s_WatchPath, s_IsFolder, playerId); + } + + while (s_Changed.TryDequeue(out var p)) + if (!string.IsNullOrEmpty(p) && p.EndsWith(".cs", StringComparison.OrdinalIgnoreCase)) + { + s_Pending[p] = now; // (re)start this file's debounce window + // Stamp the accounted-for mtime so the reconcile poll doesn't re-enqueue a + // change the watcher already delivered. + try { s_KnownWriteTimes[p] = File.GetLastWriteTimeUtc(p).Ticks; } catch { /* transient */ } + } + + ReconcilePoll(now); + + if (s_Pending.Count == 0) return; + + List ready = null; + foreach (var kv in s_Pending) + if (now - kv.Value >= DebounceSeconds) + (ready ??= new List()).Add(kv.Key); + if (ready == null) return; + + foreach (var p in ready) + { + s_Pending.Remove(p); + if (File.Exists(p)) + Apply(p); + } + } + + /// Record the current last-write time of every watched .cs so the reconcile poll only + /// reacts to saves made after the watch (re)started — mirrors "don't re-apply on resume". + private static void BaselineWriteTimes() + { + s_KnownWriteTimes.Clear(); + try + { + if (s_IsFolder) + foreach (var f in Directory.EnumerateFiles(s_WatchPath, "*.cs", SearchOption.AllDirectories)) + s_KnownWriteTimes[f] = File.GetLastWriteTimeUtc(f).Ticks; + else + s_KnownWriteTimes[s_WatchPath] = File.GetLastWriteTimeUtc(s_WatchPath).Ticks; + } + catch { /* best effort — the poll fills in files it couldn't stat here */ } + s_NextReconcile = EditorApplication.timeSinceStartup + ReconcileIntervalSeconds; + } + + /// Low-rate safety net for saves the missed: stat the + /// watched .cs files and route any mtime change into the same debounce map the watcher feeds. + private static void ReconcilePoll(double now) + { + if (now < s_NextReconcile) return; + s_NextReconcile = now + ReconcileIntervalSeconds; + try + { + if (s_IsFolder) + { + foreach (var f in Directory.EnumerateFiles(s_WatchPath, "*.cs", SearchOption.AllDirectories)) + CheckWriteTime(f, now); + } + else if (File.Exists(s_WatchPath)) + { + CheckWriteTime(s_WatchPath, now); + } + } + catch { /* transient IO (file mid-write, folder shuffle) — next poll retries */ } + } + + private static void CheckWriteTime(string path, double now) + { + long ticks = File.GetLastWriteTimeUtc(path).Ticks; + if (s_KnownWriteTimes.TryGetValue(path, out var known) && known == ticks) + return; + s_KnownWriteTimes[path] = ticks; + s_Pending[path] = now; + } + + /// Apply one changed file to the active target. Never throws. + private static void Apply(string path) + { + // Folder mode: only compile files that actually opt into code reload — an unrelated .cs save in the + // tree shouldn't recompile or log. (Single-file mode was chosen explicitly, so always apply.) + if (s_IsFolder && !PushReloadCommand.FileMentionsCodeReload(path)) + return; + + s_LastApplyFile = Path.GetFileName(path); + s_LastApplyTicks = DateTime.UtcNow.Ticks; + + try + { + // Resolve the target per save, not per watch: a connected development player wins + // (connecting one is a deliberate act, and the in-editor path is a no-op outside + // play mode anyway), otherwise apply in this editor process. Plugging in or + // disconnecting a device mid-watch reroutes the next save with no restart. + if (ConnectedPlayerCount > 0) + { + // PushChanged logs its own summary; -1 broadcasts to every connected player. + // Baseline-filtered: methods untouched since the watch started stay compiled + // on the device instead of being re-registered as interpreter overrides. + PushReloadCommand.PushChanged(path, player: -1); + return; + } + + var result = InPlaceReloadProcessor.ProcessSourceFileOnMainThread( + path, assemblyDir: null, pdb: false, useInterpreter: true); + if (result.Success) + { + // ProcessSourceFileOnMainThread only binds the overrides; firing [OnCodeReload] + // callbacks on live instances is the caller's job (mirrors CodeReloadCommands.reload_file). + // Reverted methods changed behavior too (their override was removed), so they + // count as reloaded for the callbacks. + CodeReloadRegistry.InvokeReloadCallbacks( + result.RevertedMethods.Count == 0 + ? result.RegisteredMethods + : result.RegisteredMethods.Concat(result.RevertedMethods)); + + if (result.AllUpToDate) + { + Debug.Log($"[CodeReloadWatch] {Path.GetFileName(path)} is up to date — " + + $"{result.UpToDateMethods.Count} method(s) already match compiled code" + + (result.RevertedMethods.Count > 0 + ? $"; removed {result.RevertedMethods.Count} stale override(s)" : "") + "."); + } + // "Compiled but 0 methods bound" looks like success yet applies nothing — surface + // the per-method skip reasons (e.g. the runtime Pipeline isn't running, or the + // interpreter backend rejecting an unsupported construct) instead of a bare count. + else if (result.RegisteredMethods.Count == 0) + { + var reasons = result.CompilationDiagnostics != null && result.CompilationDiagnostics.Count > 0 + ? ":\n- " + string.Join("\n- ", result.CompilationDiagnostics) + : ". Is the runtime Pipeline driver active (in play mode)?"; + Debug.LogWarning($"[CodeReloadWatch] Compiled {Path.GetFileName(path)} " + + $"but bound 0 method(s){reasons}"); + } + else + { + // Journal it so the next play-mode domain reload (which wipes the registry + // while auto-refresh keeps the compiled code stale) re-applies this file. + JournalAppliedFile(path); + Debug.Log($"[CodeReloadWatch] Applied {Path.GetFileName(path)}: " + + $"{result.RegisteredMethods.Count} method(s)" + + (result.UpToDateMethods.Count > 0 + ? $" ({result.UpToDateMethods.Count} up to date, left compiled)" : "") + "."); + } + } + else + { + // Surface the actual compiler diagnostics, not just the generic ErrorMessage — + // otherwise the watcher path swallows the reason the reload_file command already reports. + var details = result.CompilationDiagnostics != null && result.CompilationDiagnostics.Count > 0 + ? ":\n- " + string.Join("\n- ", result.CompilationDiagnostics) + : ""; + Debug.LogError($"[CodeReloadWatch] Reload failed for {Path.GetFileName(path)}: {result.ErrorMessage}{details}"); + } + } + catch (Exception ex) + { + Debug.LogError($"[CodeReloadWatch] Reload error for {Path.GetFileName(path)}: {ex.Message}"); + } + } + + // Per-method baselines (CodeReloadBaseline) captured when the watch starts, i.e. when disk + // still matches the compiled code. Reloads diff each save against them and leave untouched + // methods running compiled instead of re-registering an interpreter override for the whole + // file. SessionState-backed for the same reason as the applied-files journal: the play-mode + // domain reload wipes the store while disk keeps the user's edits. + private const string SkMethodBaselines = "Pipeline.CodeReloadWatch.MethodBaselines"; + + /// Snapshot the compiled method bodies of the watched files. Returns a short clause + /// for the caller's log line (null when nothing was captured), so a watch start or resume + /// stays a single console entry. + private static string CaptureMethodBaselines() + { + CodeReloadBaseline.Clear(); + int captured = 0, stale = 0; + try + { + var files = s_IsFolder + ? Directory.EnumerateFiles(s_WatchPath, "*.cs", SearchOption.AllDirectories) + .Where(PushReloadCommand.FileMentionsCodeReload) + : (IEnumerable)new[] { s_WatchPath }; + + foreach (var f in files) + { + // A source newer than its compiled assembly was edited without a recompile — + // snapshotting it would bless those edits as "compiled" and silently skip them + // on the next save. Leave it baseline-less: every method reloads, like before. + if (!CompiledStateMatchesDisk(f)) + { + stale++; + continue; + } + + if (CodeReloadBaseline.Capture(f)) + captured++; + // Pushes diff under the player's defines; capture that variant too so a device + // save doesn't fall back to reloading everything when #if regions differ. + var playerDefines = PushReloadCommand.PlayerDefinesFor(f); + if (playerDefines != null) + CodeReloadBaseline.Capture(f, playerDefines); + } + } + catch (Exception ex) + { + Debug.LogWarning($"[CodeReloadWatch] Baseline capture failed ({ex.Message}); " + + "saves will reload every [CodeReload] method in a file."); + } + + SessionState.SetString(SkMethodBaselines, CodeReloadBaseline.Serialize()); + if (captured == 0 && stale == 0) + return null; + return $"method baselines captured for {captured} file(s)" + + (stale > 0 ? $" ({stale} newer than their compiled assembly, unfiltered)" : "") + + ", so saves only reload methods that differ"; + } + + /// Whether the compiled assembly owning is at least as new + /// as the file — i.e. the source on disk is what the editor is running. Unknown = false. + private static bool CompiledStateMatchesDisk(string path) + { + try + { + var projectRoot = Path.GetFullPath(Path.GetDirectoryName(Application.dataPath)); + var full = Path.GetFullPath(path); + if (!full.StartsWith(projectRoot, StringComparison.OrdinalIgnoreCase)) + return false; + var relative = full.Substring(projectRoot.Length).TrimStart('/', '\\').Replace('\\', '/'); + var asmName = UnityEditor.Compilation.CompilationPipeline.GetAssemblyNameFromScriptPath(relative); + if (string.IsNullOrEmpty(asmName)) + return false; + if (!asmName.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)) + asmName += ".dll"; + var dll = Path.Combine(projectRoot, "Library", "ScriptAssemblies", asmName); + return File.Exists(dll) && File.GetLastWriteTimeUtc(dll) >= File.GetLastWriteTimeUtc(full); + } + catch + { + return false; + } + } + + // Applied-files journal: full paths of files whose overrides this watch applied in-editor. + // SessionState-backed because the overrides it mirrors live only in CodeReloadRegistry's + // statics — the domain reload triggered by entering play mode wipes them while the watched + // sources stay un-recompiled (auto-refresh is off), so without this record the next play + // session silently runs the stale compiled bodies. Session-scoped, like the overrides. + private const string SkAppliedFiles = "Pipeline.CodeReloadWatch.AppliedFiles"; + + /// Record a file whose overrides were successfully applied in this editor process. + internal static void JournalAppliedFile(string path) + { + if (string.IsNullOrEmpty(path)) return; + var files = GetJournaledAppliedFiles(); + foreach (var f in files) + if (string.Equals(f, path, StringComparison.OrdinalIgnoreCase)) + return; + var joined = files.Length == 0 ? path : string.Join("\n", files) + "\n" + path; + SessionState.SetString(SkAppliedFiles, joined); + } + + /// All journaled applied files (empty when none). + internal static string[] GetJournaledAppliedFiles() + { + var raw = SessionState.GetString(SkAppliedFiles, ""); + return string.IsNullOrEmpty(raw) ? Array.Empty() : raw.Split('\n'); + } + + /// Forget all journaled applies (watch started/stopped: overrides no longer ours to restore). + internal static void ClearAppliedFilesJournal() => SessionState.EraseString(SkAppliedFiles); + + /// Files to re-apply when a watch resumes after a domain reload. Only in play mode: + /// there the reload wiped the registry without recompiling the watched sources, so disk and + /// compiled code have diverged. An edit-mode resume follows a real recompile — current + /// compiled state already matches disk, so nothing needs re-applying. + internal static List ComputeResumeReapplies(bool isPlaying, string[] journaledFiles) + { + var result = new List(); + if (!isPlaying || journaledFiles == null) return result; + foreach (var f in journaledFiles) + if (!string.IsNullOrEmpty(f) && File.Exists(f)) + result.Add(f); + return result; + } + + private static string DescribeTarget() => + "target: connected players when present, else in-editor (always interpreter)"; + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/EditorCodeReloadWatcher.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/EditorCodeReloadWatcher.cs.meta new file mode 100644 index 0000000..a7324fe --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/EditorCodeReloadWatcher.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5ef2773459c98e743988655aff847d46 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/EditorDialogStateMirror.cs b/AIClient/Packages/com.unity.pipeline/Editor/EditorDialogStateMirror.cs new file mode 100644 index 0000000..afbcf78 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/EditorDialogStateMirror.cs @@ -0,0 +1,52 @@ +#if UNITY_6000_7_OR_NEWER +using System; +using System.Linq; +using UnityEditor; + +namespace Unity.Pipeline.Editor +{ + /// + /// Mirrors UnityEditor.EditorDialogEvents into the live pipeline server's DialogStateTracker, + /// so GET /api/dialog, dialogsDuringExecution, and the dialog busy-gate all observe modal + /// dialogs with no per-command instrumentation (see the trunk-side design doc). Ambient + /// dialogs are a live-editor-wide concept, not per-test-server — targets the live server + /// explicitly, the same way EditorProgressMirror does, so a test server's DialogStateTracker + /// never receives them. + /// + [InitializeOnLoad] + internal static class EditorDialogStateMirror + { + static EditorDialogStateMirror() + { + EditorDialogEvents.dialogWillShow -= OnDialogWillShow; + EditorDialogEvents.dialogWillShow += OnDialogWillShow; + EditorDialogEvents.dialogDismissed -= OnDialogDismissed; + EditorDialogEvents.dialogDismissed += OnDialogDismissed; + } + + static void OnDialogWillShow(DialogEventInfo info) + { + var server = PipelineServerStartup.Server; + if (server == null) + return; + + // Still on the main thread here — dialogWillShow fires before the dialog actually + // blocks it — so this is the last chance to read live Editor state for the dialog + // busy-gate's editor_status fallback (see SnapshotStatusForDialogGate's doc). + server.SnapshotStatusForDialogGate(); + + server.Dialogs.OnShown(info.Id, info.Source.ToString(), info.Title, info.Message, + info.ButtonLabels?.ToArray(), info.Level?.ToString(), info.OpenedAtUtc); + } + + static void OnDialogDismissed(DialogEventInfo info) + { + var server = PipelineServerStartup.Server; + if (server == null) + return; + + server.Dialogs.OnDismissed(info.Id, DateTime.UtcNow); + } + } +} +#endif diff --git a/AIClient/Packages/com.unity.pipeline/Editor/EditorDialogStateMirror.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/EditorDialogStateMirror.cs.meta new file mode 100644 index 0000000..2aaf5a0 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/EditorDialogStateMirror.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: eebd91c94b7a4f5494390874c6beb9e9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetVersion: 1 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineManager.cs b/AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineManager.cs new file mode 100644 index 0000000..5cd2903 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineManager.cs @@ -0,0 +1,105 @@ +using UnityEditor; +using UnityEngine; + +namespace Unity.Pipeline.Editor +{ + /// + /// Inspectable configuration and control surface for the live editor pipeline server. This is a + /// settings asset, NOT the server's owner — owns the server + /// instance (a static owner survives domain reloads cleanly, whereas a ScriptableObject's + /// lifetime does not track the server across editor events). The owner reads this asset's config + /// when starting; the custom inspector drives Start/Stop through the owner and shows live status. + /// + /// The asset is optional: without it the owner uses the defaults below. "Window/Pipeline/Settings" + /// creates it on demand. + /// + class EditorPipelineManager : ScriptableObject + { + [Tooltip("HTTP port for the editor server. 0 = auto-assign from the 7800-7849 range. Applies on next start.")] + [SerializeField] private ushort m_Port = 0; + + [Tooltip("Start the server automatically when the editor loads. Applies on next editor load.")] + [SerializeField] private bool m_AutoStart = true; + + [Tooltip("Self-heal: if the HTTP listener dies without a Stop(), re-open it on a timer. " + + "Keeps auto-tick on so the editor keeps ticking while unfocused (required for the watchdog).")] + [SerializeField] private bool m_WatchdogEnabled = true; + + [Tooltip("How often the watchdog checks the listener, between 1 and 60 seconds.")] + [SerializeField] private int m_WatchdogIntervalSeconds = 5; + + [Tooltip("Log every command request/response (raw JSON) handled by the editor server to " + + "/Logs/pipeline.log. Editor only; applies live.")] + [SerializeField] private bool m_LogRequestsResponses = false; + + [Tooltip("Record local eval-usage telemetry (fingerprints + shape, no raw source) to " + + "/Library/Pipeline/eval-usage.jsonl. Read it back with the 'report_evals' " + + "command. Local-only; no data leaves the machine. Applies live.")] + [SerializeField] private bool m_EvalTelemetryEnabled = true; + + [Tooltip("Also store the raw eval source in each eval-usage telemetry record. Off by default " + + "(privacy-first) — enable only for local debugging. Applies live.")] + [SerializeField] private bool m_StoreEvalSource = false; + + [Tooltip("Accept requests from a client running in a sandboxed browser frame (Origin: null), " + + "such as a plugin hosted inside a web application. An ordinary web page is refused " + + "either way, and a sandboxed one still needs the bearer token. Applies on next start.")] + [SerializeField] private bool m_AllowBrowserClients = false; + + // Code Reload Watch config, drawn by a dedicated inspector section (not DrawDefaultInspector). + [HideInInspector, SerializeField, UnityEngine.Serialization.FormerlySerializedAs("m_HotReloadRepushOnConnect")] + private bool m_CodeReloadRepushOnConnect = true; + + /// HTTP port for the editor server. 0 = auto-assign. Applies on next start. + public int Port => m_Port; + /// Start the server automatically when the editor loads. + public bool AutoStart => m_AutoStart; + /// Self-heal: re-open the listener on a timer if it dies without a Stop(). + public bool WatchdogEnabled => m_WatchdogEnabled; + /// How often the watchdog checks the listener, in seconds. + public int WatchdogIntervalSeconds => m_WatchdogIntervalSeconds; + /// Log every command request/response to Logs/pipeline.log. + public bool LogRequestsResponses => m_LogRequestsResponses; + public bool EvalTelemetryEnabled => m_EvalTelemetryEnabled; + public bool StoreEvalSource => m_StoreEvalSource; + public bool AllowBrowserClients => m_AllowBrowserClients; + + /// Player-target watches: re-push the watched code-reload state to any player that + /// connects mid-watch, so a restarted player catches up without waiting for the next save. + internal bool CodeReloadRepushOnConnect => m_CodeReloadRepushOnConnect; + + /// Whether the live server (owned by PipelineServerStartup) is actually running. + public bool IsServerRunning => PipelineServerStartup.Server != null && PipelineServerStartup.Server.IsRunning; + + /// The port the live server is actually listening on, or 0 when stopped. + public int ActualPort => PipelineServerStartup.Server?.Port ?? 0; + + /// Start the live server (delegates to the static owner, which reads this config). + public void StartServer() => PipelineServerStartup.EnsureServerStarted(); + + /// Stop the live server. + public void StopServer() => PipelineServerStartup.StopServer(); + + /// Restart the live server. + public void RestartServer() => PipelineServerStartup.RestartServer(); + + /// + /// Load the single settings asset if one exists, otherwise null (the owner falls back to + /// defaults). No caching — assets are cheap to look up and this is only read at start/inspect. + /// + /// The settings asset, or null if none exists. + public static EditorPipelineManager Load() + { + var guids = AssetDatabase.FindAssets("t:EditorPipelineManager"); + if (guids.Length == 0) + return null; + return AssetDatabase.LoadAssetAtPath( + AssetDatabase.GUIDToAssetPath(guids[0])); + } + + private void OnValidate() + { + m_WatchdogIntervalSeconds = Mathf.Clamp(m_WatchdogIntervalSeconds, 1, 60); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineManager.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineManager.cs.meta new file mode 100644 index 0000000..1196d74 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9e6f601455c0e0549b841c969d30c2b7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineManagerEditor.cs b/AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineManagerEditor.cs new file mode 100644 index 0000000..a13d2f1 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineManagerEditor.cs @@ -0,0 +1,196 @@ +using System.IO; +using UnityEditor; +using UnityEngine; + +namespace Unity.Pipeline.Editor +{ + /// + /// Custom inspector for the settings asset: shows live server + /// status (accurate running check + actual port, read from the static owner) and offers + /// Start/Stop/Restart buttons, alongside the editable configuration. Watchdog edits are pushed to + /// a running server immediately; port/autoStart apply on the next start. + /// + [CustomEditor(typeof(EditorPipelineManager))] + class EditorPipelineManagerEditor : UnityEditor.Editor + { + // Repaint() from inside OnInspectorGUI re-triggers OnInspectorGUI on the next editor tick, so + // a running server redrew this IMGUI-heavy inspector every frame (several ms) while merely + // visible. Repaint from EditorApplication.update at a low rate instead. + private const double StatusRepaintInterval = 0.25; + private double m_NextStatusRepaint; + + private void OnEnable() + { + EditorApplication.update += ThrottledStatusRepaint; + } + + private void OnDisable() + { + EditorApplication.update -= ThrottledStatusRepaint; + } + + private void ThrottledStatusRepaint() + { + var mgr = target as EditorPipelineManager; + if (mgr == null || !(mgr.IsServerRunning || EditorCodeReloadWatcher.IsWatching)) + return; + + double now = EditorApplication.timeSinceStartup; + if (now < m_NextStatusRepaint) + return; + m_NextStatusRepaint = now + StatusRepaintInterval; + Repaint(); + } + + /// Draw the default inspector plus live server status and Start/Stop/Restart controls. + public override void OnInspectorGUI() + { + var mgr = (EditorPipelineManager)target; + + EditorGUI.BeginChangeCheck(); + DrawDefaultInspector(); + if (EditorGUI.EndChangeCheck()) + { + // Push edited watchdog config to the live server (owned by PipelineServerStartup), so + // changes take effect without a restart. + var server = PipelineServerStartup.Server; + if (server != null) + { + server.WatchdogEnabled = mgr.WatchdogEnabled; + server.WatchdogIntervalSeconds = mgr.WatchdogIntervalSeconds; + server.LogRequestsResponses = mgr.LogRequestsResponses; + } + + // Eval-usage telemetry config lives on static fields (recording happens in the + // Runtime command layer, not the server), so push edits there too — applies live. + // Goes through the same ApplyEvalTelemetrySettings the startup/server-start paths + // use, so there is exactly one place that knows the settings->statics mapping. + PipelineServerStartup.ApplyEvalTelemetrySettings(mgr); + } + + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Status", EditorStyles.boldLabel); + using (new EditorGUI.DisabledScope(true)) + { + EditorGUILayout.Toggle("Running", mgr.IsServerRunning); + EditorGUILayout.IntField("Actual Port", mgr.ActualPort); + } + + EditorGUILayout.Space(); + using (new EditorGUILayout.HorizontalScope()) + { + using (new EditorGUI.DisabledScope(mgr.IsServerRunning)) + { + if (GUILayout.Button("Start")) + mgr.StartServer(); + } + using (new EditorGUI.DisabledScope(!mgr.IsServerRunning)) + { + if (GUILayout.Button("Stop")) + mgr.StopServer(); + } + if (GUILayout.Button("Restart")) + mgr.RestartServer(); + } + + DrawCodeReloadWatchSection(); + // Live status is kept current by ThrottledStatusRepaint — never Repaint() from here. + } + + /// + /// Watch the project's Assets folder and re-apply affected [CodeReload] methods on every save, + /// driving . Neither scope, target, nor backend is a + /// choice: the whole Assets tree is watched, each save goes to the connected player(s) if any, + /// else applies in-editor, and both paths run on the interpreter; a read-only row shows the + /// current target resolution. Config is locked while a watch is active. + /// + private void DrawCodeReloadWatchSection() + { + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Code Reload Interpreter Watch", EditorStyles.boldLabel); + + bool watching = EditorCodeReloadWatcher.IsWatching; + + serializedObject.Update(); + + // Not a picker: each save is pushed to the connected player(s) if any, else applied + // in-editor — resolved per save, so plugging in a device mid-watch reroutes the next save. + int connected = EditorCodeReloadWatcher.ConnectedPlayerCount; + using (new EditorGUI.DisabledScope(true)) + EditorGUILayout.LabelField( + new GUIContent("Target", "Resolved automatically at each file change: development player(s) if connected, otherwise the reload applies in this editor process. Both run on the interpreter."), + new GUIContent(connected > 0 + ? $"Player — {connected} connected" + : "In Editor — no player connected")); + + // Outside the watching-locked scope: read at each player-connect event, so toggling it + // takes effect for the next connection even while a watch is active. + EditorGUILayout.PropertyField( + serializedObject.FindProperty("m_CodeReloadRepushOnConnect"), + new GUIContent("Re-push On Connect", + "Re-push the watched code-reload state to any player that connects while the watch " + + "is active. A restarted player boots the original build without previously pushed " + + "overrides; this catches it up immediately instead of waiting for the next save.")); + + serializedObject.ApplyModifiedProperties(); + + using (new EditorGUILayout.HorizontalScope()) + { + using (new EditorGUI.DisabledScope(watching)) + { + // The UI always watches the whole Assets tree; StartWatch itself accepts any + // file or folder for CLI/API callers. + if (GUILayout.Button("Start Watching")) + EditorCodeReloadWatcher.StartWatch(Path.GetFullPath(Application.dataPath), + isFolder: true); + } + using (new EditorGUI.DisabledScope(!watching)) + { + if (GUILayout.Button("Stop Watching")) + EditorCodeReloadWatcher.StopWatch(); + } + } + + if (watching) + EditorGUILayout.HelpBox( + "Asset auto-refresh is disabled while watching, so saved scripts code-reload instead of " + + "triggering a domain reload. New or changed assets won't import until you refresh manually " + + "(Cmd/Ctrl+R); Stop Watching restores your auto-refresh setting.", + MessageType.Warning); + + using (new EditorGUI.DisabledScope(true)) + { + // Read WatchPath once: it goes null the instant the watch stops (domain reload / StopWatch), + // which can race the `watching` captured at the top of this method — guard against null here. + var watchPath = EditorCodeReloadWatcher.WatchPath; + // The live Target row above shows where saves currently go; this line covers what is watched. + string status = watching && !string.IsNullOrEmpty(watchPath) + ? $"{(EditorCodeReloadWatcher.IsFolder ? "folder" : "file")} · {Path.GetFileName(watchPath.TrimEnd('/', '\\'))}" + : "idle"; + EditorGUILayout.LabelField("Watching", status); + + if (watching) + { + // Liveness: saves applying while the event count stays flat means the OS file + // watcher is dead and the reconcile poll is carrying the watch. + EditorGUILayout.LabelField("Watcher Events", + $"{EditorCodeReloadWatcher.FsEventCount}{Ago(EditorCodeReloadWatcher.LastFsEventUtc)}"); + EditorGUILayout.LabelField("Last Apply", + EditorCodeReloadWatcher.LastApplyFile is string f + ? $"{f}{Ago(EditorCodeReloadWatcher.LastApplyUtc)}" + : "none yet"); + } + } + } + + private static string Ago(System.DateTime? utc) + { + if (utc == null) return ""; + var s = (System.DateTime.UtcNow - utc.Value).TotalSeconds; + return s < 1 ? " · just now" + : s < 120 ? $" · {s:0}s ago" + : s < 7200 ? $" · {s / 60:0}m ago" + : $" · {s / 3600:0}h ago"; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineManagerEditor.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineManagerEditor.cs.meta new file mode 100644 index 0000000..9d89150 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineManagerEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8a6ccaaae4fdc6f429517e759dbad721 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineServer.cs b/AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineServer.cs new file mode 100644 index 0000000..3cddf42 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineServer.cs @@ -0,0 +1,372 @@ +using System; +using System.Collections.Generic; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor.Commands; +using Unity.Pipeline.Models; +using Unity.Pipeline.Security; +using UnityEditor; +using UnityEngine; +#if UNITY_6000_5_OR_NEWER +using Unity.Scripting.LifecycleManagement; +#endif + +namespace Unity.Pipeline.Editor +{ +#if UNITY_6000_5_OR_NEWER + [NoAutoStaticsCleanup] +#endif + class EditorPipelineServer : BasePipelineServer + { + private InstanceDescriptor m_InstanceDescriptor; + + /// + /// Guards mutate-then-write of m_InstanceDescriptor: /api/status and /api/editor_status + /// both reach UpdateHeartBeat concurrently now, and InstanceDescriptor.WriteToProjectRoot's + /// own lock only covers the write, not the field mutations feeding it. + /// + private readonly object m_HeartbeatLock = new object(); + + /// + /// One-way settle latch (AUTHAPI-35). On a cold project import the server starts (and + /// writes its descriptor) while the Editor is still importing assets / compiling scripts, + /// so early main-thread commands land in a not-quite-ready Editor and fail opaquely. The + /// latch stays false until the Editor is first seen idle after startup, and is scoped to + /// the EDITOR SESSION via : once any server instance has + /// seen the Editor idle, every later instance (domain-reload restart, test server) starts + /// settled — a server coming up mid-session while a compile/import happens to be in + /// flight (script-creating test fixtures, recompile loops) must NOT re-arm the gate. + /// Volatile: set on the main thread, read from HTTP request threads. + /// + private volatile bool m_Settled; + private bool m_SettleTickSubscribed; + + /// + /// SessionState marker: the Editor has been seen idle at least once this session, i.e. + /// the post-startup settle window is over for the whole session. SessionState survives + /// domain reloads and dies with the Editor process — exactly the settle window's scope. + /// Read/written on the main thread only (Start and the update tick); request threads + /// only read the volatile snapshot. + /// + private const string SettledSessionKey = "Unity.Pipeline.EditorSessionSettled"; + + /// + /// Commands that must stay servable while the Editor is settling: editor_status is the + /// status surface callers poll to observe the busy/settling state itself. + /// Background (MainThreadRequired = false) commands are always exempt and don't need + /// listing here. + /// + private static readonly HashSet CommandsServiceableWhileSettling = new HashSet { "editor_status" }; + + /// + /// editor_status's fields as of the instant a dialog was about to be shown — see + /// . Once the dialog actually blocks the main + /// thread, editor_status can no longer run for real (unlike the settle case above, where + /// the thread is merely busy, not stuck inside a native message loop), so the dialog gate + /// serves this snapshot instead. Nothing it describes (compiling/domain reload/play mode) + /// can change while the thread that would update it is stuck, so it stays correct for the + /// whole blocked window. Null until the first dialog of the session is about to be shown. + /// + private StatusResponse m_LastStatusBeforeDialog; + + /// When true, every command transaction is written to the project transaction log. + public bool LogRequestsResponses { get; set; } + + /// + /// Whether /api/status's ordinary (non-settling, non-dialog-blocked) case should report + /// "ready" rather than "error". Defaults to whether the instance descriptor was actually + /// created; a -false test double that is genuinely running + /// can override this instead of faking a descriptor just to exercise that branch. + /// + protected virtual bool HasInstanceDescriptor => m_InstanceDescriptor != null; + + /// UTC time this server instance started listening. + public override DateTime StartedAt => m_InstanceDescriptor == null ? new DateTime() : m_InstanceDescriptor.StartedAt; + + /// + /// Whether the Editor has been seen idle (not importing, not compiling) at least once + /// this editor session. Until then the server is "settling": main-thread commands are + /// rejected with a retryable busy signal instead of executing into a half-ready Editor. + /// Virtual so tests can pin the unsettled state. + /// + protected virtual bool IsSettled => m_Settled; + + /// + /// Whether this Editor session has already completed its settle window (the SessionState + /// marker any settling server sets on first idle). Main thread only. Exposed protected so + /// tests can assert it as a precondition before probing the latch's immediate-settle path. + /// + protected static bool IsSessionSettled => SessionState.GetBool(SettledSessionKey, false); + + /// Arm the post-startup settle latch. + protected override void ServerStarted() + { + InitializeSettleLatch(); + } + + /// + /// Whether the Editor was launched with -automated. A Unity console warning for this fact + /// is unactionable (nobody watches the console in an agent-driven workflow) and, worse, was + /// logged once per constructed server instance — the isolated test servers built per test + /// (see TestEditorPipelineServer) spammed it dozens of times per suite run. The fact is + /// instead surfaced as structured data on the instance descriptor (see + /// ) — the one thing every client reads before it can + /// connect at all (UUM-149977). + /// + internal static bool DetectAutomatedMode(string[] commandLineArgs) + { + foreach (var arg in commandLineArgs) + { + if (arg == "-automated") + return true; + } + return false; + } + + /// Unsubscribe the settle-tick handler. + protected override void ServerStopped() + { + UnsubscribeSettleTick(); + } + + /// + /// Arm or immediately release the settle latch. Start() runs on the main thread, so the + /// Editor state and SessionState are readable directly. A server starts settled when the + /// session has already settled once (mid-session restarts after domain reloads, test + /// servers started while a test's own compile/import is in flight) or when the Editor is + /// idle right now — zero behavior change in both cases. Only a server started before the + /// session's first idle moment (cold import: [InitializeOnLoad] runs inside the startup + /// AssetDatabase refresh) arms the gate, and settles on the first update tick that sees + /// the Editor idle. + /// + private void InitializeSettleLatch() + { + if (SessionState.GetBool(SettledSessionKey, false) + || (!EditorApplication.isCompiling && !EditorApplication.isUpdating)) + { + MarkSettled(); + return; + } + + m_SettleTickSubscribed = true; + EditorApplication.update += SettleTick; + } + + private void SettleTick() + { + if (EditorApplication.isCompiling || EditorApplication.isUpdating) + return; + + MarkSettled(); + UnsubscribeSettleTick(); + } + + /// + /// Release this instance's latch and mark the whole session settled (main thread only). + /// + private void MarkSettled() + { + m_Settled = true; + SessionState.SetBool(SettledSessionKey, true); + } + + private void UnsubscribeSettleTick() + { + if (!m_SettleTickSubscribed) + return; + + m_SettleTickSubscribed = false; + EditorApplication.update -= SettleTick; + } + + /// + /// Busy gate (see ): while settling, reject + /// main-thread commands with a retryable busy signal — during the post-start import/compile + /// window they would otherwise execute into a half-ready Editor and fail with an opaque + /// null-data envelope (AUTHAPI-35). Background commands (status polling: recompile_status, + /// package_status, console, ...) and editor_status stay servable so callers can observe + /// progress. Reads only the volatile latch — safe on the request thread. + /// + /// The command about to be dispatched. + /// A busy reason while settling, or null once the Editor has been seen idle. + protected override string GetBusyReason(CommandInfo command) + { + if (IsSettled) + return null; + + if (!command.MainThreadRequired || CommandsServiceableWhileSettling.Contains(command.Name)) + return null; + + return "The Editor is still settling after startup (importing assets / compiling scripts), " + + "so main-thread commands are not serviceable yet. Retry shortly, or poll /api/status until it reports 'ready'."; + } + + /// + /// Called by EditorDialogStateMirror right before a dialog blocks the main thread (while + /// it's still free to read live Editor state) — captures editor_status's fields for + /// to serve while the dialog is open. + /// + internal void SnapshotStatusForDialogGate() + { + m_LastStatusBeforeDialog = EditorStatusCommand.GetEditorStatus(); + } + + /// + /// editor_status is the one MainThreadRequired command the dialog gate doesn't hard-fail: + /// it can't run for real (see 's doc), but its answer + /// is a snapshot taken the instant before the block started, which stays accurate for the + /// whole window. No snapshot exists only if a dialog opened before this server ever saw one + /// coming (should not happen in practice — EditorDialogStateMirror snapshots on every + /// dialogWillShow), in which case this falls back to the normal 503. + /// + internal override object TryGetDialogBlockedFallback(CommandInfo command, DialogInfo blockingDialog) + { + if (command.Name != "editor_status" || m_LastStatusBeforeDialog == null) + return null; + + return new StatusResponse + { + Status = "blocked_by_dialog", + Compiling = m_LastStatusBeforeDialog.Compiling, + DomainReloadInProgress = m_LastStatusBeforeDialog.DomainReloadInProgress, + PlayMode = m_LastStatusBeforeDialog.PlayMode, + LastHeartbeat = DateTime.UtcNow, + ProjectPath = m_LastStatusBeforeDialog.ProjectPath, + UnityVersion = m_LastStatusBeforeDialog.UnityVersion, + Dialog = BuildDialogPayload(blockingDialog) + }; + } + + /// + /// Post-command work, on the HTTP thread. + /// + /// The transaction log runs here directly rather than crossing to the main thread with the + /// analytics: its append is thread-safe file I/O by design (see + /// ), and driving it from the editor update loop would + /// put a read-modify-write of the log on every frame that served a command. An info with no + /// request JSON is a detached job reporting its real result, which was never part of a + /// transaction. + /// + protected override void OnCommandDone(in CommandExecutionInfo info) + { + if (LogRequestsResponses && info.RequestJson != null) + PipelineTransactionLog.Append(info.RequestJson, info.ResponseJson); + + // Requests rejected before anything ran carry no command, and nothing on the main-thread + // side has anything to say about them. + if (info.Command == null) + return; + + // Copied out of the `in` parameter because a lambda cannot capture one. + var posted = info; + Dispatcher.Post(() => OnCommandDoneMainThread(posted)); + } + + /// + /// Post-command work that needs the main thread, run on the next dispatcher pump. Analytics + /// lives here, and so does anything else added later that has to touch Unity APIs once a + /// command is done. Virtual so a test server can opt out wholesale. + /// + protected virtual void OnCommandDoneMainThread(in CommandExecutionInfo info) + { + PipelineAnalytics.RecordCommandExecuted(info); + } + + // Runtime-only commands (eval, codereload_status, …) are part of the Player surface; don't + // advertise them when a client is connected to the Editor. + /// False: Editor clients don't see runtime-only commands (they belong to the Player surface). + protected override bool IncludeRuntimeOnlyCommands => false; + /// Write the shared instance descriptor file so clients can discover this server. + protected override void CreateInstanceDescriptor() + { + // Create and write instance descriptor for CLI discovery + var automated = DetectAutomatedMode(System.Environment.GetCommandLineArgs()); + m_InstanceDescriptor = InstanceDescriptor.CreateCurrent(Port, automated); + InstanceDescriptor.WriteToProjectRoot(m_InstanceDescriptor); + } + + /// Remove the shared instance descriptor file on shutdown. + protected override void DeleteInstanceDescriptor() + { + // Clean up instance descriptor file + if (m_InstanceDescriptor != null) + { + InstanceDescriptor.RemoveFromProjectRoot(m_InstanceDescriptor.ProjectPath); + } + m_InstanceDescriptor = null; + } + + /// Refresh the descriptor's heartbeat timestamp and current token. + protected override void UpdateHeartBeat() + { + // Update heartbeat in instance descriptor + if (m_InstanceDescriptor == null) + return; + + lock (m_HeartbeatLock) + { + // Keep the port file's token current for discovery only — GetToken() validates the + // live token, so this just catches up to a rotation on the next heartbeat. + m_InstanceDescriptor.EvalToken = SecurityTokenManager.GetOrCreateToken(); + m_InstanceDescriptor.LastHeartbeat = DateTime.UtcNow; + try + { + InstanceDescriptor.WriteToProjectRoot(m_InstanceDescriptor); + } + catch (Exception ex) + { + Debug.LogWarning($"Failed to update instance descriptor: {ex.Message}"); + } + } + } + + /// Build the Editor-specific status/heartbeat payload for /api/status, including the settle state. + /// The status payload. + protected override object GetServerStatus() + { + UpdateHeartBeat(); + // "blocked_by_dialog" is checked first: a modal dialog blocks the main thread + // regardless of settle state, and is the more actionable fact for a caller — settling + // resolves on its own, a dialog needs a human. Read off DialogStateTracker's lock, same + // as /api/dialog, so this stays fast and needs no main-thread access. "settling" is + // checked next: on a cold import the settle window precedes normal operation, and + // clients waiting for "ready" (instead of firing commands blindly) land after the + // Editor is actually serviceable (AUTHAPI-35). + var openDialogs = Dialogs.CurrentlyOpen; + string status = openDialogs.Count > 0 ? "blocked_by_dialog" + : !IsSettled ? "settling" + : (HasInstanceDescriptor ? "ready" : "error"); + + // Keep the common case's shape unchanged (no "dialog" key at all) rather than + // always emitting "dialog": null — this is a widely-polled endpoint, not worth + // changing its byte shape for every request just to cover the rare blocked case. + // Gated on status itself, not openDialogs.Count, so a dialog that opens during the + // settle window doesn't attach a "dialog" key to a "settling" response (StatusResponse's + // dialog field is documented as present only when status is "blocked_by_dialog"). + if (status == "blocked_by_dialog") + { + return new + { + status, + lastHeartbeat = m_InstanceDescriptor?.LastHeartbeat, + capabilities = Capabilities, + dialog = BasePipelineServer.BuildDialogPayload(openDialogs[0]) + }; + } + return new + { + status, + lastHeartbeat = m_InstanceDescriptor?.LastHeartbeat, + capabilities = Capabilities + }; + } + + /// The bearer token clients must present to authenticate requests. + /// The current live token. + protected override string GetToken() + { + // Validate the live token so a rotation/revocation takes effect on the next request (not + // the next heartbeat). The descriptor's EvalToken is discovery-only. + return SecurityTokenManager.GetOrCreateToken(); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineServer.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineServer.cs.meta new file mode 100644 index 0000000..8fb37eb --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineServer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 11ba9c53c356c2c469bc37d0d370db29 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineStartup.cs b/AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineStartup.cs new file mode 100644 index 0000000..924e18c --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineStartup.cs @@ -0,0 +1,345 @@ +using UnityEditor; +using UnityEngine; +using Unity.Pipeline.Models; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Telemetry; +using Unity.Pipeline.Threading; +using UnityEditor.MPE; +#if UNITY_6000_5_OR_NEWER +using Unity.Scripting.LifecycleManagement; +#endif + +namespace Unity.Pipeline.Editor +{ + /// + /// Automatically starts Pipeline HTTP server when Unity Editor loads. + /// Handles startup, domain reload persistence, and cleanup. + /// + /// Static owner of the live editor server: a static owner survives domain reloads cleanly + /// (re-created by [InitializeOnLoad]), whereas a ScriptableObject's lifetime does not track the + /// server across editor events. is an optional, inspectable + /// settings asset whose config is read here at start. + /// + [InitializeOnLoad] +#if UNITY_6000_5_OR_NEWER + [NoAutoStaticsCleanup] +#endif + static class PipelineServerStartup + { + private static EditorPipelineServer m_Server; + + /// + /// The live editor pipeline server instance (null when stopped). Exposed so the test guard + /// can disable its watchdog for a test run and the EditorPipelineManager inspector can read + /// live status. + /// + public static EditorPipelineServer Server => m_Server; + + static PipelineServerStartup() + { + // Seed the compile service's define snapshot while we're guaranteed on the main + // thread — a background compile fired before any main-thread parse would otherwise + // run with an empty define set (wrong #if branches). Before the worker-process + // early-out: costs one editor API call and holds everywhere. + Compilation.RoslynCompilationService.SnapshotProjectDefines(); + + // Don't start server in AssetImportWorker processes + if (!IsMainProcess()) + return; + // Setup command discovery using TypeCache for fast Editor performance + CommandRegistry.SetDiscovery(new TypeCacheCommandDiscovery()); + + // Clean up any stale instance descriptor files from previous sessions + CleanupStaleDescriptors(); + + var cfg = EditorPipelineManager.Load(); + + // Apply the local eval-usage telemetry config on EVERY domain reload, not only when + // the server starts (AUTHAPI-29): recording hooks eval itself, not the server + // lifecycle, so an AutoStart=false session must still honor the configured opt-outs + // instead of falling back to the hardcoded defaults. + ApplyEvalTelemetrySettings(cfg); + + // Start the pipeline server (respecting the settings asset's autoStart if one exists) + if (cfg?.AutoStart ?? true) + StartServer(); + + // Handle domain reloads and editor shutdown + EditorApplication.playModeStateChanged += OnPlayModeStateChanged; + EditorApplication.quitting += OnEditorQuitting; + EditorApplication.wantsToQuit += OnEditorWantsToQuit; + + // Handle domain reload detection + AssemblyReloadEvents.beforeAssemblyReload += OnBeforeAssemblyReload; + AssemblyReloadEvents.afterAssemblyReload += OnAfterAssemblyReload; + } + + /// Start the server if it isn't already running. + public static void EnsureServerStarted() + { + StartServer(); + } + + /// + /// Force a clean restart of the editor pipeline server. Unlike EnsureServerStarted, this + /// works even when the current server's listener has died but still reports IsRunning + /// (e.g. after a test disrupted it). Used by tests to revive the live server they disrupted. + /// + public static void RestartServer() + { + StopServer(); + StartServer(); + } + + [MenuItem("Window/Pipeline/Start Server")] + private static void MenuStartServer() + { + StartServer(); + if (m_Server != null && m_Server.IsRunning) + Debug.Log($"Pipeline Server started on port {m_Server.Port}"); + else + Debug.LogWarning("Pipeline Server failed to start"); + } + + [MenuItem("Window/Pipeline/Start Server", true)] + private static bool MenuStartServerValidate() => m_Server == null || !m_Server.IsRunning; + + [MenuItem("Window/Pipeline/Stop Server")] + private static void MenuStopServer() + { + StopServer(); + } + + [MenuItem("Window/Pipeline/Stop Server", true)] + private static bool MenuStopServerValidate() => m_Server != null && m_Server.IsRunning; + + /// + /// Select the EditorPipelineManager settings asset, creating it under Assets/Settings/Pipeline + /// on first use (the live server otherwise runs from built-in defaults). + /// + [MenuItem("Window/Pipeline/Settings...")] + private static void OpenSettings() + { + var mgr = EditorPipelineManager.Load(); + if (mgr == null) + { + const string folder = "Assets/Settings/Pipeline"; + if (!AssetDatabase.IsValidFolder(folder)) + { + if (!AssetDatabase.IsValidFolder("Assets/Settings")) + AssetDatabase.CreateFolder("Assets", "Settings"); + AssetDatabase.CreateFolder("Assets/Settings", "Pipeline"); + } + + mgr = ScriptableObject.CreateInstance(); + AssetDatabase.CreateAsset(mgr, folder + "/EditorPipelineManager.asset"); + AssetDatabase.SaveAssets(); + } + Selection.activeObject = mgr; + EditorGUIUtility.PingObject(mgr); + } + + internal static bool IsMainProcess() + { + // Check command line arguments for asset import worker indicators + var args = System.Environment.GetCommandLineArgs(); + for (int i = 0; i < args.Length; i++) + { + if (args[i] == "-readonly" || args[i] == "--virtual-project-clone") + return true; + } + + if (AssetDatabase.IsAssetImportWorkerProcess()) + return false; + + if (ProcessService.level != ProcessLevel.Main) + return false; + + return true; + } + + /// + /// Apply the local eval-usage telemetry config (AUTHAPI-29). Local-only, no transmission; + /// disabling it stops even local recording. StoreSource is the explicit opt-in for + /// persisting raw eval source (off by default). Resolving the directory primes the + /// dataPath-derived default on the main thread, so off-main-thread readers (report_evals) + /// and the background record task never touch Unity APIs. + /// + /// Internal (not private): this is the ONE place that knows how to turn the settings asset + /// into the static telemetry config, so every push site — the domain-reload static ctor, + /// server start, and 's live inspector push — calls + /// through here rather than re-deriving the two-field mapping independently, which would + /// silently drift the moment a fourth push site (or a third telemetry field) showed up. + /// + internal static void ApplyEvalTelemetrySettings(EditorPipelineManager cfg) + { + EvalUsageTelemetry.Enabled = cfg?.EvalTelemetryEnabled ?? true; + EvalUsageTelemetry.StoreSource = cfg?.StoreEvalSource ?? false; + EvalUsageTelemetry.ResolveDirectory(); + } + + /// + /// Start the Pipeline HTTP server, reading configuration from the EditorPipelineManager + /// settings asset if one exists (otherwise using defaults). + /// + private static void StartServer() + { + if (m_Server != null && m_Server.IsRunning) + return; + + try + { + var cfg = EditorPipelineManager.Load(); + m_Server = new EditorPipelineServer + { + // Self-healing watchdog: if the listener dies without a Stop() (an unexpected fault + // outside a domain reload), the watchdog re-opens it so the dogfood loop doesn't + // wedge. Set before Start() (Start arms the watchdog). + WatchdogEnabled = cfg?.WatchdogEnabled ?? true, + WatchdogIntervalSeconds = cfg?.WatchdogIntervalSeconds ?? 5, + LogRequestsResponses = cfg?.LogRequestsResponses ?? false, + AllowSandboxedBrowserClients = cfg?.AllowBrowserClients ?? false, + MaxRequestBodyBytes = 32L * 1024 * 1024 + }; + + // Rotate the transaction log once per Unity session (main thread; SessionState-gated). + // The append path runs off-thread and can't touch SessionState. + PipelineTransactionLog.RotateForNewSession(); + + // Re-applied on every server start so inspector edits made this session stick + // even without a domain reload (the static ctor covers the reload path). + ApplyEvalTelemetrySettings(cfg); + + m_Server.Start(cfg?.Port ?? 0); // 0 auto-assigns from the 7800-7849 range. + + // Restore whatever auto-tick state the user last set this session (survives the + // domain reload that just wiped AutoTickCommand's statics). Only a session with no + // prior explicit set_autotick call falls back to a default, and that default is "on" + // when the watchdog is enabled: the watchdog rides EditorApplication.update, but a + // backgrounded/idle editor stops ticking once the listener dies (no requests left to + // wake it) — the exact moment the watchdog must run. Keeping auto-tick on by default + // keeps the update loop spinning regardless of focus, which keeps both the watchdog + // AND the dispatcher message pump alive. + Commands.AutoTickCommand.RestoreFromSession(defaultEnabled: m_Server.WatchdogEnabled); + } + catch (System.Exception ex) + { + Debug.LogError($"Failed to start Pipeline Server: {ex.Message}"); + } + } + + /// + /// Stop the Pipeline HTTP server. + /// + public static void StopServer() + { + if (m_Server != null) + { + try + { + m_Server.Stop(); + } + catch (System.Exception ex) + { + Debug.LogWarning($"Error stopping Pipeline Server: {ex.Message}"); + } + finally + { + m_Server = null; + } + } + } + + /// + /// Clean up stale instance descriptor files from previous Editor sessions. + /// + private static void CleanupStaleDescriptors() + { + var projectPath = System.IO.Path.GetDirectoryName(Application.dataPath); + + // Try to read existing descriptor + var existing = InstanceDescriptor.ReadFromProjectRoot(projectPath); + if (existing != null) + { + // Check if process is still running + try + { + var process = System.Diagnostics.Process.GetProcessById(existing.Pid); + if (process.HasExited) + { + // Process is dead, remove stale file + InstanceDescriptor.RemoveFromProjectRoot(projectPath); + } + } + catch + { + // Process doesn't exist or access denied, remove stale file + InstanceDescriptor.RemoveFromProjectRoot(projectPath); + } + } + } + + /// + /// Handle play mode state changes. + /// + private static void OnPlayModeStateChanged(PlayModeStateChange state) + { + // Server continues running through play mode changes + // Status endpoint will reflect current play mode via EditorApplication.isPlaying + + // RuntimePipelineDriver.Awake() switches CommandRegistry to reflection-based discovery + // on every Play Mode entry (a Player has no TypeCache). With Fast Enter Play Mode + // (domain reload disabled), nothing else runs this static constructor to switch it back + // on the way out — pre-FEPM, re-entering Edit mode via a domain reload did this for + // free. Restore TypeCache discovery explicitly here instead of relying on that reload. + if (state == PlayModeStateChange.EnteredEditMode) + CommandRegistry.SetDiscovery(new TypeCacheCommandDiscovery()); + + // Dynamic command registrations (CommandRegistry.RegisterCommand) are static state with + // domain-reload lifetime, and a script registering from Awake/OnEnable re-registers on + // every Play Mode entry. With domain reload disabled nothing resets the registry between + // sessions, so the second entry would throw "already registered dynamically" and a + // surviving entry would hold a delegate bound to the previous session's destroyed + // object. Bracket the session here to clear what it registered; registrations made in + // Edit Mode are kept, since nothing re-runs to restore them. + if (state == PlayModeStateChange.ExitingEditMode) + CommandRegistry.PlayModeSessionStarted(); + else if (state == PlayModeStateChange.EnteredEditMode) + CommandRegistry.PlayModeSessionEnded(); + } + + /// + /// Handle Editor shutdown. + /// + private static void OnEditorQuitting() + { + StopServer(); // Stop() shuts down the server's own dispatcher. + } + + private static bool OnEditorWantsToQuit() + { + // WARNING: we need to fire SessionStop in WantsToQuit. Firing in Quits won't actually send the event. + PipelineAnalytics.SendSessionStoppedIfStarted(); + return true; + } + + /// + /// Handle before assembly reload (domain reload). + /// + private static void OnBeforeAssemblyReload() + { + // Server will be automatically recreated after reload due to [InitializeOnLoad] + // Instance descriptor file will be cleaned up and recreated + + } + + /// + /// Handle after assembly reload (domain reload). + /// + private static void OnAfterAssemblyReload() + { + // Server should already be restarted via [InitializeOnLoad] + // This is mainly for logging/verification + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineStartup.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineStartup.cs.meta new file mode 100644 index 0000000..ef3bd7b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/EditorPipelineStartup.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4f85dcf6fb33a5047be5b7790e736674 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/EditorProgressMirror.cs b/AIClient/Packages/com.unity.pipeline/Editor/EditorProgressMirror.cs new file mode 100644 index 0000000..269605b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/EditorProgressMirror.cs @@ -0,0 +1,67 @@ +using UnityEditor; + +namespace Unity.Pipeline.Editor +{ + /// + /// Mirrors running items into so + /// background Editor tasks (async imports, bakes, anything instrumented with + /// Progress.Report) surface on GET /api/progress with no explicit + /// calls (CLI-488). + /// + /// The Progress events fire on the main thread, so this mirror only advances while the main + /// thread is pumping. A long SYNCHRONOUS main-thread task never yields — code inside such a + /// task should call (or the + /// wrappers) directly; that path records from within the + /// blocked call and is what the HTTP listener thread serves. + /// + [InitializeOnLoad] + internal static class EditorProgressMirror + { + static EditorProgressMirror() + { + Progress.added += OnProgressChanged; + Progress.updated += OnProgressChanged; + Progress.removed += OnProgressChanged; + } + + static void OnProgressChanged(Progress.Item[] items) + { + Refresh(); + } + + static void Refresh() + { + // Ambient UnityEditor.Progress is a live-editor-wide concept, not per-test-server — + // target the live server explicitly so a test server's CliProgress never receives it + // (and vice versa). No-op while the live server isn't running. + var server = PipelineServerStartup.Server; + if (server == null) + return; + + // Mirror the most recently ADDED running item (enumeration is registration order, + // so the last running one wins) — for nested/sequential operations that is the one + // a user watching the Editor would consider "current". + Progress.Item best = null; + foreach (var item in Progress.EnumerateItems()) + { + if (item.running) + { + best = item; + } + } + + if (best == null) + { + server.Progress.ClearAmbient(); + return; + } + + server.Progress.ReportAmbient( + best.name, + best.description, + best.currentStep > 0 ? best.currentStep : (long?)null, + best.totalSteps > 0 ? best.totalSteps : (long?)null, + !best.indefinite && best.progress >= 0f ? (double?)best.progress : null); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/EditorProgressMirror.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/EditorProgressMirror.cs.meta new file mode 100644 index 0000000..a81c32d --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/EditorProgressMirror.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 9af021bfb7d14a23bdd4aa333b5d9105 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetVersion: 1 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/PipelineAnalytics.cs b/AIClient/Packages/com.unity.pipeline/Editor/PipelineAnalytics.cs new file mode 100644 index 0000000..1e7272e --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/PipelineAnalytics.cs @@ -0,0 +1,17 @@ +// Unity 2022 compatibility shim: IAnalytic / AnalyticInfo / EditorAnalytics.SendAnalytic are Unity 6+. +// Keep call sites compiling with no-op analytics on this editor version. +#if !UNITY_6000_0_OR_NEWER +using Unity.Pipeline.Telemetry; + +namespace Unity.Pipeline.Editor +{ + internal static class PipelineAnalytics + { + internal static void RecordCommandExecuted(in CommandExecutionInfo info) { } + + internal static void SendSessionStoppedIfStarted() { } + } +} +#else +#error PipelineAnalytics.cs was replaced with a Unity 2022 shim. Restore the original package file on Unity 6+. +#endif diff --git a/AIClient/Packages/com.unity.pipeline/Editor/PipelineAnalytics.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/PipelineAnalytics.cs.meta new file mode 100644 index 0000000..ec48b13 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/PipelineAnalytics.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d5ea5eba3cbb88e43881d93395472416 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/PipelineTransactionLog.cs b/AIClient/Packages/com.unity.pipeline/Editor/PipelineTransactionLog.cs new file mode 100644 index 0000000..87b1ffd --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/PipelineTransactionLog.cs @@ -0,0 +1,169 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.CompilerServices; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using UnityEditor; +using UnityEngine; +#if UNITY_6000_5_OR_NEWER +using Unity.Scripting.LifecycleManagement; +#endif + +[assembly: InternalsVisibleTo("Unity.Pipeline.Tests.Editor")] + +namespace Unity.Pipeline.Editor +{ + /// + /// Appends editor pipeline request/response transactions to <project>/Logs/pipeline.log as a + /// JSON array. rotates any existing log to pipeline_old.log on + /// the first server start of a Unity session: SessionState survives domain reloads but resets on + /// editor restart, so the log accumulates across a session's server start/stop cycles and starts + /// fresh each new session. + /// + /// Rotation must run on the main thread (SessionState is main-thread only), hence it lives in + /// RotateForNewSession (called from server startup), NOT in Append — which runs on the background + /// HTTP thread and is restricted to thread-safe file I/O. + /// +#if UNITY_6000_5_OR_NEWER + [NoAutoStaticsCleanup] +#endif + internal static class PipelineTransactionLog + { + private const string SessionRotatedKey = "Unity.Pipeline.TransactionLog.SessionRotated"; + private const string LogFileName = "pipeline.log"; + private const string OldLogFileName = "pipeline_old.log"; + + // Field names are the JSON keys, so they intentionally stay lowercase. request/response are + // JToken so the raw JSON is embedded as real JSON (not a stringified blob) in the log array. + private struct Entry + { + public JToken request; + public JToken response; + public string time; + } + + /// + /// On the first call of a Unity session, back up any existing pipeline.log to pipeline_old.log + /// so the session starts with a fresh log. Gated by SessionState (resets on editor restart), + /// so domain-reload server restarts within a session do not rotate. Main thread only. + /// + public static void RotateForNewSession() + { + try + { + if (SessionState.GetBool(SessionRotatedKey, false)) + return; + + Rotate(GetLogsDirectory()); + SessionState.SetBool(SessionRotatedKey, true); + } + catch (Exception ex) + { + Debug.LogWarning($"Pipeline transaction log rotation failed: {ex.Message}"); + } + } + + /// + /// Append one transaction to the JSON-array log. Runs on the background HTTP thread, so it + /// uses only thread-safe file I/O (no Unity editor APIs). + /// + public static void Append(string requestJson, string responseJson) + { + try + { + Append(GetLogsDirectory(), requestJson, responseJson); + } + catch (Exception ex) + { + // Logging must never break request handling. + Debug.LogWarning($"Pipeline transaction log write failed: {ex.Message}"); + } + } + + /// + /// Back up an existing pipeline.log in to pipeline_old.log, + /// replacing any prior backup. No SessionState gate — exposed as the testable rotation seam. + /// + internal static void Rotate(string logsDir) + { + Directory.CreateDirectory(logsDir); + + var logPath = Path.Combine(logsDir, LogFileName); + var oldPath = Path.Combine(logsDir, OldLogFileName); + RotatingFileBackup.RotateToBackup(logPath, oldPath); + } + + /// + /// Serializes the log's read-modify-write. Requests are processed concurrently since the + /// /api/progress work (an exec response can be written while the next exec runs), so two + /// appends may race; without this lock they would drop or corrupt entries. + /// + private static readonly object m_AppendGate = new object(); + + /// + /// Append a transaction to the JSON-array log in an explicit directory. Testable seam behind + /// the public . + /// + internal static void Append(string logsDir, string requestJson, string responseJson) + { + lock (m_AppendGate) + { + AppendLocked(logsDir, requestJson, responseJson); + } + } + + private static void AppendLocked(string logsDir, string requestJson, string responseJson) + { + Directory.CreateDirectory(logsDir); + var logPath = Path.Combine(logsDir, LogFileName); + + var entries = ReadEntries(logPath); + entries.Add(new Entry + { + request = ToJsonToken(requestJson), + response = ToJsonToken(responseJson), + time = DateTime.UtcNow.ToString("o") + }); + + File.WriteAllText(logPath, JsonConvert.SerializeObject(entries, Formatting.Indented)); + } + + /// + /// Embed a raw JSON payload as a real JSON token. Falls back to a JSON string for empty or + /// non-JSON payloads, so the log file always stays valid JSON. + /// + private static JToken ToJsonToken(string raw) + { + if (string.IsNullOrEmpty(raw)) + return JValue.CreateNull(); + + try + { + return JToken.Parse(raw); + } + catch (JsonException) + { + return new JValue(raw); + } + } + + private static string GetLogsDirectory() + { + var projectPath = Path.GetDirectoryName(Application.dataPath); + return Path.Combine(projectPath, "Logs"); + } + + private static List ReadEntries(string logPath) + { + if (!File.Exists(logPath)) + return new List(); + + var json = File.ReadAllText(logPath); + if (string.IsNullOrEmpty(json)) + return new List(); + + return JsonConvert.DeserializeObject>(json) ?? new List(); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/PipelineTransactionLog.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/PipelineTransactionLog.cs.meta new file mode 100644 index 0000000..9062216 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/PipelineTransactionLog.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7e3c9a4b21d54f8d8b6e0c1f2a3d4e5b diff --git a/AIClient/Packages/com.unity.pipeline/Editor/PushSigner.cs b/AIClient/Packages/com.unity.pipeline/Editor/PushSigner.cs new file mode 100644 index 0000000..824097f --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/PushSigner.cs @@ -0,0 +1,273 @@ +using System; +using System.Collections.Generic; +using Unity.Pipeline.CodeReload; +using UnityEditor; +using UnityEditor.Networking.PlayerConnection; +using UnityEngine; +using UnityEngine.Networking.PlayerConnection; + +namespace Unity.Pipeline.Editor +{ + /// + /// Editor side of code-reload push signing. Owns the per-player session table (nonce announced by + /// each player's HandshakeMsg) and produces signed s with the project key + /// (Library/Pipeline/signing.key, created at build time — never here: a key no build has + /// baked would sign pushes nothing accepts, so its absence should say "build first"). + /// + /// The session table is editor-memory only, so every domain reload empties it. Recovery is the + /// handshake protocol: on load we broadcast RequestHandshake; a push whose target has no session yet is + /// deferred a couple of seconds while a directed RequestHandshake round-trips (see + /// ) — watch-mode saves right after a script recompile keep working. + /// + /// Counters only need to be strictly increasing per player session and are bound to the signed + /// nonce, so they are seeded from UTC ticks: a fresh editor session (or another machine holding a + /// copy of the key) continues above whatever a previous editor session used, without the player + /// having to report where the count stands. + /// + [InitializeOnLoad] + internal static class PushSigner + { + private sealed class Session + { + public byte[] Nonce; + public long Counter; + public string Fingerprint; // key fingerprint the player expects ("" = no key baked) + public int ProtocolVersion; + } + + // How long a push waits for the player's handshake before it is dropped. An idle IL2CPP + // player on the same machine took longer than 2 s to answer the first request after the + // editor's domain reload (verified live), which silently lost the first push. + private const double DeferSeconds = 10.0; + + private static readonly Dictionary s_Sessions = new Dictionary(); + private static readonly List<(double deadline, int playerId, byte[] payload, string desc)> s_Deferred = + new List<(double, int, byte[], string)>(); + private static bool s_DeferPumpHooked; + private static bool s_Registered; + + static PushSigner() + { + // EditorConnection is not reliably initializable during InitializeOnLoad itself. + EditorApplication.delayCall += RegisterAndRequestHandshakes; + AssemblyReloadEvents.beforeAssemblyReload += Unregister; + } + + private static void RegisterAndRequestHandshakes() + { + try + { + EditorConnection.instance.Initialize(); + EditorConnection.instance.Register(PipelineCodeReloadConnect.HandshakeMsg, OnHandshake); + s_Registered = true; + + // A domain reload just wiped the session table; ask every connected player to + // re-announce so it is warm again before anyone pushes. + var players = EditorConnection.instance.ConnectedPlayers; + if (players != null && players.Count > 0) + EditorConnection.instance.Send(PipelineCodeReloadConnect.RequestHandshakeMsg, RequestPayload()); + } + catch (Exception ex) + { + Debug.LogWarning($"[PushReload] Could not register the push-signing handshake handler: {ex.Message}"); + } + } + + private static void Unregister() + { + s_Deferred.Clear(); + if (s_DeferPumpHooked) + { + EditorApplication.update -= PumpDeferred; + s_DeferPumpHooked = false; + } + if (!s_Registered) return; + try { EditorConnection.instance.Unregister(PipelineCodeReloadConnect.HandshakeMsg, OnHandshake); } + catch { /* connection may already be gone during teardown */ } + s_Registered = false; + } + + // Non-empty payload: some transport paths drop zero-length messages. + private static byte[] RequestPayload() => new byte[] { PushEnvelope.ProtocolVersion }; + + // Main thread (EditorConnection dispatches there, same as the ack handler in PushReloadCommand). + private static void OnHandshake(MessageEventArgs args) + { + if (!PipelineCodeReloadConnect.TryDecodeHandshake(args.data, out var version, out var fingerprint, out var nonce)) + { + Debug.LogWarning($"[PushReload] Undecodable handshake from player {args.playerId} — its pushes will fail."); + return; + } + if (nonce == null || nonce.Length != PushEnvelope.NonceSize) + { + Debug.LogWarning($"[PushReload] Handshake from player {args.playerId} carries a bad session nonce — its pushes will fail."); + return; + } + + bool isNew = !s_Sessions.TryGetValue(args.playerId, out var existing) + || !NoncesEqual(existing.Nonce, nonce); + s_Sessions[args.playerId] = new Session + { + Nonce = nonce, + Counter = s_Sessions.TryGetValue(args.playerId, out var prev) ? prev.Counter : 0, + Fingerprint = fingerprint ?? "", + ProtocolVersion = version, + }; + + if (isNew) + { + var local = LocalFingerprint(); + var expected = string.IsNullOrEmpty(fingerprint) ? "none (no key baked!)" : fingerprint; + var session = $"player {args.playerId} session: protocol v{version}, expects key {expected}"; + if (local != null && !string.IsNullOrEmpty(fingerprint) && local != fingerprint) + // Actionable right now — every push to this player would be rejected — so it stays + // a warning of its own rather than waiting for the first reload. + Debug.LogWarning($"[PushReload] {session} — MISMATCH with this machine's key {local}: rebuild the player, " + + $"or copy Library/Pipeline/{PushSigningKey.KeyFileName} from the machine that built it."); + else + // A player connecting is only interesting once something is pushed to it; a + // connected dev player with the watcher off used to log this on every connect. + CodeReloadRegistry.NoteForFirstReload(session); + } + + PumpDeferred(); // a deferred push may have been waiting exactly for this handshake + } + + private static bool NoncesEqual(byte[] a, byte[] b) + { + if (a == null || b == null || a.Length != b.Length) return false; + for (int i = 0; i < a.Length; i++) + if (a[i] != b[i]) return false; + return true; + } + + internal static bool HasSession(int playerId) => s_Sessions.ContainsKey(playerId); + + internal static string LocalFingerprint() => + PushSigningKey.TryLoad(PushSigningKey.DefaultDirectory, out var key) + ? PushEnvelope.Fingerprint(key) + : null; + + /// + /// Sign for one player and send it, or — if that player's handshake + /// has not arrived (typical right after an editor domain reload) — request one and defer the + /// send for up to a couple of seconds. Returns a short status for the caller's summary line; + /// deferred/failed details are also logged here. + /// + internal static PushSendStatus PushOrDefer(int playerId, byte[] payload, string desc) + { + if (s_Sessions.ContainsKey(playerId)) + return SignAndSend(playerId, payload, desc) ? PushSendStatus.Sent : PushSendStatus.Failed; + + try + { + EditorConnection.instance.Send(PipelineCodeReloadConnect.RequestHandshakeMsg, RequestPayload(), playerId); + } + catch (Exception ex) + { + Debug.LogWarning($"[PushReload] Could not request a handshake from player {playerId}: {ex.Message}"); + } + + s_Deferred.Add((EditorApplication.timeSinceStartup + DeferSeconds, playerId, payload, desc)); + if (!s_DeferPumpHooked) + { + EditorApplication.update += PumpDeferred; + s_DeferPumpHooked = true; + } + return PushSendStatus.Deferred; + } + + private static bool SignAndSend(int playerId, byte[] payload, string desc) + { + var session = s_Sessions[playerId]; + + if (!PushSigningKey.TryLoad(PushSigningKey.DefaultDirectory, out var privateKey)) + { + Debug.LogError($"[PushReload] {desc}: no push-signing key at Library/Pipeline/{PushSigningKey.KeyFileName}. " + + "It is created at build time — build the player once on this machine, or copy the key file from the machine that built it."); + return false; + } + + var local = PushEnvelope.Fingerprint(privateKey); + if (string.IsNullOrEmpty(session.Fingerprint)) + { + Debug.LogError($"[PushReload] {desc}: player {playerId} has no baked push key and rejects all pushes. " + + "Rebuild with the Pipeline build processor enabled (it bakes the key into RuntimePipelineBuildInfo)."); + return false; + } + if (session.Fingerprint != local) + { + Debug.LogError($"[PushReload] {desc}: player {playerId} expects key {session.Fingerprint}, this machine has {local}. " + + $"Rebuild the player, or copy Library/Pipeline/{PushSigningKey.KeyFileName} from the machine that built it."); + return false; + } + + // Strictly increasing per session; UTC-tick seeding keeps a fresh editor domain (counter + // state lost) above anything a previous editor session already used. + session.Counter = Math.Max(session.Counter + 1, DateTime.UtcNow.Ticks); + + try + { + var envelope = PushEnvelope.Sign(privateKey, session.Nonce, session.Counter, payload); + EditorConnection.instance.Send(PipelineCodeReloadConnect.ApplyReloadMsg, envelope, playerId); + Commands.PushReloadCommand.TrackAck(desc + $" → player {playerId}"); + return true; + } + catch (Exception ex) + { + Debug.LogError($"[PushReload] {desc}: signing/sending to player {playerId} failed: {ex.Message}"); + return false; + } + } + + private static void PumpDeferred() + { + if (s_Deferred.Count == 0) + { + if (s_DeferPumpHooked) + { + EditorApplication.update -= PumpDeferred; + s_DeferPumpHooked = false; + } + return; + } + + double now = EditorApplication.timeSinceStartup; + // Drain in insertion (FIFO) order. The counter is assigned at send time, so sending the + // oldest ready push first keeps the newest push on the highest counter; draining + // newest-first would sign a later push with a lower counter and the player would then + // apply the stale earlier override last. Rebuild the queue with the entries that were + // neither sent nor expired, preserving their order. + var remaining = new List<(double deadline, int playerId, byte[] payload, string desc)>(s_Deferred.Count); + foreach (var entry in s_Deferred) + { + var (deadline, playerId, payload, desc) = entry; + + if (s_Sessions.ContainsKey(playerId)) + { + if (SignAndSend(playerId, payload, desc)) + Debug.Log($"[PushReload] {desc}: deferred push sent to player {playerId} (handshake arrived)."); + continue; + } + + if (now >= deadline) + { + Debug.LogWarning($"[PushReload] {desc}: no handshake from player {playerId} within {DeferSeconds:0}s — push dropped. " + + "Is the player build made with a signing-aware com.unity.pipeline package? Reconnect or restart the player and retry."); + continue; + } + + remaining.Add(entry); + } + s_Deferred.Clear(); + s_Deferred.AddRange(remaining); + } + } + + internal enum PushSendStatus + { + Sent, + Deferred, + Failed, + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/PushSigner.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/PushSigner.cs.meta new file mode 100644 index 0000000..4fc3135 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/PushSigner.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 92b04efc75a841dd83c6f1e29a07d5b3 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/PushSigningKey.cs b/AIClient/Packages/com.unity.pipeline/Editor/PushSigningKey.cs new file mode 100644 index 0000000..47a243c --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/PushSigningKey.cs @@ -0,0 +1,78 @@ +using System; +using System.IO; +using Unity.Pipeline.CodeReload; +using UnityEngine; + +namespace Unity.Pipeline.Editor +{ + /// + /// The per-project code-reload push-signing keypair: Library/Pipeline/signing.key. + /// + /// Created lazily at build time (see PipelineRuntimeBuildProcessor) and loaded at push + /// time (see PushSigner). Living under Library/ makes committing it structurally + /// impossible and scopes trust to "the machine that built the player can push to it" — a + /// teammate either copies the file or rebuilds. Deleting Library/ orphans existing + /// device builds until the next rebuild; the key fingerprint in build and push logs is how + /// that mismatch names itself. + /// + internal static class PushSigningKey + { + internal const string KeyFileName = "signing.key"; + internal const string PublicInfoFileName = "signing.key.pub"; + + /// The project's Library/Pipeline directory (also home of the port file). + internal static string DefaultDirectory => + Path.Combine(Path.GetDirectoryName(Path.GetFullPath(Application.dataPath)), "Library", "Pipeline"); + + /// Load the private key if the file exists and fully parses. + internal static bool TryLoad(string directory, out string privateKey) + { + privateKey = null; + var path = Path.Combine(directory, KeyFileName); + try + { + if (!File.Exists(path)) return false; + var text = File.ReadAllText(path).Trim(); + if (!PushEnvelope.IsPrivateKey(text)) return false; + // The prefix alone doesn't prove the body parses. Fully parse the RSA parameters now: + // a truncated or corrupt "upp1-rsa:..." passes the prefix check, then throws later in + // DerivePublicKey and fails the build. A parse failure here falls to the catch and is + // treated as unreadable, so LoadOrCreate regenerates the key — the documented recovery. + PushEnvelope.DerivePublicKey(text); + privateKey = text; + return true; + } + catch (Exception ex) + { + Debug.LogWarning($"Pipeline: could not read push-signing key at {path} ({ex.Message}) — a fresh key will be generated on the next build."); + return false; + } + } + + /// + /// Load the project key, generating and persisting a fresh one if missing or unreadable. + /// Also writes a human-readable signing.key.pub (public half + fingerprint) beside it + /// for diagnostics and for handing to a teammate's editor. + /// + internal static string LoadOrCreate(string directory, out bool created) + { + created = false; + if (TryLoad(directory, out var existing)) + return existing; + + var privateKey = PushEnvelope.CreatePrivateKey(); + var publicKey = PushEnvelope.DerivePublicKey(privateKey); + var fingerprint = PushEnvelope.Fingerprint(publicKey); + + Directory.CreateDirectory(directory); + File.WriteAllText(Path.Combine(directory, KeyFileName), privateKey); + File.WriteAllText(Path.Combine(directory, PublicInfoFileName), + $"# com.unity.pipeline push-signing public key (fingerprint {fingerprint})\n" + + "# The private half is signing.key next to this file — never commit or share it.\n" + + publicKey + "\n"); + + created = true; + return privateKey; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/PushSigningKey.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/PushSigningKey.cs.meta new file mode 100644 index 0000000..f90346e --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/PushSigningKey.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7c2e94d1a6b34f08b5d90a3c81f7e644 diff --git a/AIClient/Packages/com.unity.pipeline/Editor/RuntimePipelineConfigEditor.cs b/AIClient/Packages/com.unity.pipeline/Editor/RuntimePipelineConfigEditor.cs new file mode 100644 index 0000000..cc5c73e --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/RuntimePipelineConfigEditor.cs @@ -0,0 +1,116 @@ +using Unity.Pipeline.Config; +using UnityEditor; + +namespace Unity.Pipeline.Editor +{ + /// + /// Draws a status HelpBox (feature description, or a security Warning/Error whenever + /// enableInBuilds is on) above RuntimePipelineConfig's fields, grouped "Server" / "Runtime + /// Behavior" via [Header] (enableInBuilds sits ungrouped above both, with its own note — it is + /// checked both at build time and at runtime, unlike every other field which only matters once + /// the driver is already running). Every field except enableInBuilds itself is disabled + /// whenever enableInBuilds is off — there is nothing to configure for a server that will not + /// run — and, separately, every field except maxWorkItemsPerFrame is also disabled during Play + /// Mode: RuntimePipelineBootstrap already loaded its own (separate) config instance by the time + /// this page could be edited, so changes here would silently do nothing until the next Play + /// session or build — same as a built Player, whose config is frozen at build time. + /// maxWorkItemsPerFrame is the one exception to the Play Mode rule — RuntimePipelineDriver.Update() + /// polls it live (see RuntimePipelineConfig.GetLiveMaxWorkItemsPerFrame), so it stays editable + /// and takes effect immediately, matching the pre-redesign component's behavior for this field; + /// it is still disabled while enableInBuilds is off, since there is no driver polling it then. + /// Never reached by clicking an asset in the Project window (the config is never a saved asset) + /// — hosted directly by RuntimePipelineSettingsProvider's Project Settings page instead, via + /// Editor.CreateEditor, which works fine on an in-memory instance. + /// + [CustomEditor(typeof(RuntimePipelineConfig))] + class RuntimePipelineConfigEditor : UnityEditor.Editor + { + public override void OnInspectorGUI() + { + serializedObject.Update(); + + // Default (150px) clips "Max Work Items Per Frame"; wide enough for every label here. + var previousLabelWidth = EditorGUIUtility.labelWidth; + EditorGUIUtility.labelWidth = 200f; + + var config = (RuntimePipelineConfig)target; + var status = GetStatusMessage(config.enableInBuilds, EditorUserBuildSettings.development); + EditorGUILayout.HelpBox(status.Message, status.Type); + EditorGUILayout.Space(); + + using (new EditorGUI.DisabledScope(EditorApplication.isPlaying)) + { + EditorGUILayout.PropertyField(serializedObject.FindProperty("enableInBuilds")); + EditorGUILayout.HelpBox( + "Checked in two places: at build time it decides whether the Pipeline server is " + + "baked into the Player at all; at runtime it decides whether the driver actually " + + "starts it — live from this file in the Editor (including Play Mode), but frozen " + + "to whatever it was at build time in a Player.", + MessageType.None); + } + + // Nothing else here matters until Pipeline is actually enabled — grey it all out + // rather than let you tune settings for a server that will not run. + using (new EditorGUI.DisabledScope(EditorApplication.isPlaying || !config.enableInBuilds)) + { + EditorGUILayout.PropertyField(serializedObject.FindProperty("port")); + EditorGUILayout.PropertyField(serializedObject.FindProperty("requestTimeoutMs")); + EditorGUILayout.PropertyField(serializedObject.FindProperty("enableAuditLogging")); + EditorGUILayout.PropertyField(serializedObject.FindProperty("autoStart")); + } + + // Polled live every frame by RuntimePipelineDriver.Update(), so it stays editable (and + // useful to tune) even while playing, unlike everything else on this page — but only + // when there's actually a driver that could be running to tune. + using (new EditorGUI.DisabledScope(!config.enableInBuilds)) + { + EditorGUILayout.PropertyField(serializedObject.FindProperty("maxWorkItemsPerFrame")); + } + + if (EditorApplication.isPlaying) + { + EditorGUILayout.HelpBox( + "Read-only while in Play Mode, except Max Work Items Per Frame: the running " + + "driver already loaded its own settings, so edits to the other fields would only " + + "take effect on the next Play session or build. Max Work Items Per Frame is " + + "re-read live every frame, so it can be tuned while playing.", + MessageType.Info); + } + + serializedObject.ApplyModifiedProperties(); + + EditorGUIUtility.labelWidth = previousLabelWidth; + } + + /// + /// Core status-message logic, factored out so it's unit-testable without rendering IMGUI. + /// Always returns a message: an informative description of the feature when there is + /// nothing to warn about, a Warning when enabled in a development build (the server, and + /// with it remote code execution, will be in that build), or an Info note when enabled + /// without Development Build, where the setting has no effect. + /// + public static (string Message, MessageType Type) GetStatusMessage(bool enableInBuilds, bool developmentBuildCurrentlyOn) + { + if (!enableInBuilds) + { + return ("Runtime Pipeline lets a Player build be remotely controlled over HTTP — " + + "code-reload code, run commands, inspect state — without a domain reload. Enable " + + "'Enable In Builds' below to include it in Player builds.", + MessageType.Info); + } + + if (!developmentBuildCurrentlyOn) + { + return ("'Enable In Builds' is on, but Development Build is currently off — the " + + "Pipeline assemblies are excluded from non-development Player builds, so this " + + "setting has no effect on the next build. Enable Development Build to include " + + "the Pipeline server.", + MessageType.Info); + } + + return ("Pipeline server will be enabled in builds. Only ship this in development/QA " + + "builds — it exposes code execution and code reload over a local HTTP server.", + MessageType.Warning); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/RuntimePipelineConfigEditor.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/RuntimePipelineConfigEditor.cs.meta new file mode 100644 index 0000000..263b62e --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/RuntimePipelineConfigEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 563bc7467faa618478075fbf3ab74884 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/RuntimePipelineSettingsProvider.cs b/AIClient/Packages/com.unity.pipeline/Editor/RuntimePipelineSettingsProvider.cs new file mode 100644 index 0000000..08fa956 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/RuntimePipelineSettingsProvider.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using Unity.Pipeline.Config; +using UnityEditor; +using UnityEngine; + +namespace Unity.Pipeline.Editor +{ + /// + /// Project Settings UI for the runtime Pipeline configuration (Project Settings > Pipeline > + /// Runtime). This is the only editing surface for RuntimePipelineConfig — the config is never + /// a saved asset, so there's nothing to click on in the Project window. This is the primary, + /// discoverable UI for what used to require manually adding a RuntimePipelineManager + /// component to a scene. + /// + static class RuntimePipelineSettingsProvider + { + /// + /// Load the current settings, or a fresh in-memory default instance if none have been + /// authored yet. Deliberately does NOT persist that default: merely viewing this page, or + /// reading via get_runtime_pipeline_settings, must never have the side effect of writing to + /// disk. The caller owns the returned instance and must DestroyImmediate it when done, same + /// as RuntimePipelineConfig.Load(). + /// + public static RuntimePipelineConfig LoadOrCreateConfig() => + RuntimePipelineConfig.Load() ?? ScriptableObject.CreateInstance(); + + [SettingsProvider] + public static SettingsProvider CreateSettingsProvider() + { + RuntimePipelineConfig config = null; + UnityEditor.Editor editor = null; + DateTime loadedWriteTimeUtc = default; + + void Reload() + { + if (editor != null) + UnityEngine.Object.DestroyImmediate(editor); + if (config != null) + UnityEngine.Object.DestroyImmediate(config); + config = LoadOrCreateConfig(); + editor = UnityEditor.Editor.CreateEditor(config, typeof(RuntimePipelineConfigEditor)); + // DateTime.MinValue (no settings file yet) is a stable value here, not a moving + // target: GetSettingsFileWriteTimeUtc() keeps returning MinValue on every repaint + // until an actual edit below calls config.Save(), so LoadOrCreateConfig() no longer + // persisting a default does not cause a reload loop. + loadedWriteTimeUtc = RuntimePipelineConfig.GetSettingsFileWriteTimeUtc(); + } + + return new SettingsProvider("Project/Pipeline/Runtime", SettingsScope.Project) + { + label = "Runtime", + activateHandler = (_, __) => Reload(), + deactivateHandler = () => + { + if (editor != null) + UnityEngine.Object.DestroyImmediate(editor); + if (config != null) + UnityEngine.Object.DestroyImmediate(config); + editor = null; + config = null; + }, + guiHandler = _ => + { + // Reload whenever our cached state can no longer be trusted: + // - config == null: entering/exiting Play Mode destroyed it out from under the + // cached Editor without deactivateHandler running first (Unity purges loose, + // non-persisted ScriptableObjects around the Play Mode transition). Unity's + // Object == overload treats a destroyed native object as null even though the + // C# reference is not. + // - the file's write-time moved since we last loaded/saved it: something else + // wrote to it directly — a build's "Disable Pipeline" security-dialog choice, + // or a set_runtime_pipeline_settings CLI call — so our in-memory copy is stale. + if (config == null || RuntimePipelineConfig.GetSettingsFileWriteTimeUtc() != loadedWriteTimeUtc) + Reload(); + + EditorGUI.BeginChangeCheck(); + editor.OnInspectorGUI(); + if (EditorGUI.EndChangeCheck()) + { + config.Save(); + loadedWriteTimeUtc = RuntimePipelineConfig.GetSettingsFileWriteTimeUtc(); + } + }, + keywords = new HashSet(new[] { "Pipeline", "Runtime", "Code Reload", "Server", "CLI" }) + }; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/RuntimePipelineSettingsProvider.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/RuntimePipelineSettingsProvider.cs.meta new file mode 100644 index 0000000..0ebc8ee --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/RuntimePipelineSettingsProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d885965fd2bb57e499a29613a6cbf44f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Testing.meta b/AIClient/Packages/com.unity.pipeline/Editor/Testing.meta new file mode 100644 index 0000000..4f35249 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Testing.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 487c1aaaab92fe74884c8b7b0442128a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Testing/PipelineTestRunner.cs b/AIClient/Packages/com.unity.pipeline/Editor/Testing/PipelineTestRunner.cs new file mode 100644 index 0000000..3a2f333 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Testing/PipelineTestRunner.cs @@ -0,0 +1,836 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using UnityEditor; +using UnityEditor.TestTools.TestRunner.Api; +using UnityEngine; +using Newtonsoft.Json; +#if UNITY_6000_5_OR_NEWER +using Unity.Scripting.LifecycleManagement; +#endif + +namespace Unity.Pipeline.Editor.Testing +{ + /// + /// Core test execution engine supporting both synchronous and asynchronous execution modes. + /// Adapted from unity-tools with domain reload handling and dual mode support. + /// +#if UNITY_6000_5_OR_NEWER + [NoAutoStaticsCleanup] +#endif + static class PipelineTestRunner + { + private const string TestRequestFile = "Temp/pipeline_test_request.json"; + private const string TestStatusFile = "Temp/pipeline_test_status.json"; + + private static TestRunnerApi m_ActiveApi; + private static TestResultCollector m_ActiveCollector; + + /// + /// Execute tests with the given parameters + /// + /// "editor"/"editmode", "playmode"/"play", or "all". + /// Filter value to match against, per . + /// "testname", "assembly", or "category". + /// Whether to include tests/fixtures marked [Explicit]. + /// Run asynchronously, returning immediately with a status path to poll. + /// Timeout for synchronous execution. + /// The test execution response. + public static async Task ExecuteTestsAsync( + string mode, + string filter, + string filterType, + bool includeExplicit, + bool asyncMode, + int timeoutSeconds) + { + try + { + var parsedMode = ParseTestMode(mode); + if (!parsedMode.IsValid) + { + return CreateErrorResponse($"Invalid mode '{mode}'. Use 'editor', 'playmode', or 'all'"); + } + + // Validate filter type + var normalizedFilterType = filterType?.ToLower() ?? "testname"; + if (!string.IsNullOrEmpty(filter) && + normalizedFilterType != "testname" && normalizedFilterType != "assembly" && normalizedFilterType != "category") + { + return CreateErrorResponse($"Invalid filterType '{filterType}'. Valid options: testName, assembly, category"); + } + + // Cancel any previous run + InvalidatePreviousRun(); + + if (parsedMode.IsAll) + { + // Handle "all" mode by running both editor and playmode tests + return await ExecuteAllModesAsync(filter, normalizedFilterType, includeExplicit, asyncMode, timeoutSeconds); + } + else if (asyncMode) + { + return await ExecuteAsyncMode(parsedMode.TestMode, filter, normalizedFilterType, includeExplicit, timeoutSeconds); + } + else if (parsedMode.TestMode == TestMode.PlayMode) + { + // PlayMode entry triggers a domain reload that drops the in-flight HTTP request, + // so a synchronous playmode run can never return results over one call. Fail fast + // with guidance instead of hanging until the connection resets. + return CreateErrorResponse( + "PlayMode tests cannot run synchronously over HTTP: entering play mode triggers a " + + "domain reload that drops the request. Re-run asynchronously (run_tests --mode " + + "playmode --async_tests) and poll the test_status command for results."); + } + else + { + return await ExecuteSyncMode(parsedMode.TestMode, filter, normalizedFilterType, includeExplicit, timeoutSeconds); + } + } + catch (Exception ex) + { + Debug.LogError($"[PipelineTestRunner] Error: {ex.Message}"); + return CreateErrorResponse($"Failed to run tests: {ex.Message}"); + } + } + + /// + /// Execute tests in all modes (editor + playmode) + /// + private static async Task ExecuteAllModesAsync( + string filter, + string filterType, + bool includeExplicit, + bool asyncMode, + int timeoutSeconds) + { + if (asyncMode) + { + return CreateErrorResponse("Async mode is not supported for 'all' mode. Use 'editor' or 'playmode' for async execution."); + } + + var startTime = DateTime.UtcNow; + + try + { + // EditMode runs synchronously over HTTP (no domain reload), so its results are + // returned in this response. + Debug.Log("[PipelineTestRunner] Running editor tests (all mode)..."); + var editorResponse = await ExecuteSyncMode(TestMode.EditMode, filter, filterType, includeExplicit, timeoutSeconds); + + if (!editorResponse.Success) + { + return editorResponse; // Return error immediately + } + + // PlayMode can't run synchronously over HTTP (entering play mode triggers a domain + // reload that drops the request), so start it asynchronously and hand back a + // StatusPath. The caller polls the test_status command for the playmode results. + Debug.Log("[PipelineTestRunner] Starting playmode tests asynchronously (all mode)..."); + var playmodeStart = await ExecuteAsyncMode(TestMode.PlayMode, filter, filterType, includeExplicit, timeoutSeconds); + + if (!playmodeStart.Success) + { + return playmodeStart; // Return error immediately + } + + // Build combined response: editor results inline, playmode running async. + var duration = (DateTime.UtcNow - startTime).TotalSeconds; + return new TestExecutionResponse + { + Success = true, + Command = "run_tests", + Duration = Math.Round(duration, 2), + Mode = "All", + FilterApplied = string.IsNullOrEmpty(filter) ? null : $"{filterType}: {filter}", + ExecutionTimeMs = (int)(duration * 1000), + Summary = editorResponse.Summary, + Results = editorResponse.Results, + Result = "playmode_running", + StatusPath = playmodeStart.StatusPath, + Message = $"EditMode complete: {editorResponse.Summary.Passed}/{editorResponse.Summary.Total} passed. " + + "PlayMode tests started asynchronously — poll the test_status command for their results.", + ExecutedAt = DateTime.UtcNow + }; + } + catch (Exception ex) + { + Debug.LogError($"[PipelineTestRunner] All modes execution error: {ex.Message}"); + return CreateErrorResponse($"Failed to execute tests in all modes: {ex.Message}"); + } + } + + /// + /// Synchronous execution - blocks until completion + /// + private static async Task ExecuteSyncMode( + TestMode testMode, + string filter, + string filterType, + bool includeExplicit, + int timeoutSeconds) + { + var startTime = DateTime.UtcNow; + var api = ScriptableObject.CreateInstance(); + var collector = new TestResultCollector(); + + m_ActiveApi = api; + m_ActiveCollector = collector; + + // Set up timeout cancellation + using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(timeoutSeconds))) + { + cts.Token.Register(() => + { + Debug.Log("[PipelineTestRunner] Test execution timed out, cancelling..."); + InvalidatePreviousRun(); + }); + + try + { + // For PlayMode tests, we need to handle domain reloads + if (testMode == TestMode.PlayMode) + { + // Save request for domain reload recovery + var request = new TestRequest + { + filter = filter, + filterType = filterType, + mode = testMode.ToString(), + includeExplicit = includeExplicit, + isSync = true + }; + File.WriteAllText(TestRequestFile, JsonConvert.SerializeObject(request)); + } + + // Execute tests and wait for completion + var completionTask = ExecuteTestsInternal(api, collector, testMode, filter, filterType, includeExplicit); + var resultAdaptor = await completionTask; + + // Build response + var duration = (DateTime.UtcNow - startTime).TotalSeconds; + var response = new TestExecutionResponse + { + Success = true, + Command = "run_tests", + Duration = Math.Round(duration, 2), + Mode = testMode.ToString(), + FilterApplied = string.IsNullOrEmpty(filter) ? null : $"{filterType}: {filter}", + ExecutionTimeMs = (int)(duration * 1000), + Summary = resultAdaptor != null ? new TestSummary + { + Total = resultAdaptor.PassCount + resultAdaptor.FailCount + resultAdaptor.SkipCount + resultAdaptor.InconclusiveCount, + Passed = resultAdaptor.PassCount, + Failed = resultAdaptor.FailCount, + Skipped = resultAdaptor.SkipCount, + Inconclusive = resultAdaptor.InconclusiveCount + } : new TestSummary(), + Results = collector.Results, + ExecutedAt = DateTime.UtcNow + }; + + // Clean up PlayMode request file + CleanupRequestFile(); + + return response; + } + catch (OperationCanceledException) + { + return CreateErrorResponse("Test execution timed out"); + } + catch (Exception ex) + { + Debug.LogError($"[PipelineTestRunner] Sync execution error: {ex.Message}"); + CleanupRequestFile(); + return CreateErrorResponse($"Test execution failed: {ex.Message}"); + } + finally + { + UnregisterCollector(api, collector); + } + } + } + + /// + /// Asynchronous execution - returns immediately + /// + // Not async: the work here is synchronous (file I/O + a main-thread call that returns + // immediately). Returns a completed Task so callers can still await it. + private static Task ExecuteAsyncMode( + TestMode testMode, + string filter, + string filterType, + bool includeExplicit, + int timeoutSeconds) + { + try + { + // Save request to disk (survives domain reloads for PlayMode) + var request = new TestRequest + { + filter = filter, + filterType = filterType, + mode = testMode.ToString(), + includeExplicit = includeExplicit, + isSync = false + }; + File.WriteAllText(TestRequestFile, JsonConvert.SerializeObject(request)); + + // Clear any previous status + if (File.Exists(TestStatusFile)) + File.Delete(TestStatusFile); + + // Start test execution now, on the main thread (run_tests is MainThreadRequired, + // so we are inside the editor update tick that dispatched this command). Must NOT + // run on a background thread: the test runner creates a TestRunnerApi via + // ScriptableObject.CreateInstance, which is main-thread-only. RetrieveTestList + // returns immediately, so the HTTP "running" response below is still sent promptly. + StartAsyncTestExecution(testMode, filter, filterType, includeExplicit); + + return Task.FromResult(new TestExecutionResponse + { + Success = true, + Command = "run_tests", + Result = "running", + StatusPath = TestStatusFile, + Mode = testMode.ToString(), + FilterApplied = string.IsNullOrEmpty(filter) ? null : $"{filterType}: {filter}", + Message = "Tests started in async mode. Poll /test-status for results.", + ExecutedAt = DateTime.UtcNow + }); + } + catch (Exception ex) + { + Debug.LogError($"[PipelineTestRunner] Async setup error: {ex.Message}"); + return Task.FromResult(CreateErrorResponse($"Failed to start async test execution: {ex.Message}")); + } + } + + /// + /// Internal test execution logic + /// + private static async Task ExecuteTestsInternal( + TestRunnerApi api, + TestResultCollector collector, + TestMode testMode, + string filter, + string filterType, + bool includeExplicit) + { + var tcs = new TaskCompletionSource(); + + // Retrieve test list and filter + api.RetrieveTestList(testMode, (ITestAdaptor rootTest) => + { + try + { + var testNames = CollectTestNames(rootTest, filter, filterType, includeExplicit); + + if (testNames.Count == 0) + { + Debug.Log("[PipelineTestRunner] No tests to run after filtering"); + var emptyResult = CreateEmptyTestResult(); + tcs.SetResult(emptyResult); + return; + } + + Debug.Log($"[PipelineTestRunner] Running {testNames.Count} tests (explicit tests {(includeExplicit ? "included" : "excluded")})"); + + var testFilter = new Filter + { + testMode = testMode, + testNames = testNames.ToArray() + }; + + // Set up completion handling + collector.OnRunFinished = () => tcs.SetResult(collector.RootResult); + + api.RegisterCallbacks(collector); + api.Execute(new ExecutionSettings(testFilter)); + } + catch (Exception ex) + { + Debug.LogError($"[PipelineTestRunner] Error during test execution: {ex.Message}"); + tcs.SetException(ex); + } + }); + + return await tcs.Task; + } + + /// + /// Start async test execution on the main thread. Registers callbacks and kicks off the + /// run, then returns; completion is reported by the collector writing the status file. + /// Unlike the sync path, this does NOT reuse ExecuteTestsInternal (which sets its own + /// OnRunFinished to complete a Task, clobbering ours), and does NOT await. + /// + private static void StartAsyncTestExecution(TestMode testMode, string filter, string filterType, bool includeExplicit) + { + TestRunnerApi api = null; + TestResultCollector collector = null; + try + { + api = ScriptableObject.CreateInstance(); + collector = new TestResultCollector(); + + m_ActiveApi = api; + m_ActiveCollector = collector; + + // Async completion: write results for pollers. Set once, never overwritten. + collector.OnRunFinished = () => + { + WriteCompletedResults(collector); + RestoreLiveServerIfDisrupted(); // B2: self-heal if a test broke the live server. + CleanupRequestFile(); + UnregisterCollector(api, collector); + }; + + api.RetrieveTestList(testMode, (ITestAdaptor rootTest) => + { + try + { + var testNames = CollectTestNames(rootTest, filter, filterType, includeExplicit); + + if (testNames.Count == 0) + { + WriteStatusFile(new + { + status = "completed", + duration = 0.0, + summary = new { total = 0, passed = 0, failed = 0, skipped = 0, inconclusive = 0 }, + results = new object[0] + }); + CleanupRequestFile(); + UnregisterCollector(api, collector); + return; + } + + api.RegisterCallbacks(collector); + api.Execute(new ExecutionSettings(new Filter + { + testMode = testMode, + testNames = testNames.ToArray() + })); + } + catch (Exception ex) + { + Debug.LogError($"[PipelineTestRunner] Async run setup error: {ex.Message}"); + WriteStatusFile(new { status = "error", message = ex.Message }); + CleanupRequestFile(); + UnregisterCollector(api, collector); + } + }); + } + catch (Exception ex) + { + Debug.LogError($"[PipelineTestRunner] Async execution error: {ex.Message}"); + WriteStatusFile(new { status = "error", message = ex.Message }); + CleanupRequestFile(); + UnregisterCollector(api, collector); + } + } + + /// + /// Re-register a result collector to capture the completion of a PlayMode run that the + /// Unity Test Framework auto-resumes after a play-mode domain reload (see TestJobDataHolder + /// in the test-framework package). The previous collector did not survive the reload. + /// Deliberately does NOT call RetrieveTestList/api.Execute: the run is already in flight, so + /// starting another one double-executes the task list (running scene tasks during play + /// mode) and trips the runner's "too many instant steps" guard. The collector rebuilds its + /// per-test results from the RootResult tree at RunFinished, since the incremental + /// TestFinished callbacks were delivered to a collector from the previous domain. + /// + private static void ReattachResultCollector() + { + TestRunnerApi api = null; + TestResultCollector collector = null; + try + { + api = ScriptableObject.CreateInstance(); + collector = new TestResultCollector(); + + m_ActiveApi = api; + m_ActiveCollector = collector; + + collector.OnRunFinished = () => + { + WriteCompletedResults(collector); + RestoreLiveServerIfDisrupted(); + CleanupRequestFile(); + UnregisterCollector(api, collector); + }; + + api.RegisterCallbacks(collector); + } + catch (Exception ex) + { + Debug.LogError($"[PipelineTestRunner] Failed to reattach result collector: {ex.Message}"); + WriteStatusFile(new { status = "error", message = ex.Message }); + CleanupRequestFile(); + UnregisterCollector(api, collector); + } + } + + /// + /// Called after domain reload to resume pending tests + /// + [InitializeOnLoad] + public static class TestReloader + { + static TestReloader() + { + EditorApplication.delayCall += CheckForPendingTests; + } + } + + /// Resume any test run that was in flight before a domain reload dropped it. + public static void CheckForPendingTests() + { + if (!File.Exists(TestRequestFile)) return; + if (File.Exists(TestStatusFile)) return; // Already completed + + try + { + var json = File.ReadAllText(TestRequestFile); + var request = JsonConvert.DeserializeObject(json); + + Debug.Log("[PipelineTestRunner] Reattaching result collector after domain reload"); + if (request.isSync) + { + // For sync mode, we can't really resume after domain reload + // The command has already timed out or failed + CleanupRequestFile(); + return; + } + + // The Unity Test Framework (TestJobDataHolder) auto-resumes the in-flight PlayMode + // run after a play-mode domain reload. We must NOT start a new run here: re-calling + // api.Execute double-starts the job, which re-runs the task list (executing scene + // tasks during play mode) and trips the runner's "too many instant steps" guard. + // We only need to re-register a collector — our previous one did not survive the + // reload — to capture the resumed run's completion. Runs on the main thread because + // CheckForPendingTests is invoked via EditorApplication.delayCall. + ReattachResultCollector(); + } + catch (Exception ex) + { + Debug.LogError($"[PipelineTestRunner] Failed to resume tests: {ex.Message}"); + WriteStatusFile(new { status = "error", message = $"Failed to resume tests: {ex.Message}" }); + CleanupRequestFile(); + } + } + + #region Utility Methods + + private struct ParsedTestMode + { + public bool IsValid { get; set; } + public bool IsAll { get; set; } + public TestMode TestMode { get; set; } + + public static ParsedTestMode Invalid => new ParsedTestMode { IsValid = false }; + public static ParsedTestMode All => new ParsedTestMode { IsValid = true, IsAll = true }; + public static ParsedTestMode Single(TestMode mode) => new ParsedTestMode { IsValid = true, IsAll = false, TestMode = mode }; + } + + private static ParsedTestMode ParseTestMode(string mode) + { + switch (mode?.ToLower()) + { + case "editor": + case "editmode": + return ParsedTestMode.Single(TestMode.EditMode); + case "playmode": + case "play": + return ParsedTestMode.Single(TestMode.PlayMode); + case "all": + return ParsedTestMode.All; + default: + return ParsedTestMode.Invalid; + } + } + + private static List CollectTestNames(ITestAdaptor test, string filter, string filterType, bool includeExplicit) + { + var testNames = new List(); + CollectTestNamesRecursive(test, testNames, filter, filterType, includeExplicit); + return testNames; + } + + private static void CollectTestNamesRecursive(ITestAdaptor test, List testNames, string filter, string filterType, bool includeExplicit) + { + if (test == null) return; + + // Skip [Explicit] tests AND [Explicit] fixtures (the whole subtree) unless includeExplicit. + // Checked at EVERY node — including suite/fixture nodes — because a class-level [Explicit] + // is not reliably propagated to [UnityTest] leaf RunState by Unity's adaptor; honoring the + // declaring type's attribute here is what makes class-level [Explicit] actually exclude. + if (!includeExplicit && IsExplicit(test)) + return; + + // Only collect leaf tests (actual test methods, not fixtures/suites) + if (!test.HasChildren && test.IsSuite == false) + { + // Apply user filter + if (!ShouldIncludeTest(test, filter, filterType)) + return; + + testNames.Add(test.FullName); + } + + // Recurse into children + if (test.Children != null) + { + foreach (var child in test.Children) + { + CollectTestNamesRecursive(child, testNames, filter, filterType, includeExplicit); + } + } + } + + /// + /// True if the test, its method, or its declaring fixture type is marked [Explicit]. + /// Class-level [Explicit] must be honored here because Unity does not always propagate it + /// to leaf RunState (notably for [UnityTest]). + /// + private static bool IsExplicit(ITestAdaptor test) + { + if (test.RunState == RunState.Explicit) + return true; + + var method = test.Method?.MethodInfo; + if (method != null && method.GetCustomAttributes(true).Any(a => a.GetType().Name == "ExplicitAttribute")) + return true; + + var type = test.TypeInfo?.Type; + if (type != null && type.GetCustomAttributes(true).Any(a => a.GetType().Name == "ExplicitAttribute")) + return true; + + return false; + } + + private static bool ShouldIncludeTest(ITestAdaptor test, string filter, string filterType) + { + if (string.IsNullOrEmpty(filter)) + return true; + + switch (filterType) + { + case "assembly": + var assemblyName = test.TypeInfo?.Assembly?.GetName()?.Name; + return assemblyName != null && + assemblyName.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0; + + case "testname": + return test.FullName != null && + test.FullName.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0; + + case "category": + return test.Categories != null && + test.Categories.Any(c => c.Equals(filter, StringComparison.OrdinalIgnoreCase)); + + default: + return true; + } + } + + private static void InvalidatePreviousRun() + { + if (m_ActiveCollector != null) + { + m_ActiveCollector.Cancel(); + UnregisterCollector(m_ActiveApi, m_ActiveCollector); + Debug.Log("[PipelineTestRunner] Invalidated previous test run"); + } + } + + /// + /// Unregisters a collector from Unity's TestRunnerApi callback registry (process-wide, not + /// per-instance) and clears the active-run fields if they still point at it. + /// + private static void UnregisterCollector(TestRunnerApi api, TestResultCollector collector) + { + if (api != null && collector != null) + { + try { api.UnregisterCallbacks(collector); } + catch (Exception ex) + { + Debug.LogWarning($"[PipelineTestRunner] Could not unregister collector: {ex.Message}"); + } + } + + if (ReferenceEquals(m_ActiveCollector, collector)) + { + m_ActiveApi = null; + m_ActiveCollector = null; + } + } + + private static TestExecutionResponse CreateErrorResponse(string message) + { + return new TestExecutionResponse + { + Success = false, + Command = "run_tests", + Error = message, + Results = new List(), + Summary = new TestSummary(), + ExecutedAt = DateTime.UtcNow + }; + } + + private static ITestResultAdaptor CreateEmptyTestResult() + { + // This is a bit of a hack since ITestResultAdaptor is an interface + // In practice, this case should be rare (no tests matching filter) + return null; + } + + /// + /// B2 self-heal: after a test run, if a test left the live editor server disrupted (its + /// listener died, or its discovery descriptor was deleted/clobbered), restart it so the + /// dogfood loop and subsequent commands keep working instead of wedging the session. No-op + /// when the server is healthy. Runs at run completion — the watchdog is disabled during the + /// run (PipelineWatchdogTestGuard), so this is what revives the live server afterwards. + /// + private static void RestoreLiveServerIfDisrupted() + { + try + { + var server = PipelineServerStartup.Server; + var root = Path.GetDirectoryName(Application.dataPath); + var descriptor = Unity.Pipeline.Models.InstanceDescriptor.ReadFromProjectRoot(root); + + var disrupted = server == null + || !server.IsRunning + || descriptor == null + || descriptor.Port != server.Port; + + if (disrupted) + { + Debug.Log("[PipelineTestRunner] Live server was disrupted during the test run — restarting it."); + PipelineServerStartup.RestartServer(); + } + } + catch (Exception ex) + { + Debug.LogWarning($"[PipelineTestRunner] Live server restore check failed: {ex.Message}"); + } + } + + private static void WriteCompletedResults(TestResultCollector collector) + { + try + { + if (!collector.IsComplete) + { + WriteStatusFile(new { status = "error", message = "Tests did not complete" }); + return; + } + + var root = collector.RootResult; + var result = new + { + status = "completed", + duration = Math.Round(root.Duration, 2), + summary = new + { + total = root.PassCount + root.FailCount + root.SkipCount + root.InconclusiveCount, + passed = root.PassCount, + failed = root.FailCount, + skipped = root.SkipCount, + inconclusive = root.InconclusiveCount + }, + results = collector.Results.ToArray() + }; + + WriteStatusFile(result); + } + catch (Exception ex) + { + Debug.LogError($"[PipelineTestRunner] Failed to write results: {ex.Message}"); + WriteStatusFile(new { status = "error", message = ex.Message }); + } + } + + private static void WriteStatusFile(object data) + { + try + { + File.WriteAllText(TestStatusFile, JsonConvert.SerializeObject(data, Formatting.Indented)); + } + catch (Exception ex) + { + Debug.LogError($"[PipelineTestRunner] Failed to write status file: {ex.Message}"); + } + } + + private static void CleanupRequestFile() + { + try { if (File.Exists(TestRequestFile)) File.Delete(TestRequestFile); } catch { } + } + + /// + /// Get current test status (for async mode polling) + /// + /// The status file's JSON contents, "running" if a request is pending, or null if there's no run. + public static string GetTestStatus() + { + if (File.Exists(TestStatusFile)) + return File.ReadAllText(TestStatusFile); + if (File.Exists(TestRequestFile)) + return JsonConvert.SerializeObject(new { status = "running" }); + return null; + } + + /// + /// Cancel running tests + /// + /// A status payload confirming cancellation (or that there was nothing to cancel). + public static object CancelTests() + { + if (m_ActiveCollector == null && !File.Exists(TestRequestFile) && !File.Exists(TestStatusFile)) + return new { status = "no_tests", message = "No test run in progress." }; + + bool wasPlayMode = false; + try + { + if (File.Exists(TestRequestFile)) + { + var json = File.ReadAllText(TestRequestFile); + wasPlayMode = json.Contains("PlayMode"); + } + } + catch { } + + InvalidatePreviousRun(); + WriteStatusFile(new { status = "cancelled", message = "Test run cancelled." }); + CleanupRequestFile(); + + if (wasPlayMode && EditorApplication.isPlaying) + { + Debug.Log("[PipelineTestRunner] Exiting play mode to cancel PlayMode tests"); + EditorApplication.ExitPlaymode(); + } + + Debug.Log("[PipelineTestRunner] Test run cancelled"); + return new { status = "cancelled", message = "Test run cancelled." }; + } + + #endregion + + [Serializable] + private class TestRequest + { + public string filter; + public string filterType; + public string mode; + public bool includeExplicit; + public bool isSync; + } + } +} + diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Testing/PipelineTestRunner.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Testing/PipelineTestRunner.cs.meta new file mode 100644 index 0000000..2992d00 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Testing/PipelineTestRunner.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b9212c4c36abc384e8bdbefe0d9892df +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Testing/TestResultCollector.cs b/AIClient/Packages/com.unity.pipeline/Editor/Testing/TestResultCollector.cs new file mode 100644 index 0000000..32114ed --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Testing/TestResultCollector.cs @@ -0,0 +1,182 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using UnityEditor.TestTools.TestRunner.Api; +using UnityEngine; + +namespace Unity.Pipeline.Editor.Testing +{ + /// + /// Collects test results from Unity TestRunner API callbacks. + /// Adapted from unity-tools implementation with sync/async mode support. + /// + class TestResultCollector : ICallbacks + { + /// True once has processed a (non-duplicate, non-cancelled) run. + public bool IsComplete { get; private set; } + /// Set by ; subsequent callbacks are ignored once true. + public bool IsCancelled { get; set; } + /// Per-test results collected so far. + public List Results { get; } = new List(); + /// The completed run's root result tree, set by . + public ITestResultAdaptor RootResult { get; private set; } + + // For async mode + /// Invoked when processes a completed run (async mode). + public Action OnRunFinished { get; set; } + + // For sync mode + private TaskCompletionSource m_CompletionSource; + + /// Create a collector ready to receive callbacks for a new run. + public TestResultCollector() + { + m_CompletionSource = new TaskCompletionSource(); + } + + /// + /// Wait for test completion (sync mode) + /// + /// The completed run's root result tree. + public Task WaitForCompletionAsync() + { + return m_CompletionSource.Task; + } + + /// ICallbacks hook: a run has started. + /// The tests about to run. + public void RunStarted(ITestAdaptor testsToRun) + { + if (IsCancelled) return; + + IsComplete = false; + Results.Clear(); + Debug.Log($"[TestResultCollector] Run started: {testsToRun.TestCaseCount} test(s)"); + } + + /// ICallbacks hook: a single test has started. No-op. + /// The test about to run. + public void TestStarted(ITestAdaptor test) + { + // No action needed for test start + } + + /// ICallbacks hook: a single (non-suite) test has finished. + /// The finished test's result. + public void TestFinished(ITestResultAdaptor result) + { + if (IsCancelled) return; + if (result.Test.IsSuite) return; + + Results.Add(BuildTestResult(result)); + } + + /// ICallbacks hook: the run has finished. + /// The run's root result tree. + public void RunFinished(ITestResultAdaptor result) + { + if (IsCancelled) + { + Debug.Log("[TestResultCollector] Ignoring RunFinished from cancelled run"); + return; + } + + // A stale collector can receive a later run's RunFinished (see PipelineTestRunner); + // re-completing OnRunFinished/m_CompletionSource would throw. IsComplete can't detect + // this — RunStarted resets it on every non-cancelled collector, stale ones included. + if (m_CompletionSource.Task.IsCompleted) + { + Debug.Log("[TestResultCollector] Ignoring duplicate RunFinished (already completed)"); + return; + } + + RootResult = result; + IsComplete = true; + + // If we attached after the tests already ran (PlayMode re-registers a fresh collector + // after each play-mode domain reload, so the incremental TestFinished callbacks were + // delivered to a collector from a previous domain), rebuild from the authoritative + // result tree. The normal in-domain path leaves Results already populated. + if (Results.Count == 0) + { + CollectLeafResults(result); + } + + var total = result.PassCount + result.FailCount + result.SkipCount + result.InconclusiveCount; + Debug.Log($"[TestResultCollector] Run finished: {total} total, {result.PassCount} passed, {result.FailCount} failed"); + + // Notify async mode + OnRunFinished?.Invoke(); + + // Notify sync mode (guard against double-complete if the task was already + // completed by SetError/Cancel, mirroring the guards in those methods) + m_CompletionSource.TrySetResult(result); + } + + /// + /// Cancel the test collection and notify sync waiters + /// + public void Cancel() + { + IsCancelled = true; + if (!m_CompletionSource.Task.IsCompleted) + { + m_CompletionSource.SetCanceled(); + } + } + + /// + /// Set error state and notify sync waiters + /// + /// The error to complete the sync waiter's task with. + public void SetError(Exception exception) + { + if (!m_CompletionSource.Task.IsCompleted) + { + m_CompletionSource.SetException(exception); + } + } + + /// + /// Recursively collect leaf (non-suite) test results from the result tree. Used at + /// RunFinished to rebuild Results when this collector was registered too late to receive + /// the incremental TestFinished callbacks (PlayMode resume after a domain reload). + /// + private void CollectLeafResults(ITestResultAdaptor result) + { + if (result == null) return; + + if (!result.Test.IsSuite && !result.Test.HasChildren) + { + Results.Add(BuildTestResult(result)); + return; + } + + if (result.Children != null) + { + foreach (var child in result.Children) + { + CollectLeafResults(child); + } + } + } + + private static TestResult BuildTestResult(ITestResultAdaptor result) + { + return new TestResult + { + FullName = result.Test.FullName, + Status = result.TestStatus.ToString(), + Duration = result.Duration, + Message = Truncate(result.Message, 10000), + StackTrace = Truncate(result.StackTrace, 10000) + }; + } + + private static string Truncate(string s, int maxLength) + { + if (s == null || s.Length <= maxLength) return s; + return s.Substring(0, maxLength) + "\n... (truncated)"; + } + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Testing/TestResultCollector.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/Testing/TestResultCollector.cs.meta new file mode 100644 index 0000000..97f68e1 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Testing/TestResultCollector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f4541ff42ef502f4989e8ab059df20f3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/TypeCacheCommandDiscovery.cs b/AIClient/Packages/com.unity.pipeline/Editor/TypeCacheCommandDiscovery.cs new file mode 100644 index 0000000..9174418 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/TypeCacheCommandDiscovery.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using Unity.Pipeline.Commands; +using UnityEditor; + +namespace Unity.Pipeline.Editor +{ + /// + /// Editor implementation of command discovery using Unity's TypeCache. + /// Provides fast command discovery in Editor mode via Unity's optimized caching system. + /// + class TypeCacheCommandDiscovery : ICommandDiscovery + { + /// + /// Find all methods marked with specified attribute using TypeCache. + /// + /// The attribute type to search for. + /// The matching methods. + public IEnumerable GetMethodsWithAttribute() where T : Attribute + { + return TypeCache.GetMethodsWithAttribute(); + } + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Editor/TypeCacheCommandDiscovery.cs.meta b/AIClient/Packages/com.unity.pipeline/Editor/TypeCacheCommandDiscovery.cs.meta new file mode 100644 index 0000000..15b703c --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/TypeCacheCommandDiscovery.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f7f7b0f5ced14e548afee892a4014ce9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Unity.Pipeline.Editor.asmdef b/AIClient/Packages/com.unity.pipeline/Editor/Unity.Pipeline.Editor.asmdef new file mode 100644 index 0000000..c2e7ed4 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Unity.Pipeline.Editor.asmdef @@ -0,0 +1,21 @@ +{ + "name": "Unity.Pipeline.Editor", + "rootNamespace": "Unity.Pipeline.Editor", + "references": [ + "Unity.Pipeline", + "Unity.Pipeline.Attributes", + "Unity.Pipeline.IlInterpreter", + "Unity.Nuget.Newtonsoft-Json" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} diff --git a/AIClient/Packages/com.unity.pipeline/Editor/Unity.Pipeline.Editor.asmdef.meta b/AIClient/Packages/com.unity.pipeline/Editor/Unity.Pipeline.Editor.asmdef.meta new file mode 100644 index 0000000..0b423f3 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Editor/Unity.Pipeline.Editor.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a3ca9b2d97442e0499ea28b681f751d9 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/LICENSE.md b/AIClient/Packages/com.unity.pipeline/LICENSE.md new file mode 100644 index 0000000..d786c29 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/LICENSE.md @@ -0,0 +1,5 @@ +com.unity.pipeline copyright © 2026 Unity Technologies + +Licensed under the Unity Package Distribution License (see https://unity3d.com/legal/licenses/Unity_Package_Distribution_License ). + +Unless expressly provided otherwise, the software under this license is made available strictly on an “AS IS” BASIS WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED. Please review the license for details on these and other terms and conditions.” diff --git a/AIClient/Packages/com.unity.pipeline/LICENSE.md.meta b/AIClient/Packages/com.unity.pipeline/LICENSE.md.meta new file mode 100644 index 0000000..6b4c589 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/LICENSE.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c07017e56bf04bf4992412964a20140c +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/README.md b/AIClient/Packages/com.unity.pipeline/README.md new file mode 100644 index 0000000..00295ab --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/README.md @@ -0,0 +1,91 @@ +# Unity Pipeline Package + +[![Unity Version](https://img.shields.io/badge/Unity-6.0%2B-blue.svg)](https://unity3d.com/unity/whats-new/2023.3.0) + +Transform Unity Editor into a programmable automation element for CI/CD pipelines and development workflows. The package exposes a running Unity Editor (or development Player) over a local HTTP API so external tools, scripts, or agents can execute commands remotely. + +## Install the Unity CLI + +The Pipeline package is driven through the `unity` CLI. + +macOS / Linux +``` +curl -fsSL https://public-cdn.cloud.unity3d.com/hub/prod/cli/install.sh | UNITY_CLI_CHANNEL=beta bash +``` + +Windows (PowerShell) +``` +$env:UNITY_CLI_CHANNEL='beta'; irm https://public-cdn.cloud.unity3d.com/hub/prod/cli/install.ps1 | iex +``` + +For more details, see the [CLI documentation](https://github.com/Unity-Technologies/unity-hub/tree/dev/src/cli). + +## Install the Pipeline package + +Install the package into a Unity project with: + +```bash +unity pipeline install +``` + +By default it targets the current directory (or the running Unity instance). Use `--project-path` to target a specific project: + +```bash +unity pipeline install --project-path /path/to/your/unity/project +``` + +Then open the project in the Unity Editor. The package automatically starts its HTTP server and registers the built-in commands. + +## Connect to a running Editor + +Run `unity command` with no command name to connect to a Unity instance and list its available commands: + +```bash +# Auto-discover a Unity instance from the current directory +unity command + +# Connect to a specific project +unity command --project-path /path/to/your/unity/project +``` + +Click [here](Documentation~/connectivity.md) for more details on Connectivity troubleshooting. + +## Connect to a running Player (Runtime) + +To target a running development Player instead of the Editor, use `--runtime` (by process name) or `--runtime-path` (by the location of the runtime port file). These options go **after** `command` and **before** the command name. + +```bash +# By Player process/executable name +unity command --runtime MyGame.exe runtime_status + +# By the path where the runtime port file is located +unity command --runtime-path runtime_status +``` + +`--runtime-path` points to where the `.unity-pipeline-runtime-port` file lives: + +- **Windows** — the port file sits next to the Player executable: + + ```bash + unity command --runtime-path "C:\Builds\MyGame" runtime_status + ``` + +- **macOS** — pass the path to the `.app` bundle: + + ```bash + unity command --runtime-path "/Users/me/Builds/MyGame.app" runtime_status + ``` + +Click [here](Documentation~/connectivity.md) for more details on Connectivity troubleshooting. + +## Documentation + +For the full command reference, connectivity details, runtime setup, and code-reload guides, see the [Pipeline documentation](Documentation~/index.md). + +## License + +com.unity.package is licensed under the Unity Companion License. See [LICENSE.md](LICENSE.md) for more legal information. + +## Contributions to this repository + +We are not accepting pull requests at this time. If you find an issue with the package or would like to request a new feature, please submit a [GitHub issue](https://github.com/Unity-Technologies/com.unity.pipeline/issues). diff --git a/AIClient/Packages/com.unity.pipeline/README.md.meta b/AIClient/Packages/com.unity.pipeline/README.md.meta new file mode 100644 index 0000000..786d10f --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d1a2488a30b969941afb4af17c063ad3 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime.meta b/AIClient/Packages/com.unity.pipeline/Runtime.meta new file mode 100644 index 0000000..4b3402e --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a9bf7426ce9ccf4448467e47c849c567 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Analyzers.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Analyzers.meta new file mode 100644 index 0000000..501f850 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Analyzers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a83ffb4c25f355a419ba91b8fc12ca48 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Analyzers/IlInterpreterAnalyzer.dll b/AIClient/Packages/com.unity.pipeline/Runtime/Analyzers/IlInterpreterAnalyzer.dll new file mode 100644 index 0000000000000000000000000000000000000000..82197e41cd37f6ed60298add29b8f8c733c13845 GIT binary patch literal 18944 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 literal 0 HcmV?d00001 diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Analyzers/IlInterpreterAnalyzer.dll.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Analyzers/IlInterpreterAnalyzer.dll.meta new file mode 100644 index 0000000..85a1566 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Analyzers/IlInterpreterAnalyzer.dll.meta @@ -0,0 +1,39 @@ +fileFormatVersion: 2 +guid: 33fa77d2af5e469ca652745160e4c35d +labels: +- RoslynAnalyzer +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + : Any + second: + enabled: 0 + settings: + Exclude Editor: 1 + Exclude Linux64: 1 + Exclude OSXUniversal: 1 + Exclude Win: 1 + Exclude Win64: 1 + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/AssemblyInfo.cs b/AIClient/Packages/com.unity.pipeline/Runtime/AssemblyInfo.cs new file mode 100644 index 0000000..1f7bd9b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/AssemblyInfo.cs @@ -0,0 +1,10 @@ +using System.Runtime.CompilerServices; + +// Lets the runtime test assembly's PipelineClient read a server's internal Token to authenticate. +[assembly: InternalsVisibleTo("Unity.Pipeline.Tests.Runtime")] +// Lets the EditMode test assembly unit-test internal runtime utilities (e.g. MaxLengthStream). +[assembly: InternalsVisibleTo("Unity.Pipeline.Tests.Editor")] +// Lets the Editor assembly feed CliProgress's internal ambient mirror (EditorProgressMirror) +// and consume internal interpreter glue (e.g. IlInterpreterHostBindings, which the code-reload +// link.xml generator derives its preservation set from). +[assembly: InternalsVisibleTo("Unity.Pipeline.Editor")] diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/AssemblyInfo.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/AssemblyInfo.cs.meta new file mode 100644 index 0000000..0045189 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/AssemblyInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 87863085291527c4581eb05fcc20b47c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Attributes.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Attributes.meta new file mode 100644 index 0000000..585d915 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Attributes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3da432e2a5ea462089d41e21aa49f59b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Attributes/CodeReloadAttributes.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Attributes/CodeReloadAttributes.cs new file mode 100644 index 0000000..0d1082d --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Attributes/CodeReloadAttributes.cs @@ -0,0 +1,71 @@ +using System; + +namespace Unity.Pipeline.CodeReload +{ + /// + /// Marks a method as reloadable: edit its body directly in the original source file and + /// apply the file with the reload_file command (or the interpreter-backed variants). The + /// running instance picks up the new body without a domain reload. Bodies may touch members of + /// any accessibility, including private/protected/internal ones of the target type. + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public class CodeReloadAttribute : Attribute + { + /// + /// Optional identifier for this reloadable method. + /// If not specified, uses TypeName.MethodName format. + /// + public string Id { get; set; } + + /// + /// Whether this method requires main thread execution. + /// Defaults to true for Unity API safety. + /// + public bool RequireMainThread { get; set; } = true; + } + + /// + /// Marks a parameterless instance method to be invoked after a code reload is applied to its + /// declaring component. Fires once per reload_file that binds at least one override on + /// the type, on every live instance — a place to re-initialize or refresh state when the code is + /// swapped (analogous to a domain-reload-free OnEnable). The method runs on the main thread; + /// exceptions are logged, not propagated. Only UnityEngine.Object-derived types are supported + /// (instances are discovered via FindObjectsByType). + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + [JetBrains.Annotations.MeansImplicitUse] + public class OnCodeReloadAttribute : Attribute + { + } + + /// + /// Marks a compiled static method as the code reload override for a specific [CodeReload] + /// method. Emitted by the reload pipeline on the code it generates from an edited source file + /// (see SourceCodeTransformer); user code does not write it by hand. + /// + /// Override signature: the original method's signature plus the target instance as the first + /// parameter. Example: void Update() becomes static void Update(TargetType instance). + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public class CodeReloadOverrideMethodAttribute : Attribute + { + /// + /// Target method identifier in format "TypeName.MethodName" + /// Must match a method marked with [CodeReload]. + /// + public string TargetMethodId { get; } + + /// + /// Optional description of what this code reload does. + /// Useful for debugging and code reload management. + /// + public string Description { get; set; } + + /// Mark a method as the code-reload override for the given target method. + /// Target method identifier, "TypeName.MethodName". + public CodeReloadOverrideMethodAttribute(string targetMethodId) + { + TargetMethodId = targetMethodId ?? throw new ArgumentNullException(nameof(targetMethodId)); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Attributes/CodeReloadAttributes.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Attributes/CodeReloadAttributes.cs.meta new file mode 100644 index 0000000..2d20e06 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Attributes/CodeReloadAttributes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0bd43f6237214774ab4a178b811eb453 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Attributes/Unity.Pipeline.Attributes.asmdef b/AIClient/Packages/com.unity.pipeline/Runtime/Attributes/Unity.Pipeline.Attributes.asmdef new file mode 100644 index 0000000..8cc2ba3 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Attributes/Unity.Pipeline.Attributes.asmdef @@ -0,0 +1,14 @@ +{ + "name": "Unity.Pipeline.Attributes", + "rootNamespace": "Unity.Pipeline.CodeReload", + "references": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Attributes/Unity.Pipeline.Attributes.asmdef.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Attributes/Unity.Pipeline.Attributes.asmdef.meta new file mode 100644 index 0000000..799fa2c --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Attributes/Unity.Pipeline.Attributes.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b522baaf20314499ba2deea8dd838496 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload.meta b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload.meta new file mode 100644 index 0000000..5fa8328 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c29607a31a43d7149b8296de99b81d8e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/AccessibilityValidator.cs b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/AccessibilityValidator.cs new file mode 100644 index 0000000..7df5a39 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/AccessibilityValidator.cs @@ -0,0 +1,211 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityPipeline.Microsoft.CodeAnalysis; +using UnityPipeline.Microsoft.CodeAnalysis.CSharp; +using UnityPipeline.Microsoft.CodeAnalysis.CSharp.Syntax; +using UnityEngine; + +namespace Unity.Pipeline.CodeReload +{ + /// + /// Accessibility gate for [CodeReload] method bodies on the compiled (Assembly.Load) backend. + /// + /// The compiled backend cannot use non-public members of the target type: even if the override + /// compiled with Roslyn's access checks relaxed, Unity's Mono enforces accessibility when + /// JIT-ing the loaded override IL and does not honor [assembly: IgnoresAccessChecksTo] + /// (verified on Mono 6.13) — the access would throw (e.g. FieldAccessException) on first + /// dispatch and silently fall back to the original body. Compiled-backend overrides therefore + /// compile with standard access checks (see + /// RoslynCompilationService.AllowNonPublicMemberAccess, interpreter-only), and this + /// validator runs up front — only when the compiled backend will execute the override — to turn + /// the eventual raw CS0122 into a clear reload error. The interpreter backend reaches + /// non-public members via reflection and must not be gated. + /// + static class AccessibilityValidator + { + /// + /// Check that every [CodeReload] method body only accesses public instance members of its + /// declaring type. Runs over an already-built semantic model + class declaration, so the + /// in-place reload path shares one compilation between validation and transformation + /// instead of building two. + /// + /// The semantic model built over the source containing the declaring type. + /// The declaring type's class declaration within . + /// Map of method name to body source, for the methods being validated. + /// Name of the declaring type to validate against. + /// The validation result, including any violations found. + public static AccessibilityValidationResult ValidatePublicAccess( + SemanticModel model, + ClassDeclarationSyntax classDecl, + Dictionary methodBodies, + string originalTypeName) + { + var result = new AccessibilityValidationResult + { + IsValid = true, + Violations = new List() + }; + + try + { + var classSymbol = model.GetDeclaredSymbol(classDecl); + + foreach (var method in classDecl.Members.OfType()) + { + var methodName = method.Identifier.ValueText; + if (!methodBodies.ContainsKey(methodName) || method.Body == null) + continue; + + var seen = new HashSet(); + foreach (var name in method.Body.DescendantNodes().OfType()) + { + if (IsMemberName(name)) + continue; + + var symbol = model.GetSymbolInfo(name).Symbol; + if (!IsInstanceMemberOf(symbol, classSymbol)) + continue; + + if (symbol.DeclaredAccessibility != Accessibility.Public && seen.Add(symbol.Name)) + { + result.Violations.Add(new AccessibilityViolation + { + MemberName = symbol.Name, + MethodName = methodName, + AccessLevel = symbol.DeclaredAccessibility, + ViolationType = AccessibilityViolationType.PrivateAccess, + ErrorMessage = $"Cannot access non-public member '{symbol.Name}' " + + $"({symbol.DeclaredAccessibility}) in [CodeReload] method '{methodName}'", + Suggestion = $"Make '{symbol.Name}' public in {originalTypeName}, or reload " + + "through the interpreter backend (reload_file_editor_interpreter), which " + + "reaches non-public members. The compiled backend loads the override " + + "as a separate assembly and Mono enforces accessibility at dispatch." + }); + } + } + } + + result.IsValid = result.Violations.Count == 0; + return result; + } + catch (Exception ex) + { + Debug.LogError($"CodeReload: Accessibility validation error: {ex.Message}"); + return new AccessibilityValidationResult + { + IsValid = false, + ValidationError = ex.Message, + Violations = new List() + }; + } + } + + /// True if the name is the right-hand member name of an access (foo.Bar -> Bar). + private static bool IsMemberName(SimpleNameSyntax node) + { + if (node.Parent is MemberAccessExpressionSyntax ma && ma.Name == node) + return true; + if (node.Parent is QualifiedNameSyntax) + return true; + if (node.Parent is MemberBindingExpressionSyntax) + return true; + return false; + } + + /// True if the symbol is an instance field/property/method/event of the type or a base. + private static bool IsInstanceMemberOf(ISymbol symbol, INamedTypeSymbol type) + { + if (symbol == null || symbol.IsStatic) + return false; + + switch (symbol.Kind) + { + case SymbolKind.Field: + case SymbolKind.Property: + case SymbolKind.Method: + case SymbolKind.Event: + break; + default: + return false; + } + + for (var t = type; t != null; t = t.BaseType) + { + if (SymbolEqualityComparer.Default.Equals(t, symbol.ContainingType)) + return true; + } + return false; + } + } + + /// + /// Result of accessibility validation for code reload methods. + /// + class AccessibilityValidationResult + { + /// True when no accessibility violations were found. + public bool IsValid { get; set; } + /// Violations found, if any. + public List Violations { get; set; } = new List(); + /// Set when validation itself could not run (e.g. a parse failure), rather than a violation being found. + public string ValidationError { get; set; } + + /// Human-readable summary of or all . + public string GetFormattedErrorMessage() + { + if (!string.IsNullOrEmpty(ValidationError)) + return $"CodeReload Validation Error: {ValidationError}"; + + if (Violations.Count == 0) + return "All member access is valid for code reload."; + + var errorMessage = $"CodeReload Validation Failed: {Violations.Count} accessibility violation(s) found\n\n"; + for (int i = 0; i < Violations.Count; i++) + { + var violation = Violations[i]; + errorMessage += $"{i + 1}. Method '{violation.MethodName}': {violation.ErrorMessage}\n"; + errorMessage += $" → Suggestion: {violation.Suggestion}\n"; + if (i < Violations.Count - 1) + errorMessage += "\n"; + } + + errorMessage += "\nFix these accessibility issues and run reload_file again."; + return errorMessage; + } + } + + /// + /// Information about a specific accessibility violation in code reload code. + /// + class AccessibilityViolation + { + /// Name of the non-public member that was accessed. + public string MemberName { get; set; } + /// Name of the [CodeReload] method containing the access. + public string MethodName { get; set; } + /// The member's actual accessibility. + public Accessibility AccessLevel { get; set; } + /// Category of violation. + public AccessibilityViolationType ViolationType { get; set; } + /// Human-readable description of the violation. + public string ErrorMessage { get; set; } + /// Suggested fix. + public string Suggestion { get; set; } + } + + /// + /// Types of accessibility violations that can occur in code reload methods. + /// + enum AccessibilityViolationType + { + /// A private member was accessed. + PrivateAccess, + /// An internal member was accessed. + InternalAccess, + /// A protected member was accessed. + ProtectedAccess, + /// The source could not be parsed to determine accessibility. + ParseError + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/AccessibilityValidator.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/AccessibilityValidator.cs.meta new file mode 100644 index 0000000..3958537 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/AccessibilityValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1bdaafa6e8d172648a57310104db179a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/CodeReloadActivity.cs b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/CodeReloadActivity.cs new file mode 100644 index 0000000..2edcc0b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/CodeReloadActivity.cs @@ -0,0 +1,67 @@ +using System; + +namespace Unity.Pipeline.CodeReload +{ + /// + /// Thread-safe snapshot of the most recent code-reload activity, for on-screen display by + /// . Fed from two sides: the PlayerConnection receiver + /// (compile-started / compile-failed notices arrive on a background thread) and the apply path + /// in RuntimePipelineDriver (main thread). Timestamps use + /// because Unity's Time API is main-thread-only and reporters run off it. + /// + static class CodeReloadActivity + { + public enum Phase + { + /// No reload in flight; nothing to show beyond the override count. + Idle = 0, + /// The editor announced a compile for this player (ReloadPendingMsg). + Compiling = 1, + /// A pushed override was applied; message is the apply summary. + Applied = 2, + /// Editor compile failed or on-device apply failed; message says why. + Failed = 3, + } + + private static readonly object s_Lock = new object(); + private static Phase s_Phase = Phase.Idle; + private static string s_Message = ""; + private static int s_PhaseTick = Environment.TickCount; + + public static void ReportCompileStarted(string name) => Set(Phase.Compiling, name); + public static void ReportApplied(string summary) => Set(Phase.Applied, summary); + public static void ReportFailed(string summary) => Set(Phase.Failed, summary); + + private static void Set(Phase phase, string message) + { + lock (s_Lock) + { + s_Phase = phase; + s_Message = message ?? ""; + s_PhaseTick = Environment.TickCount; + } + } + + /// Current phase, its message, and milliseconds since the phase changed. + public static Phase Snapshot(out string message, out int ageMs) + { + lock (s_Lock) + { + message = s_Message; + ageMs = Environment.TickCount - s_PhaseTick; + return s_Phase; + } + } + + private static long s_OverrideCalls; + + /// Called by the dispatch path once per overridden-method invocation. The running + /// total lets the overlay show a call rate — "N overrides · 0 calls/s" exposes the + /// bound-but-inert case (override registered but the woven prologue never dispatching), + /// which no log line catches. + public static void CountOverrideCall() => System.Threading.Interlocked.Increment(ref s_OverrideCalls); + + /// Total overridden-method invocations this session. + public static long OverrideCallCount => System.Threading.Interlocked.Read(ref s_OverrideCalls); + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/CodeReloadActivity.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/CodeReloadActivity.cs.meta new file mode 100644 index 0000000..21640ef --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/CodeReloadActivity.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 689f041b295d86a4b8ffd6249abf5a7a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/CodeReloadBaseline.cs b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/CodeReloadBaseline.cs new file mode 100644 index 0000000..ddeadd6 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/CodeReloadBaseline.cs @@ -0,0 +1,295 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Text; +using UnityPipeline.Microsoft.CodeAnalysis; +using UnityPipeline.Microsoft.CodeAnalysis.CSharp; +using UnityPipeline.Microsoft.CodeAnalysis.CSharp.Syntax; +using UnityPipeline.Microsoft.CodeAnalysis.Text; +using Unity.Pipeline.Compilation; + +namespace Unity.Pipeline.CodeReload +{ + /// + /// Per-method snapshot of a reloadable file's last-compiled source, so a reload can skip + /// methods whose bodies still match the code the target already runs compiled. Without this, + /// every save re-registers an interpreter override for every [CodeReload] method in the file, + /// and methods the user never touched pay the interpreter's per-call cost. + /// + /// A baseline is captured per (file, preprocessor symbols) pair — the same file diffs + /// differently under editor and player defines. For each [CodeReload] method it stores a hash + /// of the declaration's token stream (trivia excluded, so whitespace and comment edits don't + /// count as changes), plus one context hash over the rest of the file with all executable + /// bodies removed. A context change (fields, consts, signatures, usings) conservatively marks + /// every method changed: an override compiles against the current file, so same-file + /// declaration edits can shift an untouched body's meaning. + /// + /// Owned by whoever knows when disk matches the compiled state (the editor watch); with no + /// baseline captured, classification returns null and reloads behave as before. The store is + /// static, so the editor persists/restores it across domain reloads itself. + /// + static class CodeReloadBaseline + { + private sealed class Entry + { + public ulong ContextHash; + public readonly Dictionary MethodHashes = new Dictionary(); + } + + // Key: normalized full path + '\u001f' + define key. + private static readonly Dictionary s_Entries = + new Dictionary(StringComparer.OrdinalIgnoreCase); + + /// Number of captured (file, defines) baselines. + public static int Count => s_Entries.Count; + + /// + /// Snapshot as the compiled reference state for the given + /// preprocessor symbols (null = project defaults). Call only when the file on disk is known + /// to match what the reload target runs compiled. Returns false (and drops any stale entry) + /// when the file can't be read or has no [CodeReload] method. + /// + public static bool Capture(string filePath, string[] preprocessorSymbols = null) + { + string source; + try { source = File.ReadAllText(filePath); } + catch { source = null; } + return CaptureFromSource(filePath, source, preprocessorSymbols); + } + + /// See ; source text supplied by the caller (tests). + public static bool CaptureFromSource(string filePath, string sourceCode, string[] preprocessorSymbols = null) + { + var key = KeyFor(filePath, preprocessorSymbols); + var entry = sourceCode == null ? null : ComputeEntry(sourceCode, preprocessorSymbols); + if (entry == null) + { + s_Entries.Remove(key); + return false; + } + s_Entries[key] = entry; + return true; + } + + /// + /// Diff against the captured baseline for + /// (, ). Returns the + /// [CodeReload] method names whose declarations still match it — safe to leave running + /// compiled. Null when no baseline was captured for that pair (treat everything as + /// changed); empty when the file's context changed, so nothing is skippable. + /// + public static HashSet GetUnchangedMethods( + string filePath, string sourceCode, string[] preprocessorSymbols = null) + { + if (!s_Entries.TryGetValue(KeyFor(filePath, preprocessorSymbols), out var baseline)) + return null; + + var unchanged = new HashSet(StringComparer.Ordinal); + var current = sourceCode == null ? null : ComputeEntry(sourceCode, preprocessorSymbols); + if (current == null || current.ContextHash != baseline.ContextHash) + return unchanged; + + foreach (var kv in current.MethodHashes) + if (baseline.MethodHashes.TryGetValue(kv.Key, out var h) && h == kv.Value) + unchanged.Add(kv.Key); + return unchanged; + } + + /// + /// True when every [CodeReload] method in matches the baseline + /// and none of them is in (methods that must reload anyway — + /// e.g. already overridden on a device that can't unregister). Callers use this to skip a + /// whole compile-and-push. False when no baseline was captured. + /// + public static bool IsFileUpToDate( + string filePath, string sourceCode, string[] preprocessorSymbols = null, + ICollection mustReload = null) + { + if (!s_Entries.TryGetValue(KeyFor(filePath, preprocessorSymbols), out var baseline)) + return false; + var current = sourceCode == null ? null : ComputeEntry(sourceCode, preprocessorSymbols); + if (current == null || current.ContextHash != baseline.ContextHash) + return false; + + foreach (var kv in current.MethodHashes) + { + if (!baseline.MethodHashes.TryGetValue(kv.Key, out var h) || h != kv.Value) + return false; + if (mustReload != null && mustReload.Contains(kv.Key)) + return false; + } + return true; + } + + /// Drop every captured baseline (watch stopped, or about to recapture). + public static void Clear() => s_Entries.Clear(); + + /// + /// Flatten the store to one string so the editor can stash it in SessionState across the + /// play-mode domain reload — the reload wipes these statics while disk keeps the user's + /// edits, so the baseline can't be recaptured from disk at that point. + /// + public static string Serialize() + { + var sb = new StringBuilder(); + foreach (var kv in s_Entries) + { + sb.Append(kv.Key).Append('\u001e').Append(kv.Value.ContextHash.ToString("x", CultureInfo.InvariantCulture)); + foreach (var m in kv.Value.MethodHashes) + sb.Append('\u001e').Append(m.Key).Append('=').Append(m.Value.ToString("x", CultureInfo.InvariantCulture)); + sb.Append('\n'); + } + return sb.ToString(); + } + + /// Replace the store with a snapshot. Unparseable lines are dropped. + public static void Restore(string serialized) + { + s_Entries.Clear(); + if (string.IsNullOrEmpty(serialized)) return; + + foreach (var line in serialized.Split('\n')) + { + if (line.Length == 0) continue; + var fields = line.Split('\u001e'); + if (fields.Length < 2) continue; + if (!ulong.TryParse(fields[1], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var contextHash)) + continue; + + var entry = new Entry { ContextHash = contextHash }; + bool ok = true; + for (int i = 2; i < fields.Length; i++) + { + int eq = fields[i].LastIndexOf('='); + if (eq <= 0 || !ulong.TryParse(fields[i].Substring(eq + 1), + NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var h)) + { + ok = false; + break; + } + entry.MethodHashes[fields[i].Substring(0, eq)] = h; + } + if (ok) + s_Entries[fields[0]] = entry; + } + } + + private static string KeyFor(string filePath, string[] preprocessorSymbols) + { + string path; + try { path = Path.GetFullPath(filePath); } + catch { path = filePath ?? ""; } + var defines = preprocessorSymbols == null ? "" : string.Join(";", preprocessorSymbols); + return path + '\u001f' + defines; + } + + /// + /// Hash the file: one hash per [CodeReload] method name (overload hashes fold together — + /// method ids are name-keyed everywhere else too), and a context hash over every token + /// outside an executable body. Null when no class carries a [CodeReload] method. + /// + private static Entry ComputeEntry(string sourceCode, string[] preprocessorSymbols) + { + SyntaxNode root; + try + { + root = CSharpSyntaxTree.ParseText(sourceCode, + RoslynCompilationService.ProjectParseOptions(preprocessorSymbols)).GetRoot(); + } + catch + { + return null; + } + + var entry = new Entry(); + foreach (var node in root.DescendantNodes()) + { + if (node is not MethodDeclarationSyntax method || + !InPlaceReloadProcessor.HasCodeReloadAttribute(method)) + continue; + var name = method.Identifier.ValueText; + var declHash = HashTokens(method, null); + entry.MethodHashes[name] = entry.MethodHashes.TryGetValue(name, out var prior) + ? MixHash(prior, declHash) + : declHash; + } + if (entry.MethodHashes.Count == 0) + return null; + + entry.ContextHash = HashTokens(root, CollectBodySpans(root)); + return entry; + } + + /// + /// Spans of every executable body in the file: method/ctor/operator bodies, accessor + /// bodies, and expression bodies (incl. expression-bodied properties/indexers). Reloadable + /// bodies are covered per-method; the others bind to compiled code from an override either + /// way, so their edits can't change what an override does and must not poison the context. + /// + private static List CollectBodySpans(SyntaxNode root) + { + var spans = new List(); + foreach (var node in root.DescendantNodes()) + { + switch (node) + { + case BaseMethodDeclarationSyntax m: + if (m.Body != null) spans.Add(m.Body.Span); + if (m.ExpressionBody != null) spans.Add(m.ExpressionBody.Span); + break; + case AccessorDeclarationSyntax a: + if (a.Body != null) spans.Add(a.Body.Span); + if (a.ExpressionBody != null) spans.Add(a.ExpressionBody.Span); + break; + case PropertyDeclarationSyntax p when p.ExpressionBody != null: + spans.Add(p.ExpressionBody.Span); + break; + case IndexerDeclarationSyntax ix when ix.ExpressionBody != null: + spans.Add(ix.ExpressionBody.Span); + break; + } + } + spans.Sort((a, b) => a.Start.CompareTo(b.Start)); + return spans; + } + + // FNV-1a 64 over the token stream. Trivia never enters the hash, so formatting and + // comments can't mark a method changed. A separator byte between tokens keeps ("ab","c") + // and ("a","bc") distinct even though C# tokenization already makes that unlikely. + private const ulong FnvOffset = 14695981039346656037UL; + private const ulong FnvPrime = 1099511628211UL; + + private static ulong HashTokens(SyntaxNode node, List excludedSpans) + { + ulong h = FnvOffset; + int next = 0; // excludedSpans is sorted; tokens come in document order + foreach (var token in node.DescendantTokens()) + { + if (excludedSpans != null) + { + while (next < excludedSpans.Count && excludedSpans[next].End <= token.Span.Start) + next++; + if (next < excludedSpans.Count && excludedSpans[next].Contains(token.Span)) + continue; + } + + h = (h ^ 0xFF) * FnvPrime; + var text = token.Text; + for (int i = 0; i < text.Length; i++) + { + h = (h ^ (byte)text[i]) * FnvPrime; + h = (h ^ (byte)(text[i] >> 8)) * FnvPrime; + } + } + return h; + } + + private static ulong MixHash(ulong a, ulong b) + { + for (int i = 0; i < 8; i++) + a = (a ^ (byte)(b >> (i * 8))) * FnvPrime; + return a; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/CodeReloadBaseline.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/CodeReloadBaseline.cs.meta new file mode 100644 index 0000000..6f4df9c --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/CodeReloadBaseline.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 9844e60b4d0144ffa632f3433a159737 diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/CodeReloadRegistry.cs b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/CodeReloadRegistry.cs new file mode 100644 index 0000000..176dd93 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/CodeReloadRegistry.cs @@ -0,0 +1,673 @@ +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.ExceptionServices; +using Unity.Pipeline.Threading; +using UnityEngine; + +namespace Unity.Pipeline.CodeReload +{ + /// + /// Central registry for managing code reload method and component overrides. + /// Handles runtime method resolution, override registration, and fallback logic. + /// Thread-safe for runtime code reload operations. + /// + /// + /// Deliberately NOT [NoAutoStaticsCleanup]: RegisterReloadableMethod appends without deduplicating, + /// and RuntimePipelineDriver.Awake re-registers on every Play Mode entry, so opting out would + /// accumulate duplicates across FEPM sessions. Let AutoStaticsCleanup reset these statics instead. + /// + public static class CodeReloadRegistry + { + /// + /// Dispatcher used to marshal main-thread-required code-reload overrides to the main thread. + /// Injected by RuntimePipelineDriver (= its server's dispatcher). Null = run on the + /// current thread (no marshaling). + /// + public static Dispatcher Dispatcher { get; set; } + + /// + /// Absolute roots a running Player is allowed to code reload source files from (Assets folder + /// + loaded package locations). Baked into RuntimePipelineBuildInfo at build time (a running + /// Player cannot resolve the project layout) and published here when the runtime server + /// starts, so reload commands can validate incoming file paths. Null until published. + /// + public static IReadOnlyList AllowedReloadRoots { get; set; } + + // Facts established at domain-reload / Play Mode entry that only matter once the user + // actually reloads (target count, receiver state, connected players). Collected here and + // printed as ONE console line on the first override registration ATTEMPT of the session — + // attempt, not success, so a reload against an empty registry still gets the summary next + // to its skip reasons. Statics reset with the domain, so each session collects afresh. + private static readonly List s_FirstReloadNotes = new(); + private static bool s_FirstReloadNotesFlushed; + + /// + /// Record a startup fact for the "first reload this session" summary line. Once that line + /// has been printed, a late note (e.g. a player connecting mid-session) is logged directly. + /// + /// Short clause, no trailing period, e.g. "3 reloadable method(s) registered". + public static void NoteForFirstReload(string note) + { + if (string.IsNullOrEmpty(note)) return; + lock (s_FirstReloadNotes) + { + if (s_FirstReloadNotesFlushed) + { + Debug.Log($"CodeReload: {note}."); + return; + } + s_FirstReloadNotes.Add(note); + } + } + + private static void FlushFirstReloadNotes() + { + string line = null; + lock (s_FirstReloadNotes) + { + if (s_FirstReloadNotesFlushed) return; + s_FirstReloadNotesFlushed = true; + if (s_FirstReloadNotes.Count > 0) + line = "CodeReload: first reload this session — " + string.Join("; ", s_FirstReloadNotes) + "."; + s_FirstReloadNotes.Clear(); + } + if (line != null) + Debug.Log(line); + } + + // Thread-safe collections for runtime code reload switching + private static readonly ConcurrentDictionary m_MethodOverrides = new(); + private static readonly ConcurrentDictionary> m_ReloadableMethods = new(); + private static readonly ConcurrentDictionary m_LoadedCodeReloadTypes = new(); + + /// + /// Raised after a method override is registered or removed (once per method — a + /// multi-method reload fires it several times back to back, so debounce reactions). + /// Lets UI that reflects reloadable code (e.g. a debug panel overlay) rebuild when a + /// compiled method's body is swapped. + /// + /// INTERNAL for now — deliberately held back from the first public API surface; make it + /// public when the introspection surface ships (external consumers poll + /// GetStats().ActiveOverrideCount meanwhile). The raise sites stay: register, unregister + /// (revert), and ClearAllOverrides — the transitions a subscriber needs. + /// + internal static event Action OverridesChanged; + + private static void RaiseOverridesChanged() + { + try + { + OverridesChanged?.Invoke(); + } + catch (Exception ex) + { + Debug.LogError($"CodeReload: OverridesChanged handler threw: {ex}"); + } + } + + /// + /// Register a method as reloadable. Called during discovery phase. + /// + /// The method marked with . + /// The attribute instance (supplies the override id and main-thread requirement). + public static void RegisterReloadableMethod(MethodInfo method, CodeReloadAttribute attribute) + { + var methodId = GetMethodId(method, attribute.Id); + + if (!m_ReloadableMethods.ContainsKey(methodId)) + { + m_ReloadableMethods[methodId] = new List(); + } + + m_ReloadableMethods[methodId].Add(method); + } + + /// + /// Register a code reload method override from compiled code reload assembly. + /// Returns true if the override was registered, false if it was skipped. + /// + /// The override method marked with . + /// The attribute instance (identifies the target method). + /// The type the override method was compiled into. + /// True if the override was registered. + public static bool RegisterMethodOverride(MethodInfo overrideMethod, CodeReloadOverrideMethodAttribute attribute, Type sourceType) + { + return RegisterMethodOverride(overrideMethod, attribute, sourceType, out _); + } + + /// + /// Register a code reload method override from compiled code reload assembly. + /// Returns true if the override was registered, false if it was skipped (target not + /// reloadable or signature mismatch). The out parameter carries a user-facing reason + /// when registration is skipped. + /// + /// The override method marked with . + /// The attribute instance (identifies the target method). + /// The type the override method was compiled into. + /// A user-facing reason when registration is skipped, or null on success. + /// True if the override was registered. + public static bool RegisterMethodOverride(MethodInfo overrideMethod, CodeReloadOverrideMethodAttribute attribute, Type sourceType, out string skipReason) + { + FlushFirstReloadNotes(); + skipReason = null; + var targetMethodId = attribute.TargetMethodId; + + // Validate that target method exists and is reloadable + if (!m_ReloadableMethods.ContainsKey(targetMethodId)) + { + Debug.LogWarning($"CodeReload: Target method '{targetMethodId}' not found or not marked [CodeReload]"); + skipReason = $"target '{targetMethodId}' is not registered as a reloadable [CodeReload] method. " + + "Ensure the component is in the scene and in play mode (RuntimePipelineDriver auto-discovers it)."; + return false; + } + + var originalMethods = m_ReloadableMethods[targetMethodId]; + if (!originalMethods.Any()) + { + Debug.LogWarning($"CodeReload: No original methods registered for '{targetMethodId}'"); + skipReason = $"no original methods registered for '{targetMethodId}'."; + return false; + } + + // Validate signature compatibility (basic check - instance parameter + matching return type) + var originalMethod = originalMethods.First(); + if (!ValidateSignatureCompatibility(originalMethod, overrideMethod)) + { + Debug.LogError($"CodeReload: Signature mismatch for '{targetMethodId}'. Override method must have instance parameter as first argument."); + skipReason = $"signature mismatch for '{targetMethodId}'. The override must be " + + $"'public static {originalMethod.ReturnType.Name} {overrideMethod.Name}" + + $"({originalMethod.DeclaringType?.Name} instance, ...)'."; + return false; + } + + var methodOverride = new MethodOverride + { + TargetMethodId = targetMethodId, + OverrideMethod = overrideMethod, + SourceType = sourceType, + RequireMainThread = GetMainThreadRequirement(originalMethod), + Description = attribute.Description + }; + + m_MethodOverrides[targetMethodId] = methodOverride; + RaiseOverridesChanged(); + return true; + } + + /// + /// Register an IL2CPP-safe override that dispatches through + /// (a IlInterpreter interpreter invoke) instead of a loaded . The target + /// must already be registered reloadable (same precondition as ). + /// + internal static bool RegisterInterpreterMethodOverride( + string targetMethodId, Func interpreterInvoke, out string skipReason) + { + FlushFirstReloadNotes(); + skipReason = null; + + if (!m_ReloadableMethods.TryGetValue(targetMethodId, out var originalMethods) || originalMethods.Count == 0) + { + skipReason = $"target '{targetMethodId}' is not registered as a reloadable [CodeReload] method. " + + "Ensure the component is in the scene and in play mode (RuntimePipelineDriver auto-discovers it)."; + return false; + } + + m_MethodOverrides[targetMethodId] = new MethodOverride + { + TargetMethodId = targetMethodId, + InterpreterInvoke = interpreterInvoke, + RequireMainThread = GetMainThreadRequirement(originalMethods.First()), + }; + + Debug.Log($"CodeReload: Registered interpreter override for '{targetMethodId}'"); + RaiseOverridesChanged(); + return true; + } + + /// + /// Remove one active override so the woven prologue falls through to the original compiled + /// body again. Used when a reloaded file's method matches the compiled baseline again (the + /// edit was reverted) — keeping the override would leave a correct but slower interpreter + /// dispatch in place. Returns false when no override was registered for the id. + /// + internal static bool UnregisterMethodOverride(string targetMethodId) + { + if (!m_MethodOverrides.TryRemove(targetMethodId, out _)) + return false; + Debug.Log($"CodeReload: Removed override for '{targetMethodId}' — original compiled body is active again"); + RaiseOverridesChanged(); + return true; + } + + /// + /// After a reload binds, invoke every [OnCodeReload] method on all live instances of the + /// types that own the given reloaded methods. Lets a component re-init state when its code is + /// swapped. Parameterless instance methods only; exceptions are logged, not propagated. + /// + internal static void InvokeReloadCallbacks(IEnumerable reloadedTargetMethodIds) + { + if (reloadedTargetMethodIds == null) return; + + var types = new HashSet(); + foreach (var id in reloadedTargetMethodIds) + { + if (m_ReloadableMethods.TryGetValue(id, out var methods) && methods.Count > 0 + && methods[0].DeclaringType != null) + { + types.Add(methods[0].DeclaringType); + } + } + + foreach (var type in types) + InvokeReloadCallbacksOnType(type); + } + + private static void InvokeReloadCallbacksOnType(Type type) + { + var callbacks = type + .GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) + .Where(m => m.GetParameters().Length == 0 && m.GetCustomAttribute() != null) + .ToList(); + if (callbacks.Count == 0) return; + + if (!typeof(UnityEngine.Object).IsAssignableFrom(type)) + { + Debug.LogWarning($"CodeReload: [OnCodeReload] on '{type.Name}' ignored — only " + + "UnityEngine.Object-derived types are supported (instances are found via FindObjectsByType)."); + return; + } + +#if UNITY_6000_5_OR_NEWER + var instances = UnityEngine.Object.FindObjectsByType(type); +#else + var instances = UnityEngine.Object.FindObjectsByType(type, FindObjectsSortMode.None); +#endif + foreach (var instance in instances) + { + foreach (var cb in callbacks) + { + try + { + cb.Invoke(instance, null); + } + catch (Exception ex) + { + Debug.LogError($"CodeReload: [OnCodeReload] {type.Name}.{cb.Name} threw: {ex.Message}"); + } + } + } + } + + /// True when at least one [CodeReload] target has been registered this session. + internal static bool HasReloadableMethods => m_ReloadableMethods.Count > 0; + + /// + /// Resolve the runtime that declares a reloadable target method, so an + /// interpreter host binding can be built for it. Returns false if not registered. + /// + internal static bool TryGetReloadableDeclaringType(string targetMethodId, out Type declaringType) + { + declaringType = null; + if (m_ReloadableMethods.TryGetValue(targetMethodId, out var methods) && methods.Count > 0) + { + declaringType = methods[0].DeclaringType; + return declaringType != null; + } + return false; + } + + /// + /// Attempt to invoke code reload override if available, otherwise invoke original method. + /// Returns true if code reload override was invoked, false if original method should be called. + /// + /// The instance's type. + /// Method identifier, "TypeName.MethodName". + /// The instance to invoke the override on. + /// The original call's arguments, boxed. + /// True if a code reload override was invoked. + public static bool TryInvokeCodeReload(string methodId, T instance, object[] parameters = null) + { + return TryInvokeCodeReload(methodId, (object)instance, parameters); + } + + /// + /// Cheap, allocation-free check for an active override. The woven prologue calls this + /// before building the boxed argument array, so a woven method with no active override + /// allocates nothing per call. + /// + /// Method identifier, "TypeName.MethodName". + /// True if an override is currently registered for . + public static bool HasOverride(string methodId) => m_MethodOverrides.ContainsKey(methodId); + + /// + /// Non-generic dispatch entry point. This is the method woven into [CodeReload] + /// methods at compile time (a non-generic signature keeps the injected IL simple). + /// Returns true if a code reload override was invoked, false if the original body should run. + /// + /// Method identifier, "TypeName.MethodName". + /// The instance to invoke the override on. + /// The original call's arguments, boxed. + /// True if a code reload override was invoked. + public static bool TryInvokeCodeReload(string methodId, object instance, object[] parameters = null) + => TryInvokeCodeReloadResult(methodId, instance, parameters, out _); + + /// + /// Called by the woven prologue when an override returned null for a method whose return + /// type is a value type — unboxing null would throw an opaque NullReferenceException at + /// the call site. Public only for woven code; not meant to be called by hand. + /// + /// Method identifier, "TypeName.MethodName", named in the thrown message. + public static void ThrowOverrideReturnedNull(string methodId) + { + throw new InvalidOperationException( + $"CodeReload: the override for '{methodId}' returned null, but the method returns " + + "a value type, so there is no value to unbox. Fix the override to return a value, " + + "or revert the reload."); + } + + /// + /// Value-returning dispatch: woven into value-returning [CodeReload] methods. Like + /// but also hands back the + /// override's (boxed) return value in . Returns true if an override + /// ran (and the woven prologue should return ), false if the + /// original body should run. + /// + /// Method identifier, "TypeName.MethodName". + /// The instance to invoke the override on. + /// The original call's arguments, boxed. + /// The override's (boxed) return value, if one ran. + /// True if a code reload override was invoked. + public static bool TryInvokeCodeReloadResult(string methodId, object instance, object[] parameters, out object result) + { + result = null; + if (!m_MethodOverrides.TryGetValue(methodId, out var methodOverride)) + { + return false; // No code reload override available + } + + CodeReloadActivity.CountOverrideCall(); // feeds the overlay's calls/s rate + + try + { + result = InvokeOverrideMarshalled(methodOverride, instance, parameters); + return true; + } + catch (TargetInvocationException ex) when (ex.InnerException != null) + { + // Exception from mono backend - rethrow for cases like imgui ExitGui + ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); + throw; // unreachable + } + catch (IlInterpreter.ScriptRuntimeException ex) when (ex.InnerException != null) + { + // Exception from IlInterpreter backend - rethrow for cases like imgui ExitGui. + // The inner exception alone has no script location; log the interpreter's + // message (which carries "at line N (file)") first so the failure is traceable. + if (!(ex.InnerException is ExitGUIException)) + Debug.LogError($"CodeReload: override '{methodId}' threw {ex.Message}"); + ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); + throw; // unreachable + } + catch (Exception ex) + { + // Invocation infrastructure failed (interpreter-detected error, reflection arg + // marshaling): log and fall back to the original body. + Debug.LogError($"CodeReload: Error invoking override for '{methodId}': " + + $"{ex.GetType().Name}: {ex.Message}"); + Debug.LogError($"CodeReload: Stack trace: {ex.StackTrace}"); + result = null; + return false; // Fall back to original method + } + } + + /// + /// Run the override, marshalling to the main thread when required, and return its (boxed) + /// result. The common case is already on the main thread: invoke directly with no per-call + /// closure allocation; only the rare cross-thread marshal pays for a closure. + /// + private static object InvokeOverrideMarshalled(MethodOverride methodOverride, object instance, object[] parameters) + { + if (methodOverride.RequireMainThread && Dispatcher != null && !Dispatcher.IsMainThread()) + { + object marshalled = null; + var mo = methodOverride; + Dispatcher.Invoke(() => marshalled = InvokeOverride(mo, instance, parameters)); + return marshalled; + } + return InvokeOverride(methodOverride, instance, parameters); + } + + /// + /// Invoke the override: through the IlInterpreter interpreter (IL2CPP-safe; the delegate marshals + /// args itself, so no array is built here) or via reflection on the loaded MethodInfo (which + /// needs an instance-prepended argument array). Returns the (boxed) result, null for void. + /// + private static object InvokeOverride(MethodOverride methodOverride, object instance, object[] parameters) + { + if (methodOverride.InterpreterInvoke != null) + return methodOverride.InterpreterInvoke(instance, parameters); + + var invokeParams = new object[(parameters?.Length ?? 0) + 1]; + invokeParams[0] = instance; + if (parameters != null && parameters.Length > 0) + Array.Copy(parameters, 0, invokeParams, 1, parameters.Length); + return methodOverride.OverrideMethod.Invoke(null, invokeParams); + } + + /// + /// Register all methods in a type that have the [CodeReload] attribute. + /// Uses reflection to discover and register them as reload targets. + /// + /// The type to scan for [CodeReload] methods. + public static void RegisterReloadableType(System.Type type) + { + if (type == null) + { + Debug.LogWarning("CodeReload: Cannot register null type"); + return; + } + + int registeredCount = 0; + + // Get all instance methods (public and non-public) + var instanceMethods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + foreach (var method in instanceMethods) + { + var codeReloadAttr = method.GetCustomAttribute(); + if (codeReloadAttr != null) + { + RegisterReloadableMethod(method, codeReloadAttr); + registeredCount++; + } + } + + // Get all static methods (public and non-public) + var staticMethods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); + foreach (var method in staticMethods) + { + var codeReloadAttr = method.GetCustomAttribute(); + if (codeReloadAttr != null) + { + RegisterReloadableMethod(method, codeReloadAttr); + registeredCount++; + } + } + + if (registeredCount > 0) + { + Debug.Log($"CodeReload: Registered {registeredCount} reloadable methods from type {type.Name}"); + } + else + { + Debug.Log($"CodeReload: No methods with [CodeReload] attribute found in type {type.Name}"); + } + } + + /// + /// Register a type from loaded code reload assembly for discovery scanning. + /// + /// The loaded code-reload assembly's type. + /// Identifier of the compiled code-reload assembly the type came from. + public static void RegisterCodeReloadType(Type type, string assemblyId) + { + var typeKey = $"{assemblyId}:{type.FullName}"; + m_LoadedCodeReloadTypes[typeKey] = type; + } + + /// + /// Clear all code reload overrides. Used by cleanup_codereload command. + /// + public static void ClearAllOverrides() + { + var overrideCount = m_MethodOverrides.Count; + var typeCount = m_LoadedCodeReloadTypes.Count; + + m_MethodOverrides.Clear(); + m_LoadedCodeReloadTypes.Clear(); + if (overrideCount > 0) + RaiseOverridesChanged(); + } + + /// + /// Clear all registry state including reloadable methods. + /// FOR TESTING ONLY - this should not be called in production code. + /// + public static void ClearAllForTesting() + { + var overrideCount = m_MethodOverrides.Count; + var typeCount = m_LoadedCodeReloadTypes.Count; + var reloadableCount = m_ReloadableMethods.Sum(kvp => kvp.Value.Count); + + m_MethodOverrides.Clear(); + m_LoadedCodeReloadTypes.Clear(); + m_ReloadableMethods.Clear(); + } + + /// + /// Get statistics about current code reload state. + /// + /// Current reloadable/override/loaded-type counts. + public static CodeReloadStats GetStats() + { + return new CodeReloadStats + { + ReloadableMethodCount = m_ReloadableMethods.Sum(kvp => kvp.Value.Count), + ActiveOverrideCount = m_MethodOverrides.Count, + LoadedTypeCount = m_LoadedCodeReloadTypes.Count, + ReloadableMethodIds = m_ReloadableMethods.Keys.ToList(), + ActiveOverrideIds = m_MethodOverrides.Keys.ToList() + }; + } + + /// + /// Generate method ID from MethodInfo and optional custom ID. + /// Format: TypeName.MethodName or custom ID if provided. + /// + private static string GetMethodId(MethodInfo method, string customId = null) + { + if (!string.IsNullOrEmpty(customId)) + { + return customId; + } + + return $"{method.DeclaringType?.Name}.{method.Name}"; + } + + /// + /// Validate that code reload method signature is compatible with original method. + /// Code reload method must have instance parameter as first argument. + /// + private static bool ValidateSignatureCompatibility(MethodInfo originalMethod, MethodInfo overrideMethod) + { + var originalParams = originalMethod.GetParameters(); + var overrideParams = overrideMethod.GetParameters(); + + // Code reload method must have at least one parameter (the instance) + if (overrideParams.Length == 0) + { + return false; + } + + // First parameter must be compatible with declaring type of original method + var firstParam = overrideParams[0]; + if (!originalMethod.DeclaringType.IsAssignableFrom(firstParam.ParameterType)) + { + return false; + } + + // Remaining parameters must match original method parameters + if (overrideParams.Length - 1 != originalParams.Length) + { + return false; + } + + for (int i = 0; i < originalParams.Length; i++) + { + if (overrideParams[i + 1].ParameterType != originalParams[i].ParameterType) + { + return false; + } + } + + // Return types must match + return originalMethod.ReturnType == overrideMethod.ReturnType; + } + + /// + /// Determine if original method requires main thread execution. + /// + private static bool GetMainThreadRequirement(MethodInfo originalMethod) + { + // Honour the [CodeReload] attribute's main thread requirement + var codeReloadAttr = originalMethod.GetCustomAttribute(); + if (codeReloadAttr != null) + { + return codeReloadAttr.RequireMainThread; + } + + // Default to main thread requirement for safety + return true; + } + + /// + /// Information about a registered method override. + /// + private class MethodOverride + { + public string TargetMethodId { get; set; } + public MethodInfo OverrideMethod { get; set; } + + /// + /// IL2CPP-safe dispatch: when set, the override runs through this delegate (a IlInterpreter + /// interpreter invoke) instead of reflection. Receives the + /// target instance and the original call arguments; returns the method's (boxed) result, + /// or null for a void method. + /// + public Func InterpreterInvoke { get; set; } + + public Type SourceType { get; set; } + public bool RequireMainThread { get; set; } + public string Description { get; set; } + } + } + + /// + /// Statistics about current code reload registry state. + /// + public class CodeReloadStats + { + /// Number of methods registered as reloadable. + public int ReloadableMethodCount { get; set; } + /// Number of active method overrides. + public int ActiveOverrideCount { get; set; } + /// Number of code-reload assembly types currently loaded. + public int LoadedTypeCount { get; set; } + /// Method ids registered as reloadable. + public List ReloadableMethodIds { get; set; } = new(); + /// Method ids with an active override. + public List ActiveOverrideIds { get; set; } = new(); + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/CodeReloadRegistry.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/CodeReloadRegistry.cs.meta new file mode 100644 index 0000000..bcabbee --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/CodeReloadRegistry.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 23cd8d0c782f1974e8a3b4095a178092 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/InPlaceReloadProcessor.cs b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/InPlaceReloadProcessor.cs new file mode 100644 index 0000000..275ad5e --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/InPlaceReloadProcessor.cs @@ -0,0 +1,703 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using UnityPipeline.Microsoft.CodeAnalysis; +using UnityPipeline.Microsoft.CodeAnalysis.CSharp; +using UnityPipeline.Microsoft.CodeAnalysis.CSharp.Syntax; +using Unity.Pipeline.Compilation; +using UnityEngine; + +namespace Unity.Pipeline.CodeReload +{ + /// + /// Main orchestrator for in-place code reload processing. + /// Handles the complete pipeline: source parsing -> transformation -> compilation. + /// + static class InPlaceReloadProcessor + { + /// + /// Process a source file for in-place code reload. + /// Extracts [CodeReload] methods, transforms to static overrides, and compiles. + /// DEADLOCK FIX: Detects main thread and uses synchronous processing when needed. + /// + /// Path to source file containing [CodeReload] methods + /// Optional directory to save compiled assembly + /// Emit debug symbols mapped to the original source so breakpoints bind. + /// Compilation result with success/failure and diagnostic information + public static Task ProcessSourceFileAsync(string sourceFilePath, string assemblyDir = null, bool pdb = false, bool useInterpreter = false) + { + // Runs synchronously on the calling (main) thread; returns a completed Task. + return Task.FromResult(ProcessSourceFileOnMainThread(sourceFilePath, assemblyDir, pdb, useInterpreter)); + } + + /// + /// Process source file on main thread synchronously to avoid deadlocks. + /// + /// Path to source file containing [CodeReload] methods. + /// Optional directory to save compiled assembly. + /// Emit debug symbols mapped to the original source so breakpoints bind. + /// Route the override through the interpreter backend instead of Assembly.Load. + /// Compilation result with success/failure and diagnostic information. + public static InPlaceReloadResult ProcessSourceFileOnMainThread(string sourceFilePath, string assemblyDir = null, bool pdb = false, bool useInterpreter = false) + { + var result = new InPlaceReloadResult + { + SourceFilePath = sourceFilePath, + Success = false + }; + + try + { + Debug.Log($"CodeReload: Processing source file synchronously on main thread: {sourceFilePath}"); + + // The interpreter backend needs #line directives when source-line errors are + // enabled: its runtime errors resolve locations from the embedded PDB, which are + // only meaningful mapped to the user's file. + var lineInfo = useInterpreter && CodeReloadCompiler.EmitSourceLineInfo; + var prep = PrepareOverride(sourceFilePath, pdb || lineInfo, enforcePublicAccess: !useInterpreter); + if (!prep.Success) + { + result.ErrorMessage = prep.Error; + result.CompilationDiagnostics = prep.Diagnostics; + return result; + } + + result.OriginalTypeName = prep.TypeName; + result.ExtractedMethods = prep.MethodNames; + result.UpToDateMethods = prep.UpToDateMethods; + result.TransformedCode = prep.TransformedCode; + + // A method that matches the baseline again (the edit was undone) may still carry an + // override from an earlier reload — drop it so the compiled body runs at full speed. + foreach (var name in prep.UpToDateMethods) + { + var id = $"{prep.TypeName}.{name}"; + if (CodeReloadRegistry.UnregisterMethodOverride(id)) + result.RevertedMethods.Add(id); + } + + if (prep.MethodNames.Count == 0) + { + result.Success = true; + result.CompilationDiagnostics = prep.Diagnostics; + Debug.Log($"CodeReload: {sourceFilePath} is up to date — all " + + $"{prep.UpToDateMethods.Count} [CodeReload] method(s) match the compiled baseline" + + (result.RevertedMethods.Count > 0 + ? $"; removed {result.RevertedMethods.Count} stale override(s)" : "") + "."); + return result; + } + + var compilationResult = CompileTransformedCode(prep, assemblyDir, pdb, sourceFilePath, useInterpreter); + + result.Success = compilationResult.IsSuccess; + result.AssemblyName = compilationResult.AssemblyName; + result.RegisteredMethods = compilationResult.RegisteredMethods; + result.CompilationDiagnostics = prep.Diagnostics.Concat(compilationResult.Diagnostics).ToList(); + + if (result.Success) + { + Debug.Log($"CodeReload: In-place reload successful for {sourceFilePath} - {result.RegisteredMethods.Count} methods registered" + + (result.UpToDateMethods.Count > 0 ? $" ({result.UpToDateMethods.Count} up to date, left compiled)" : "")); + } + else + { + result.ErrorMessage = compilationResult.ErrorDetails ?? "Compilation failed"; + Debug.LogError($"CodeReload: In-place reload compilation failed: {result.ErrorMessage}"); + } + + return result; + } + catch (Exception ex) + { + Debug.LogError($"CodeReload: Error processing source file {sourceFilePath}: {ex.Message}\n{ex.StackTrace}"); + + result.ErrorMessage = $"Processing error: {ex.Message}"; + return result; + } + } + + /// + /// What hands back: the extracted type and surviving methods, + /// the transformed source (null when everything was up to date), and the diagnostics + /// gathered on the way. false means a hard failure with + /// set. + /// + private sealed class OverridePreparation + { + public bool Success; + public string Error; + public string TypeName; + public List MethodNames; + public List UpToDateMethods = new List(); + public string TransformedCode; + public List Diagnostics = new List(); + } + + /// + /// Shared prefix for in-place reload and push-to-player: read the file, extract [CodeReload] + /// methods, drop the ones still matching the captured (they + /// run correct AND faster compiled — + /// reports them, and keeps named ones in anyway), reject + /// non-public member access when the compiled backend will run the override + /// (), and transform bodies into a static override + /// class. When every method is up to date, succeeds with an empty + /// and a null + /// — nothing to compile. + /// + private static OverridePreparation PrepareOverride( + string sourceFilePath, bool pdb, bool enforcePublicAccess, + string[] preprocessorSymbols = null, ICollection forceInclude = null, + bool useBaseline = true) + { + var prep = new OverridePreparation(); + + var sourceCode = ReadSourceFile(sourceFilePath); + if (string.IsNullOrEmpty(sourceCode)) + { + prep.Error = $"Could not read source file: {sourceFilePath}"; + return prep; + } + + var extraction = ExtractCodeReloadableMethods(sourceCode, preprocessorSymbols); + // Each skip entry carries its own reason (return-type gate, nested type, …). + foreach (var skipped in extraction.SkippedMethods) + prep.Diagnostics.Add($"[CodeReload] {skipped} was skipped."); + + if (!extraction.HasMethods) + { + prep.Error = extraction.SkippedMethods.Count > 0 + ? $"No reloadable [CodeReload] methods in {sourceFilePath}. Skipped: " + + $"{string.Join(", ", extraction.SkippedMethods)}." + : $"No [CodeReload] methods found in {sourceFilePath}"; + return prep; + } + + // Skip methods whose declarations still match the captured baseline: their compiled + // bodies are already what the source says, and the compiled body is strictly faster + // than any override (the interpreter backend pays per call). No baseline captured + // (returns null) = no filtering, the pre-baseline behavior. + var unchanged = useBaseline + ? CodeReloadBaseline.GetUnchangedMethods(sourceFilePath, sourceCode, preprocessorSymbols) + : null; + if (unchanged != null && unchanged.Count > 0) + { + foreach (var name in extraction.Methods.Keys.ToList()) + { + if (!unchanged.Contains(name)) continue; + if (forceInclude != null && forceInclude.Contains(name)) continue; + extraction.Methods.Remove(name); + extraction.MethodSignatures.Remove(name); + prep.UpToDateMethods.Add(name); + } + + if (extraction.Methods.Count == 0) + { + prep.TypeName = extraction.TypeName; + prep.MethodNames = new List(); + prep.Success = true; + return prep; + } + } + + // Build one compilation + semantic model for the transform, so Roslyn's metadata bind + // is paid once per reload (shared with the string TransformMethodBodies overload). + var model = SourceCodeTransformer.BuildSemanticModel( + sourceCode, extraction.TypeName, out var classDecl, preprocessorSymbols); + if (classDecl == null) + { + prep.Error = $"Could not find class '{extraction.TypeName}' in source."; + return prep; + } + + // Only the interpreter backend compiles with relaxed accessibility (see + // RoslynCompilationService.AllowNonPublicMemberAccess) and reaches non-public members at + // runtime, via reflection. The Assembly.Load backend keeps standard access checks — a + // non-public access would only surface later as a raw CS0122 — so reject it up front + // with an actionable message. + if (enforcePublicAccess) + { + var validation = AccessibilityValidator.ValidatePublicAccess( + model, classDecl, extraction.Methods, extraction.TypeName); + if (!validation.IsValid) + { + prep.Error = validation.GetFormattedErrorMessage(); + return prep; + } + } + + // enforcePublicAccess doubles as the backend discriminator (true == Assembly.Load, see + // the callers): only the interpreter needs interpolation lowered to string.Format — + // the compiled backend keeps interpolations native. + prep.TransformedCode = SourceCodeTransformer.TransformMethodBodies( + model, classDecl, extraction.Methods, extraction.TypeName, extraction.MethodSignatures, + emitLineDirectives: pdb, originalFilePath: sourceFilePath, + rewriteInterpolations: !enforcePublicAccess); + + prep.TypeName = extraction.TypeName; + prep.MethodNames = extraction.Methods.Keys.ToList(); + prep.Success = true; + return prep; + } + + /// + /// Compile a source file's [CodeReload] override(s) to raw assembly IL bytes without + /// registering them locally — for pushing to a player that runs them through the + /// interpreter. Editor-side only (needs Roslyn). false + /// bypasses the filter — the caller can't vouch that the + /// target player was built from the baselined sources. + /// + internal static PushCompileResult CompileOverrideForPush(string sourceFilePath, string[] preprocessorSymbols = null, + ICollection forceInclude = null, bool useBaseline = true) + { + var r = new PushCompileResult(); + try + { + // When source-line errors are enabled, #line directives map each body to the + // original file so the embedded PDB's sequence points — used by the player-side + // interpreter for runtime error messages — carry the user's real line numbers. + // enforcePublicAccess: false — pushed overrides run through the on-device + // interpreter, which reaches non-public members by reflection. + var prep = PrepareOverride(sourceFilePath, pdb: CodeReloadCompiler.EmitSourceLineInfo, + enforcePublicAccess: false, preprocessorSymbols, forceInclude, useBaseline); + if (!prep.Success) + { + r.Error = prep.Error; + r.Diagnostics = prep.Diagnostics; + return r; + } + + r.UpToDateMethods = prep.UpToDateMethods; + if (prep.MethodNames.Count == 0) + { + // Everything matches the baseline — a push would only replace compiled bodies + // with slower interpreted ones on the device. + r.Success = true; + r.TypeName = prep.TypeName; + r.Diagnostics = prep.Diagnostics; + return r; + } + + var tempName = $"PushReload_{prep.TypeName}_{DateTime.Now:yyyyMMdd_HHmmss}"; + if (!CodeReloadCompiler.TryCompileOverrideBytes(prep.TransformedCode, tempName, out var il, out var compileDiagnostics, documentPath: sourceFilePath, preprocessorSymbols: preprocessorSymbols)) + { + r.Error = "Compilation failed"; + r.Diagnostics = prep.Diagnostics.Concat(compileDiagnostics).ToList(); + return r; + } + + r.Success = true; + r.TypeName = prep.TypeName; + r.MethodNames = prep.MethodNames; + r.IlBytes = il; + r.Diagnostics = prep.Diagnostics.Concat(compileDiagnostics).ToList(); + return r; + } + catch (Exception ex) + { + r.Error = $"Push compile error: {ex.Message}"; + return r; + } + } + + /// + /// Check if a source file contains [CodeReload] methods. + /// Simple synchronous check to avoid async deadlocks in tests. + /// + /// Path to source file to check + /// True if file contains [CodeReload] methods + public static Task ContainsCodeReloadableMethodsAsync(string sourceFilePath) + { + try + { + if (!File.Exists(sourceFilePath)) + { + return Task.FromResult(false); + } + + // Use synchronous read for simple attribute check to avoid deadlocks + var sourceCode = File.ReadAllText(sourceFilePath); + if (string.IsNullOrEmpty(sourceCode)) + { + return Task.FromResult(false); + } + + // Quick check for the [CodeReload] attribute. Prefix match (no closing bracket) so + // combined attribute lists like [CodeReload, DebugPanel("x")] still pass. + var result = sourceCode.Contains("[CodeReload"); + return Task.FromResult(result); + } + catch (Exception ex) + { + Debug.LogError($"CodeReload: Error checking for [CodeReload] methods in {sourceFilePath}: {ex.Message}"); + return Task.FromResult(false); + } + } + + /// + /// Read source file content synchronously (for main thread). + /// + private static string ReadSourceFile(string filePath) + { + try + { + if (!File.Exists(filePath)) + { + Debug.LogError($"CodeReload: Source file not found: {filePath}"); + return null; + } + + return File.ReadAllText(filePath); + } + catch (Exception ex) + { + Debug.LogError($"CodeReload: Error reading source file {filePath}: {ex.Message}"); + return null; + } + } + + /// + /// Extract [CodeReload] methods from source code. + /// + private static CodeReloadableExtractionResult ExtractCodeReloadableMethods( + string sourceCode, string[] preprocessorSymbols = null) + { + var result = new CodeReloadableExtractionResult(); + + try + { + var syntaxTree = CSharpSyntaxTree.ParseText(sourceCode, + RoslynCompilationService.ProjectParseOptions(preprocessorSymbols)); + var root = syntaxTree.GetRoot(); + + // Find the class containing [CodeReload] methods. + var classDeclaration = root.DescendantNodes() + .OfType() + .FirstOrDefault(c => c.DescendantNodes().OfType().Any(HasCodeReloadAttribute)); + + if (classDeclaration == null) + { + return result; + } + + result.TypeName = classDeclaration.Identifier.ValueText; + + // The transform lifts bodies into ONE override class for the top-level type chosen + // above. Tagged methods anywhere else in the file — in a NESTED type (which the + // weaver still weaves: Cecil's GetTypes() is recursive) or in a sibling top-level + // type — would otherwise be dropped without a word, leaving a woven prologue that + // never finds an override. Surface each one loudly; when nothing else is + // reloadable, these become the reload's error. + foreach (var method in root.DescendantNodes() + .OfType().Where(HasCodeReloadAttribute)) + { + var owner = method.Ancestors().OfType().FirstOrDefault(); + if (owner == null || owner == classDeclaration) + continue; + var ownerChain = string.Join(".", method.Ancestors() + .OfType().Reverse().Select(t => t.Identifier.ValueText)); + result.SkippedMethods.Add(owner.Parent is TypeDeclarationSyntax + ? $"'{method.Identifier.ValueText}' (declared in nested type '{ownerChain}' — " + + "code reload only supports methods declared directly in a top-level class)" + : $"'{method.Identifier.ValueText}' (declared in '{ownerChain}' — only the first " + + $"type with [CodeReload] methods, '{result.TypeName}', is reloaded per file; split the file)"); + } + + var codeReloadableMethods = classDeclaration.Members + .OfType() + .Where(HasCodeReloadAttribute); + + foreach (var method in codeReloadableMethods) + { + var methodName = method.Identifier.ValueText; + + // Tagged methods must pass the same gate the weaver applies (void or + // IEnumerator returns; instance or static). The weaver never weaves a + // dispatch prologue into the others, so their override would register and + // then never run — reload would report success while silently no-opping. + if (!IsMethodLevelSupported(method, out var skipReason)) + { + result.SkippedMethods.Add($"'{methodName}' ({skipReason})"); + continue; + } + var methodBody = ExtractMethodBody(method); + var signature = ExtractMethodSignature(method); + + if (methodBody != null) + { + result.Methods[methodName] = methodBody; + result.MethodSignatures[methodName] = signature; + } + } + + Debug.Log($"CodeReload: Extracted {result.Methods.Count} [CodeReload] methods from class {result.TypeName}"); + return result; + } + catch (Exception ex) + { + Debug.LogError($"CodeReload: Error extracting [CodeReload] methods: {ex.Message}"); + return result; + } + } + + /// + /// Check if method has [CodeReload] attribute. The unqualified name must match exactly: a + /// suffix match also catches [OnCodeReload] — the post-reload callback, not a reload target — + /// and pushing that name makes the player-side registry lookup fail for the whole file. + /// Internal so hashes exactly the methods extraction picks. + /// + internal static bool HasCodeReloadAttribute(MethodDeclarationSyntax method) + { + return method.AttributeLists + .SelectMany(al => al.Attributes) + .Any(a => UnqualifiedAttributeName(a) == "CodeReload"); + } + + /// + /// Attribute name as the source wrote it, minus any namespace qualifier and the optional + /// "Attribute" suffix — [Foo.BarAttribute] and [Bar] both yield "Bar". + /// + private static string UnqualifiedAttributeName(AttributeSyntax attr) + { + var name = attr.Name.ToString(); + var lastDot = name.LastIndexOf('.'); + if (lastDot >= 0) + name = name.Substring(lastDot + 1); + if (name.EndsWith("Attribute")) + name = name.Substring(0, name.Length - "Attribute".Length); + return name; + } + + /// + /// Gate for explicitly-tagged [CodeReload] methods, mirroring the skips the weaver applies + /// (CodeReloadInPlaceILPostProcessor.Process): unsupported return types get no dispatch + /// prologue, so extracting them would produce an override that never runs. Instance and + /// STATIC methods both weave (a static dispatches with a null instance). Coroutines + /// (System.Collections.IEnumerator) are supported: the weaver routes them through the + /// result dispatch, and the override's iterator — compiled or interpreted — is what + /// StartCoroutine drives. + /// + private static bool IsMethodLevelSupported(MethodDeclarationSyntax method, out string reason) + { + var returnType = method.ReturnType.ToString(); + if (returnType != "void" && + returnType is not ("IEnumerator" or "System.Collections.IEnumerator")) + { + reason = $"returns {returnType} — void methods and IEnumerator coroutines only"; + return false; + } + + reason = null; + return true; + } + + /// + /// Extract method body content (excluding braces). + /// null when the method has no block body at all (expression-bodied, abstract). + /// + private static string ExtractMethodBody(MethodDeclarationSyntax method) + { + if (method.Body == null) + return null; + + var bodyText = method.Body.ToString().Trim(); + // Remove outer braces + if (bodyText.StartsWith("{") && bodyText.EndsWith("}")) + { + bodyText = bodyText.Substring(1, bodyText.Length - 2).Trim(); + } + return bodyText; + } + + /// + /// Extract method signature information. + /// + private static MethodSignatureInfo ExtractMethodSignature(MethodDeclarationSyntax method) + { + var signature = new MethodSignatureInfo + { + ReturnType = method.ReturnType.ToString() + }; + + foreach (var parameter in method.ParameterList.Parameters) + { + var paramInfo = new ParameterInfo + { + Type = parameter.Type?.ToString() ?? "object", + Name = parameter.Identifier.ValueText, + HasDefaultValue = parameter.Default != null, + DefaultValue = parameter.Default?.Value?.ToString() + }; + + signature.Parameters.Add(paramInfo); + } + + return signature; + } + + /// + /// Compile transformed code synchronously (for main thread). + /// + private static CodeReloadCompileResult CompileTransformedCode( + OverridePreparation prep, + string assemblyDir, + bool emitPdb, + string documentPath, + bool useInterpreter) + { + try + { + // Generate a temporary file name for the transformed code + var tempFileName = $"InPlace_{prep.TypeName}_{DateTime.Now:yyyyMMdd_HHmmss}"; + + return CodeReloadCompiler.CompileSourceCodeOnMainThread( + prep.TransformedCode, + tempFileName, + assemblyDir, + emitPdb, + documentPath, + useInterpreter + ? new InterpreterOverrideSet + { + TypeName = prep.TypeName, + MethodNames = prep.MethodNames + } + : null); + } + catch (Exception ex) + { + Debug.LogError($"CodeReload: Error compiling transformed code for {prep.TypeName}: {ex.Message}"); + + return CodeReloadCompileResult.Failure( + "Compilation Error", + ex.Message, + 0, + new List { ex.ToString() }); + } + } + + /// + /// Result of extracting [CodeReload] methods from source code. + /// + private class CodeReloadableExtractionResult + { + /// + /// Name of the class containing [CodeReload] methods. + /// + public string TypeName { get; set; } + + /// + /// Dictionary of method names to their extracted body code. + /// + public Dictionary Methods { get; set; } = new Dictionary(); + + /// + /// Dictionary of method names to their signature information. + /// + public Dictionary MethodSignatures { get; set; } = new Dictionary(); + + /// + /// Whether any [CodeReload] methods were found. + /// + public bool HasMethods => Methods.Count > 0; + + /// + /// Explicitly-tagged methods that were rejected with the reason ("'Total' (returns + /// int — void methods and IEnumerator coroutines only)"), so the caller can report + /// them instead of failing opaquely. + /// + public List SkippedMethods { get; } = new List(); + } + } + + /// + /// Result of in-place code reload processing. + /// + class InPlaceReloadResult + { + /// + /// Path to the source file that was processed. + /// + public string SourceFilePath { get; set; } + + /// + /// Whether the processing was successful. + /// + public bool Success { get; set; } + + /// + /// Name of the original type containing [CodeReload] methods. + /// + public string OriginalTypeName { get; set; } + + /// + /// List of method names that were extracted and processed. + /// + public List ExtractedMethods { get; set; } = new List(); + + /// + /// Generated transformed code for code reload assembly. + /// + public string TransformedCode { get; set; } + + /// + /// Name of the compiled assembly (if successful). + /// + public string AssemblyName { get; set; } + + /// + /// List of registered method IDs (if successful). + /// + public List RegisteredMethods { get; set; } = new List(); + + /// + /// [CodeReload] method names skipped because they still match the compiled baseline — + /// their compiled bodies keep running (no interpreter cost). + /// + internal List UpToDateMethods { get; set; } = new List(); + + /// + /// Method ids whose stale override was removed because the source matches the compiled + /// baseline again (the edit was reverted). + /// + internal List RevertedMethods { get; set; } = new List(); + + /// Every extracted method matched the baseline; nothing was compiled or registered. + internal bool AllUpToDate => Success && ExtractedMethods.Count == 0 && UpToDateMethods.Count > 0; + + /// + /// Error message if processing failed. + /// + public string ErrorMessage { get; set; } + + /// + /// Compilation diagnostics (warnings, errors). + /// + public List CompilationDiagnostics { get; set; } = new List(); + + /// + /// Execution time in milliseconds. + /// + public long ExecutionTimeMs { get; set; } + } + + /// + /// Result of compiling an override for pushing to a player (no local registration). + /// + internal class PushCompileResult + { + public bool Success { get; set; } + public string TypeName { get; set; } + public List MethodNames { get; set; } = new List(); + public byte[] IlBytes { get; set; } + public string Error { get; set; } + public List Diagnostics { get; set; } = new List(); + + /// [CodeReload] method names skipped because they still match the compiled baseline. + public List UpToDateMethods { get; set; } = new List(); + + /// Every extracted method matched the baseline; there is nothing to push. + public bool AllUpToDate => Success && MethodNames.Count == 0 && UpToDateMethods.Count > 0; + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/InPlaceReloadProcessor.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/InPlaceReloadProcessor.cs.meta new file mode 100644 index 0000000..a8da6aa --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/InPlaceReloadProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 411fb44c3329710449bcbfc2af627524 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/PipelineCodeReloadConnect.cs b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/PipelineCodeReloadConnect.cs new file mode 100644 index 0000000..b987dcf --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/PipelineCodeReloadConnect.cs @@ -0,0 +1,195 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Unity.Pipeline.CodeReload +{ + /// + /// Shared contract for pushing a compiled in-place code-reload override from the editor to a + /// running player over Unity's PlayerConnection — the same editor↔player message bus the Profiler + /// and Console use (tunnels over USB for mobile, no IP or open port required). Lives in Runtime so + /// both the player (PlayerConnection.Register) and the editor push command + /// (EditorConnection.Send) reference the same GUIDs and wire format. + /// + /// The editor compiles the edited method(s) to override-assembly IL bytes (Roslyn, editor-only) + /// and ships {typeName, methodNames, il}; the player feeds them to + /// InterpreterCodeReloadExecutor.Register and runs them through the IlInterpreter interpreter — + /// no Assembly.Load, so it works under IL2CPP. + /// + /// This type touches no Unity API, so it compiles unconditionally on both editor and player. + /// + static class PipelineCodeReloadConnect + { + /// editor → player: apply a compiled override (typeName + method names + IL). + public static readonly Guid ApplyReloadMsg = new Guid("b6f1e0d24c7a4e13a9f2c8d5017e3b44"); + + /// player → editor: an ack (ok + human-readable summary) for a received push. + public static readonly Guid ResultMsg = new Guid("c2a7d4e916b84f0db3e5a1c6072f8d99"); + + /// editor → player: a save is being compiled for a push (payload = utf8 file name). + /// Compilation happens editor-side, so this notice is the only way an on-device overlay can + /// show "compiling…" progress. + public static readonly Guid ReloadPendingMsg = new Guid("d4c9f2a1385e46b7a0d1e8c4529b6f77"); + + /// editor → player: the compile for a pending reload failed (payload = utf8 summary). + /// Without it the on-device overlay would sit on "compiling…" forever after a syntax error. + public static readonly Guid ReloadFailedMsg = new Guid("e7b3a8d05c214f9e8b6d2f0a1c435588"); + + /// player → editor: session announcement for push signing — protocol version, the + /// key fingerprint the player's baked public key expects, and the random session nonce every + /// signed push must carry. Sent on connect and in answer to . + public static readonly Guid HandshakeMsg = new Guid("f19c5b8a2d7e40c6b8a3f0d612c94e55"); + + /// editor → player: re-announce your handshake (empty payload). Sent when the editor's + /// nonce table is empty for a target — typically right after an editor domain reload. + public static readonly Guid RequestHandshakeMsg = new Guid("a8d2c7f4691e4b0f9c5d3a80e17b6c22"); + + /// + /// Wire format: [typeNameLen:int32-LE][utf8 typeName][methodCount:int32-LE] + /// (per method: [len:int32-LE][utf8 name]) [il bytes…]. + /// + public static byte[] Encode(string typeName, IReadOnlyList methodNames, byte[] il) + { + var methods = methodNames ?? Array.Empty(); + + var nameBytes = Encoding.UTF8.GetBytes(typeName ?? ""); + var methodBytes = new byte[methods.Count][]; + int methodsSize = 4; // count + for (int i = 0; i < methods.Count; i++) + { + methodBytes[i] = Encoding.UTF8.GetBytes(methods[i] ?? ""); + methodsSize += 4 + methodBytes[i].Length; + } + + int ilLen = il?.Length ?? 0; + var buf = new byte[4 + nameBytes.Length + methodsSize + ilLen]; + int o = 0; + o = WriteInt32(buf, o, nameBytes.Length); + o = WriteBytes(buf, o, nameBytes); + o = WriteInt32(buf, o, methods.Count); + for (int i = 0; i < methods.Count; i++) + { + o = WriteInt32(buf, o, methodBytes[i].Length); + o = WriteBytes(buf, o, methodBytes[i]); + } + if (ilLen > 0) Buffer.BlockCopy(il, 0, buf, o, ilLen); + return buf; + } + + public static bool TryDecode(byte[] data, out string typeName, out string[] methodNames, out byte[] il) + { + typeName = null; methodNames = null; il = null; + if (data == null || data.Length < 4) return false; + try + { + int o = 0; + int nameLen = ReadInt32(data, ref o); + if (nameLen < 0 || o + nameLen > data.Length) return false; + typeName = Encoding.UTF8.GetString(data, o, nameLen); o += nameLen; + + if (o + 4 > data.Length) return false; + int methodCount = ReadInt32(data, ref o); + if (methodCount < 0) return false; + methodNames = new string[methodCount]; + for (int i = 0; i < methodCount; i++) + { + if (o + 4 > data.Length) return false; + int len = ReadInt32(data, ref o); + if (len < 0 || o + len > data.Length) return false; + methodNames[i] = Encoding.UTF8.GetString(data, o, len); o += len; + } + + int ilLen = data.Length - o; + il = new byte[ilLen]; + if (ilLen > 0) Buffer.BlockCopy(data, o, il, 0, ilLen); + return true; + } + catch + { + return false; + } + } + + /// Handshake wire format: [protocolVersion:int32-LE][fpLen:int32-LE][utf8 fingerprint][nonce…]. + public static byte[] EncodeHandshake(int protocolVersion, string keyFingerprint, byte[] sessionNonce) + { + var fp = Encoding.UTF8.GetBytes(keyFingerprint ?? ""); + var nonce = sessionNonce ?? Array.Empty(); + var buf = new byte[4 + 4 + fp.Length + nonce.Length]; + int o = 0; + o = WriteInt32(buf, o, protocolVersion); + o = WriteInt32(buf, o, fp.Length); + o = WriteBytes(buf, o, fp); + if (nonce.Length > 0) Buffer.BlockCopy(nonce, 0, buf, o, nonce.Length); + return buf; + } + + public static bool TryDecodeHandshake(byte[] data, out int protocolVersion, out string keyFingerprint, out byte[] sessionNonce) + { + protocolVersion = 0; keyFingerprint = null; sessionNonce = null; + if (data == null || data.Length < 8) return false; + try + { + int o = 0; + protocolVersion = ReadInt32(data, ref o); + int fpLen = ReadInt32(data, ref o); + if (fpLen < 0 || fpLen > 256 || o + fpLen > data.Length) return false; + keyFingerprint = Encoding.UTF8.GetString(data, o, fpLen); o += fpLen; + sessionNonce = new byte[data.Length - o]; + if (sessionNonce.Length > 0) Buffer.BlockCopy(data, o, sessionNonce, 0, sessionNonce.Length); + return true; + } + catch + { + return false; + } + } + + /// Payload for the plain-text notices (, ). + public static byte[] EncodeText(string text) => Encoding.UTF8.GetBytes(text ?? ""); + + public static string DecodeText(byte[] data) => + data == null || data.Length == 0 ? "" : Encoding.UTF8.GetString(data); + + /// Result wire format: [ok:1 byte][utf8 message…]. + public static byte[] EncodeResult(bool ok, string message) + { + var msgBytes = Encoding.UTF8.GetBytes(message ?? ""); + var buf = new byte[1 + msgBytes.Length]; + buf[0] = (byte)(ok ? 1 : 0); + Buffer.BlockCopy(msgBytes, 0, buf, 1, msgBytes.Length); + return buf; + } + + public static bool TryDecodeResult(byte[] data, out bool ok, out string message) + { + ok = false; message = null; + if (data == null || data.Length < 1) return false; + ok = data[0] != 0; + message = data.Length > 1 ? Encoding.UTF8.GetString(data, 1, data.Length - 1) : ""; + return true; + } + + private static int WriteInt32(byte[] buf, int off, int v) + { + buf[off] = (byte)v; + buf[off + 1] = (byte)(v >> 8); + buf[off + 2] = (byte)(v >> 16); + buf[off + 3] = (byte)(v >> 24); + return off + 4; + } + + private static int WriteBytes(byte[] buf, int off, byte[] src) + { + if (src.Length > 0) Buffer.BlockCopy(src, 0, buf, off, src.Length); + return off + src.Length; + } + + private static int ReadInt32(byte[] buf, ref int off) + { + int v = buf[off] | (buf[off + 1] << 8) | (buf[off + 2] << 16) | (buf[off + 3] << 24); + off += 4; + return v; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/PipelineCodeReloadConnect.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/PipelineCodeReloadConnect.cs.meta new file mode 100644 index 0000000..17ffc14 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/PipelineCodeReloadConnect.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0ec832e9c0db7b84db213582f2ebc203 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/PushEnvelope.cs b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/PushEnvelope.cs new file mode 100644 index 0000000..e9a2603 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/PushEnvelope.cs @@ -0,0 +1,336 @@ +using System; +using System.Security.Cryptography; +using System.Text; + +namespace Unity.Pipeline.CodeReload +{ + /// Outcome of opening a signed push envelope. Everything except is a + /// rejection; the receiver reports them generically on the wire and specifically in its own log. + enum PushVerifyStatus + { + Ok, + /// The receiver has no baked public key — every push is rejected (strict policy). + NoKey, + /// Structurally not a v1 envelope (bad magic, truncated, absurd lengths). + Malformed, + /// Envelope parses but the RSA signature does not verify under the baked key. + BadSignature, + /// Signature is valid but was made for a different session nonce (replay across + /// sessions/devices, or the editor's nonce table is stale). + NonceMismatch, + /// Signature and nonce are valid but the counter did not increase (replay within + /// the session, or out-of-order delivery). + CounterNotIncreasing, + /// The platform's RSA implementation threw — crypto is unusable here. Surfaced by + /// the boot self-test; should never be the steady state. + CryptoUnavailable, + } + + /// + /// Authenticated envelope for editor → player code-reload pushes, plus the project signing-key + /// primitives. Pure BCL (System.Security.Cryptography, no Unity API) so it compiles on both + /// sides and is unit-testable without a connection. + /// + /// Wire format (little-endian): + /// [magic "UPP1" 4B][session nonce 16B][counter int64][payloadLen int32][payload][RSA signature] + /// The signature is RSA-2048 / SHA-256 / PKCS#1 v1.5 over UTF8() followed + /// by every envelope byte before the signature, so a signature can never be repurposed by a + /// future feature signing other content with the same project key. + /// + /// Keys are serialized in a deliberately trivial private format (base64 RSAParameters fields) + /// rather than XML/PKCS#8: RSA.To/FromXmlString and ImportPkcs8PrivateKey both have per-platform + /// availability gaps across Unity scripting backends; base64ing the raw parameters has none. + /// + static class PushEnvelope + { + public const string DomainTag = "unity-pipeline/push-reload/v1"; + public const int ProtocolVersion = 1; + public const int NonceSize = 16; + public const int RsaKeySizeBits = 2048; + + private const string PrivatePrefix = "upp1-rsa:"; + private const string PublicPrefix = "upp1-rsa-pub:"; + private const int HeaderSize = 4 + NonceSize + 8 + 4; // magic + nonce + counter + payloadLen + private const int MaxPayload = 64 * 1024 * 1024; // sanity bound, far above any real push + + private static readonly byte[] Magic = { (byte)'U', (byte)'P', (byte)'P', (byte)'1' }; + + // ---- keys ---- + + /// Generate a fresh RSA-2048 private key (contains the public half). + public static string CreatePrivateKey() + { + using (var rsa = RSA.Create()) + { + rsa.KeySize = RsaKeySizeBits; + var p = rsa.ExportParameters(true); + return PrivatePrefix + string.Join(".", + B64(p.Modulus), B64(p.Exponent), B64(p.D), B64(p.P), B64(p.Q), + B64(p.DP), B64(p.DQ), B64(p.InverseQ)); + } + } + + /// Extract the shippable public half of a private key. + public static string DerivePublicKey(string privateKey) + { + var p = ParsePrivate(privateKey); + return PublicPrefix + B64(p.Modulus) + "." + B64(p.Exponent); + } + + public static bool IsPublicKey(string key) => + !string.IsNullOrEmpty(key) && key.StartsWith(PublicPrefix, StringComparison.Ordinal); + + public static bool IsPrivateKey(string key) => + !string.IsNullOrEmpty(key) && key.StartsWith(PrivatePrefix, StringComparison.Ordinal); + + /// Short stable id of a keypair (SHA-256 over modulus+exponent, first 8 bytes hex). + /// Accepts the public or the private serialization and gives the same answer. + public static string Fingerprint(string key) + { + RSAParameters p = IsPublicKey(key) ? ParsePublic(key) : ParsePrivate(key); + using (var sha = SHA256.Create()) + { + var data = new byte[p.Modulus.Length + p.Exponent.Length]; + Buffer.BlockCopy(p.Modulus, 0, data, 0, p.Modulus.Length); + Buffer.BlockCopy(p.Exponent, 0, data, p.Modulus.Length, p.Exponent.Length); + var hash = sha.ComputeHash(data); + var sb = new StringBuilder(16); + for (int i = 0; i < 8; i++) sb.Append(hash[i].ToString("x2")); + return sb.ToString(); + } + } + + /// Cryptographically random session nonce. + public static byte[] CreateNonce() + { + var nonce = new byte[NonceSize]; + using (var rng = RandomNumberGenerator.Create()) + rng.GetBytes(nonce); + return nonce; + } + + // ---- signing (editor side) ---- + + public static byte[] Sign(string privateKey, byte[] sessionNonce, long counter, byte[] payload) => + Sign(privateKey, sessionNonce, counter, payload, DomainTag); + + /// Domain-tag overload: exists so tests can prove a signature made under a different + /// tag is rejected. Production code always signs with . + public static byte[] Sign(string privateKey, byte[] sessionNonce, long counter, byte[] payload, string domainTag) + { + if (sessionNonce == null || sessionNonce.Length != NonceSize) + throw new ArgumentException($"session nonce must be {NonceSize} bytes", nameof(sessionNonce)); + payload = payload ?? Array.Empty(); + + var preamble = new byte[HeaderSize + payload.Length]; + Buffer.BlockCopy(Magic, 0, preamble, 0, 4); + Buffer.BlockCopy(sessionNonce, 0, preamble, 4, NonceSize); + WriteInt64(preamble, 4 + NonceSize, counter); + WriteInt32(preamble, 4 + NonceSize + 8, payload.Length); + Buffer.BlockCopy(payload, 0, preamble, HeaderSize, payload.Length); + + byte[] sig; + using (var rsa = RSA.Create()) + { + rsa.ImportParameters(ParsePrivate(privateKey)); + sig = rsa.SignData(Tagged(domainTag, preamble), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); + } + + var envelope = new byte[preamble.Length + sig.Length]; + Buffer.BlockCopy(preamble, 0, envelope, 0, preamble.Length); + Buffer.BlockCopy(sig, 0, envelope, preamble.Length, sig.Length); + return envelope; + } + + // ---- opening (player side) ---- + + /// Cheap structural check: does this look like a v1 envelope (as opposed to a + /// legacy raw payload from a pre-signing editor)? + public static bool LooksLikeEnvelope(byte[] data) => + data != null && data.Length >= HeaderSize && + data[0] == Magic[0] && data[1] == Magic[1] && data[2] == Magic[2] && data[3] == Magic[3]; + + /// Parse without any crypto. Editor-play-mode strip only — never a security gate. + public static bool TryParse(byte[] envelope, out byte[] nonce, out long counter, out byte[] payload) + { + nonce = null; counter = 0; payload = null; + if (!LooksLikeEnvelope(envelope)) return false; + + nonce = new byte[NonceSize]; + Buffer.BlockCopy(envelope, 4, nonce, 0, NonceSize); + counter = ReadInt64(envelope, 4 + NonceSize); + int payloadLen = ReadInt32(envelope, 4 + NonceSize + 8); + if (payloadLen < 0 || payloadLen > MaxPayload || HeaderSize + payloadLen > envelope.Length) + return false; + + payload = new byte[payloadLen]; + Buffer.BlockCopy(envelope, HeaderSize, payload, 0, payloadLen); + return true; + } + + /// + /// Full verification: structure, signature under , session nonce + /// equality, strictly increasing counter. On , + /// and are set. Stateless — callers own + /// the last-counter bookkeeping (see ). + /// + public static PushVerifyStatus TryOpen(string publicKey, byte[] envelope, byte[] expectedNonce, + long lastCounter, out long counter, out byte[] payload) + { + counter = 0; payload = null; + if (string.IsNullOrEmpty(publicKey)) return PushVerifyStatus.NoKey; + if (!LooksLikeEnvelope(envelope)) return PushVerifyStatus.Malformed; + + int payloadLen = ReadInt32(envelope, 4 + NonceSize + 8); + if (payloadLen < 0 || payloadLen > MaxPayload) return PushVerifyStatus.Malformed; + int preambleLen = HeaderSize + payloadLen; + if (preambleLen >= envelope.Length) return PushVerifyStatus.Malformed; // signature must be non-empty + + // Signature first: nothing later is meaningful on unauthenticated bytes. + try + { + var preamble = new byte[preambleLen]; + Buffer.BlockCopy(envelope, 0, preamble, 0, preambleLen); + var sig = new byte[envelope.Length - preambleLen]; + Buffer.BlockCopy(envelope, preambleLen, sig, 0, sig.Length); + + using (var rsa = RSA.Create()) + { + rsa.ImportParameters(ParsePublic(publicKey)); + if (!rsa.VerifyData(Tagged(DomainTag, preamble), sig, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)) + return PushVerifyStatus.BadSignature; + } + } + catch (FormatException) { return PushVerifyStatus.Malformed; } // corrupt key string + catch (Exception) { return PushVerifyStatus.CryptoUnavailable; } + + if (expectedNonce == null || expectedNonce.Length != NonceSize) + return PushVerifyStatus.NonceMismatch; + // Constant-time not required (the nonce is not secret; it is a liveness binding), but + // the full compare is trivial anyway. + int diff = 0; + for (int i = 0; i < NonceSize; i++) diff |= envelope[4 + i] ^ expectedNonce[i]; + if (diff != 0) return PushVerifyStatus.NonceMismatch; + + long c = ReadInt64(envelope, 4 + NonceSize); + if (c <= lastCounter) return PushVerifyStatus.CounterNotIncreasing; + + counter = c; + payload = new byte[payloadLen]; + Buffer.BlockCopy(envelope, HeaderSize, payload, 0, payloadLen); + return PushVerifyStatus.Ok; + } + + /// + /// Boot-time probe that the platform can run the verify path at all (RSA import + VerifyData + /// on a garbage signature must return false, not throw). Catches an IL2CPP/platform crypto + /// gap on day one instead of as mysterious per-push rejects. + /// + public static bool VerifySelfTest(string publicKey, out string error) + { + error = null; + try + { + using (var rsa = RSA.Create()) + { + rsa.ImportParameters(ParsePublic(publicKey)); + var garbageSig = new byte[RsaKeySizeBits / 8]; + if (rsa.VerifyData(new byte[] { 1, 2, 3 }, garbageSig, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1)) + { + error = "garbage signature verified — RSA implementation is broken here"; + return false; + } + } + return true; + } + catch (Exception ex) + { + error = ex.GetType().Name + ": " + ex.Message; + return false; + } + } + + // ---- internals ---- + + private static byte[] Tagged(string domainTag, byte[] preamble) + { + var tag = Encoding.UTF8.GetBytes(domainTag ?? ""); + var signed = new byte[tag.Length + preamble.Length]; + Buffer.BlockCopy(tag, 0, signed, 0, tag.Length); + Buffer.BlockCopy(preamble, 0, signed, tag.Length, preamble.Length); + return signed; + } + + private static RSAParameters ParsePrivate(string key) + { + if (!IsPrivateKey(key)) throw new FormatException("not a " + PrivatePrefix + " private key"); + var f = key.Substring(PrivatePrefix.Length).Split('.'); + if (f.Length != 8) throw new FormatException("private key must have 8 fields"); + return new RSAParameters + { + Modulus = D64(f[0]), Exponent = D64(f[1]), D = D64(f[2]), P = D64(f[3]), + Q = D64(f[4]), DP = D64(f[5]), DQ = D64(f[6]), InverseQ = D64(f[7]), + }; + } + + private static RSAParameters ParsePublic(string key) + { + if (!IsPublicKey(key)) throw new FormatException("not a " + PublicPrefix + " public key"); + var f = key.Substring(PublicPrefix.Length).Split('.'); + if (f.Length != 2) throw new FormatException("public key must have 2 fields"); + return new RSAParameters { Modulus = D64(f[0]), Exponent = D64(f[1]) }; + } + + private static string B64(byte[] b) => Convert.ToBase64String(b ?? Array.Empty()); + private static byte[] D64(string s) => Convert.FromBase64String(s); + + private static void WriteInt32(byte[] buf, int off, int v) + { + buf[off] = (byte)v; buf[off + 1] = (byte)(v >> 8); + buf[off + 2] = (byte)(v >> 16); buf[off + 3] = (byte)(v >> 24); + } + + private static void WriteInt64(byte[] buf, int off, long v) + { + for (int i = 0; i < 8; i++) buf[off + i] = (byte)(v >> (8 * i)); + } + + private static int ReadInt32(byte[] buf, int off) => + buf[off] | (buf[off + 1] << 8) | (buf[off + 2] << 16) | (buf[off + 3] << 24); + + private static long ReadInt64(byte[] buf, int off) + { + long v = 0; + for (int i = 0; i < 8; i++) v |= (long)buf[off + i] << (8 * i); + return v; + } + } + + /// + /// The player-side gate: one per receiver session. Owns the session nonce and the last-accepted + /// counter, so is the single call the receiver makes per push. + /// + sealed class PushVerifier + { + private readonly string m_PublicKey; + private readonly byte[] m_SessionNonce; + private long m_LastCounter; + + public PushVerifier(string publicKey, byte[] sessionNonce) + { + m_PublicKey = publicKey; + m_SessionNonce = sessionNonce; + } + + public byte[] SessionNonce => m_SessionNonce; + + public PushVerifyStatus Verify(byte[] envelope, out byte[] payload) + { + var status = PushEnvelope.TryOpen(m_PublicKey, envelope, m_SessionNonce, m_LastCounter, + out var counter, out payload); + if (status == PushVerifyStatus.Ok) + m_LastCounter = counter; + return status; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/PushEnvelope.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/PushEnvelope.cs.meta new file mode 100644 index 0000000..d6b4c54 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/PushEnvelope.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 3f7a1c92be504d8fa2617e0c4b9d5a21 diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/SourceCodeTransformer.cs b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/SourceCodeTransformer.cs new file mode 100644 index 0000000..3a8cbc3 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/SourceCodeTransformer.cs @@ -0,0 +1,590 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +// The package bundles Roslyn renamed with a "UnityPipeline." prefix (Runtime/Plugins/CodeAnalysis); +// the dotnet test projects reference the same DLLs (IlInterpreter/BundledRoslyn.props). +using UnityPipeline.Microsoft.CodeAnalysis; +using UnityPipeline.Microsoft.CodeAnalysis.CSharp; +using UnityPipeline.Microsoft.CodeAnalysis.CSharp.Syntax; +using Unity.Pipeline.Compilation; +using UnityEngine; + +namespace Unity.Pipeline.CodeReload +{ + /// + /// Transforms [CodeReload] method bodies (edited in place on a MonoBehaviour) into static + /// code reload override methods that the registry can dispatch to. + /// + /// The transform is driven by a Roslyn . Because the body is moved into + /// a standalone static class (no this, no base type, not nested in the original type), every + /// reference that relied on the declaring type's scope is re-qualified so it still binds: + /// + /// instance members of the type hierarchy (e.g. transform on Component) -> instance.<member> + /// static members inherited or declared on the type hierarchy (e.g. FindObjectsByType on + /// Object) -> <ContainingType>.<member> + /// nested types (enum/class) of the type hierarchy (e.g. a private enum State) -> <ContainingType>.<NestedType> + /// + /// Locals, parameters, and types/members reachable via the file's using directives are left + /// untouched. The output is a static override class the registry can bind: + /// + /// [CodeReloadOverrideMethod("Type.Method")] + /// public static <ret> Method(Type instance, <params>) { ...rewritten body... } + /// + static class SourceCodeTransformer + { + /// + /// Transform the [CodeReload] methods named in into a + /// static override class. (the full source of the + /// file) is required so the semantic model can resolve member bindings in context. + /// + /// + /// When true, each rewritten body is bracketed by #line directives that map it back to + /// the original source file so an attached debugger binds breakpoints in the file the user + /// edited. Requires . The body is emitted with its original + /// whitespace (no NormalizeWhitespace) so line positions survive the transform. + /// + /// Absolute path of the source file, recorded in the #line directives. + /// Map of method name to edited body source. + /// Name of the declaring type. + /// Map of method name to its original signature. + /// The full original source file, needed to build the semantic model. + /// + /// Rewrite string interpolation to string.Format(...). Required by the interpreter + /// backend, which cannot run the compiler's DefaultInterpolatedStringHandler + /// lowering; pass false on the Assembly.Load backend so interpolations compile natively + /// (e.g. a FormattableString-targeted interpolation survives). + /// + /// Source for a static override class matching the shape the registry dispatches to. + internal static string TransformMethodBodies( + Dictionary methodBodies, + string originalTypeName, + Dictionary originalMethodSignatures, + string originalTypeDefinition = null, + bool emitLineDirectives = false, + string originalFilePath = null, + bool rewriteInterpolations = true) + { + if (string.IsNullOrEmpty(originalTypeDefinition)) + { + throw new InvalidOperationException( + "In-place transformation requires the full original source to build a semantic model."); + } + + var model = BuildSemanticModel(originalTypeDefinition, originalTypeName, out var classDecl); + if (classDecl == null) + throw new InvalidOperationException($"Could not find class '{originalTypeName}' in source."); + + return TransformMethodBodies(model, classDecl, methodBodies, originalTypeName, + originalMethodSignatures, emitLineDirectives, originalFilePath, rewriteInterpolations); + } + + /// + /// Parse and build the one compilation + semantic model the + /// transform (and its callers' validation) runs against, plus the declaration of + /// — null when the source has no such class. Imports ALL + /// metadata members, not the Public default: the transform's new-method check diffs the + /// source against the compiled type, and with public-only import every PRIVATE compiled + /// method would look new and get wrongly co-emitted. + /// (the project's, or a push target's) makes #if regions match the assembly being patched. + /// + internal static SemanticModel BuildSemanticModel( + string source, string typeName, out ClassDeclarationSyntax classDecl, + string[] preprocessorSymbols = null) + { + var tree = CSharpSyntaxTree.ParseText(source, + RoslynCompilationService.ProjectParseOptions(preprocessorSymbols)); + var compilation = CSharpCompilation.Create( + "CodeReloadInPlaceTransform", + new[] { tree }, + RoslynCompilationService.GetMetadataReferences(), + new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary) + .WithMetadataImportOptions(MetadataImportOptions.All)); + var model = compilation.GetSemanticModel(tree); + classDecl = tree.GetRoot().DescendantNodes() + .OfType() + .FirstOrDefault(c => c.Identifier.ValueText == typeName); + return model; + } + + /// + /// Core transform over an already-built semantic model + class declaration, so the in-place + /// reload path can share one compilation between validation and transformation instead of + /// building two. + /// + internal static string TransformMethodBodies( + SemanticModel model, + ClassDeclarationSyntax classDecl, + Dictionary methodBodies, + string originalTypeName, + Dictionary originalMethodSignatures, + bool emitLineDirectives = false, + string originalFilePath = null, + bool rewriteInterpolations = true) + { + try + { + var root = classDecl.SyntaxTree.GetRoot(); + var classSymbol = model.GetDeclaredSymbol(classDecl); + var compiledTwin = FindCompiledType(model.Compilation, classSymbol); + // A top-level type with no compiled twin is entirely NEW (the file was added since + // the build): every method is co-emittable, and the receiver parameter can't name + // the type — it doesn't exist in any reference — so it degrades to object (the + // dispatch passes null for statics anyway). Instance-member access still can't + // compile in that state; new-type reloads are for self-contained static methods. + var wholeTypeIsNew = compiledTwin == null && classSymbol?.ContainingType == null; + var newMethods = ComputeNewMethodNames(classDecl, compiledTwin, wholeTypeIsNew); + // A static type can't appear as a parameter (CS0721), so its receiver slot — always + // dispatched null anyway — degrades to object. Check the compiled twin too: the + // source may have dropped the static keyword while the running build still has it. + var typeIsStatic = classDecl.Modifiers.Any(SyntaxKind.StaticKeyword) + || (compiledTwin?.IsStatic ?? false); + var instanceTypeName = wholeTypeIsNew || typeIsStatic ? "object" : originalTypeName; + var rewriter = new ImplicitScopeQualifier(model, classSymbol, newMethods, + new HashSet(methodBodies.Keys)); + + var sb = new StringBuilder(); + var emittedUsings = new HashSet(); + foreach (var u in root.DescendantNodes().OfType()) + { + if (emittedUsings.Add(u.Name?.ToString() ?? u.ToString())) + sb.AppendLine(u.ToString()); + } + if (emittedUsings.Add("Unity.Pipeline.CodeReload")) + sb.AppendLine("using Unity.Pipeline.CodeReload;"); + + var namespaceName = GetNamespace(classDecl); + if (!string.IsNullOrEmpty(namespaceName) && emittedUsings.Add(namespaceName)) + sb.AppendLine($"using {namespaceName};"); + sb.AppendLine(); + + sb.AppendLine($"public static class {originalTypeName}CodeReloadOverrides"); + sb.AppendLine("{"); + + foreach (var method in classDecl.Members.OfType()) + { + var methodName = method.Identifier.ValueText; + var isOverride = methodBodies.ContainsKey(methodName) && method.Body != null; + // A method the compiled type doesn't declare is NEW — nothing compiled can + // dispatch to it, but a reloaded body can: co-emit it into the override class + // so it becomes an interpreted method the rewritten call sites reach directly. + var isNewMethod = !isOverride && newMethods.Contains(methodName) + && (method.Body != null || method.ExpressionBody != null); + if (!isOverride && !isNewMethod) + continue; + + // Qualify instance members first: the semantic model is bound to the original + // syntax tree, so this must run before any rewrite that produces new nodes. + // Interpolation-to-string.Format is purely syntactic — no semantic model — so + // it can safely run on the qualified (synthesized) tree. It runs only for the + // interpreter backend (see the rewriteInterpolations doc). + // New methods may be expression-bodied; emitted text is `=> expr;` then. + SyntaxNode rewrittenBody = method.Body != null + ? rewriter.Visit(method.Body) + : rewriter.Visit(method.ExpressionBody); + if (rewriteInterpolations) + rewrittenBody = new InterpolationToFormatRewriter().Visit(rewrittenBody); + var bodySuffix = method.Body != null ? "" : ";"; + var returnType = method.ReturnType.ToString(); + + // Overrides always take the receiver first (the dispatch passes null for + // statics); a new STATIC method has no receiver at all — call sites stay bare. + var parameters = new List(); + if (isOverride || !method.Modifiers.Any(SyntaxKind.StaticKeyword)) + parameters.Add($"{instanceTypeName} instance"); + parameters.AddRange(isOverride + ? method.ParameterList.Parameters.Select(p => $"{p.Type} {p.Identifier.ValueText}") + // New methods keep their parameter list verbatim (modifiers, defaults). + : method.ParameterList.Parameters.Select(p => p.ToString())); + + if (isOverride) + sb.AppendLine($" [CodeReloadOverrideMethod(\"{originalTypeName}.{methodName}\")]"); + sb.AppendLine($" public static {returnType} {methodName}({string.Join(", ", parameters)})"); + + if (emitLineDirectives && !string.IsNullOrEmpty(originalFilePath)) + { + // Map the body back to the original file. The rewriter only makes intra-line + // edits, so a single #line at the body's opening brace maps every line of the + // block; emit the body with original trivia (not NormalizeWhitespace) to keep + // line counts intact. #line hidden masks the generated scaffolding that follows. + var bodyNode = (SyntaxNode)method.Body ?? method.ExpressionBody; + var bodyLine = bodyNode.GetLocation().GetLineSpan().StartLinePosition.Line + 1; + var escapedPath = originalFilePath.Replace("\\", "\\\\"); + sb.AppendLine($"#line {bodyLine} \"{escapedPath}\""); + sb.AppendLine(rewrittenBody.ToString() + bodySuffix); + sb.AppendLine("#line hidden"); + } + else + { + sb.AppendLine(" " + rewrittenBody.NormalizeWhitespace().ToString() + bodySuffix); + } + sb.AppendLine(); + } + + sb.AppendLine("}"); + + var result = sb.ToString(); + Debug.Log($"CodeReload: Transformed {methodBodies.Count} in-place method(s) for {originalTypeName}"); + return result; + } + catch (Exception ex) + { + Debug.LogError($"CodeReload: Error transforming in-place methods for {originalTypeName}: {ex.Message}"); + throw new InvalidOperationException( + $"Failed to transform in-place methods for {originalTypeName}: {ex.Message}", ex); + } + } + + private static string GetNamespace(SyntaxNode node) + { + for (var current = node.Parent; current != null; current = current.Parent) + { + if (current is NamespaceDeclarationSyntax ns) + return ns.Name.ToString(); + } + return null; + } + + /// + /// Names of methods the edited source declares but the COMPILED type doesn't — methods the + /// user added since the last compile. Their call sites can't bind to the host object, so + /// they are co-emitted into the override class and called directly. Generic methods are + /// excluded (outside the interpreter subset). When the whole type is new + /// () every method qualifies; when only the compiled twin + /// lookup failed (a nested type) the set is empty — every call site then binds to the + /// host, the pre-existing behavior. + /// + private static HashSet ComputeNewMethodNames( + ClassDeclarationSyntax classDecl, INamedTypeSymbol compiledType, bool wholeTypeIsNew) + { + var result = new HashSet(); + if (compiledType == null && !wholeTypeIsNew) + return result; + + foreach (var method in classDecl.Members.OfType()) + { + if (method.Body == null && method.ExpressionBody == null) + continue; + if (method.TypeParameterList != null) + continue; + var name = method.Identifier.ValueText; + // Declared-members check only: a name that exists compiled (any overload, or on a + // base type but redeclared here) stays host-bound. A source method hiding a base + // member counts as new — the co-emitted copy preserves the source's binding. + if (wholeTypeIsNew || compiledType.GetMembers(name).Length == 0) + result.Add(name); + } + return result; + } + + /// + /// The compiled (metadata) symbol for , resolved from the + /// compilation's references — the source declaration shadows it inside the compilation, so + /// the reference assemblies are probed directly. Null when no compiled twin exists. + /// + private static INamedTypeSymbol FindCompiledType( + UnityPipeline.Microsoft.CodeAnalysis.Compilation compilation, INamedTypeSymbol classSymbol) + { + if (classSymbol == null || classSymbol.ContainingType != null) + return null; + var metadataName = classSymbol.ContainingNamespace is { IsGlobalNamespace: false } ns + ? $"{ns.ToDisplayString()}.{classSymbol.MetadataName}" + : classSymbol.MetadataName; + foreach (var reference in compilation.References) + { + if (compilation.GetAssemblyOrModuleSymbol(reference) is IAssemblySymbol asm + && asm.GetTypeByMetadataName(metadataName) is { } compiled) + return compiled; + } + return null; + } + + /// + /// Rewrites bare references that depended on the original type's scope so they still bind after + /// the body is moved into a standalone static class, using the semantic model: + /// instance members -> instance.x, static members of the type hierarchy -> + /// ContainingType.x, and nested types of the type hierarchy -> ContainingType.Nested. + /// Locals, parameters, and anything reachable via using are left untouched. + /// + private class ImplicitScopeQualifier : CSharpSyntaxRewriter + { + private readonly SemanticModel m_Model; + private readonly INamedTypeSymbol m_Type; + private readonly HashSet m_NewMethods; + private readonly HashSet m_ReloadedMethods; + + public ImplicitScopeQualifier(SemanticModel model, INamedTypeSymbol type, + HashSet newMethods = null, HashSet reloadedMethods = null) + { + m_Model = model; + m_Type = type; + m_NewMethods = newMethods ?? new HashSet(); + m_ReloadedMethods = reloadedMethods ?? new HashSet(); + } + + /// + /// Calls to NEW methods (declared in the edited source, absent from the compiled type) + /// can't bind to the host object — the callee only exists as a co-emitted static in the + /// override class. Rebuild the call as a direct static invocation, threading the + /// receiver (the implicit instance, or an explicit one like other.Helper()) + /// as the first argument to match the co-emitted signature. + /// + public override SyntaxNode VisitInvocationExpression(InvocationExpressionSyntax node) + { + // Resolve on the original node — the model is bound to the original tree. + var target = m_NewMethods.Count > 0 + ? m_Model.GetSymbolInfo(node.Expression).Symbol as IMethodSymbol + : null; + var visited = (InvocationExpressionSyntax)base.VisitInvocationExpression(node); + if (target == null || !m_NewMethods.Contains(target.Name) + || !SymbolEqualityComparer.Default.Equals(target.ContainingType, m_Type)) + return visited; + // Conditional calls (`x?.NewHelper()`) have no receiver expression to thread as an + // argument; leave them — the compile fails with a clear CS1061 instead of silently + // running the helper on the wrong instance. + if (visited.Expression is MemberBindingExpressionSyntax) + return visited; + + var arguments = visited.ArgumentList; + // A new method that is itself reloaded is emitted in the override shape — leading + // instance parameter even when static (the dispatch it gets after the next compile + // passes null there) — so its call sites must pass a receiver either way. + if (!target.IsStatic || m_ReloadedMethods.Contains(target.Name)) + { + // The visited expression is either `receiver.Helper` (this -> instance already + // applied by the base visit) or a bare/qualified name; a member access carries + // the receiver to thread through, anything else means the implicit `instance`. + // A STATIC call has no receiver — its qualifier is a type name — so the + // caller's own `instance` is what the override-shaped callee gets. + var receiver = !target.IsStatic && visited.Expression is MemberAccessExpressionSyntax ma + ? ma.Expression + : (ExpressionSyntax)SyntaxFactory.IdentifierName("instance"); + arguments = arguments.WithArguments( + arguments.Arguments.Insert(0, SyntaxFactory.Argument(receiver))); + } + return SyntaxFactory.InvocationExpression( + SyntaxFactory.IdentifierName(target.Name), arguments) + .WithTriviaFrom(visited); + } + + public override SyntaxNode VisitThisExpression(ThisExpressionSyntax node) + { + return SyntaxFactory.IdentifierName("instance").WithTriviaFrom(node); + } + + public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node) + { + if (ShouldSkip(node)) + return base.VisitIdentifierName(node); + + // Symbol is resolved from the original node (the semantic model is bound to the original + // tree); the same node is what gets wrapped since an identifier has no children to rewrite. + return TryQualify(node, node) ?? base.VisitIdentifierName(node); + } + + public override SyntaxNode VisitGenericName(GenericNameSyntax node) + { + // e.g. GetComponent() or FindObjectsByType() — visit type arguments first + // (a type arg may itself be a nested type needing qualification), then wrap the result. + var visited = (GenericNameSyntax)base.VisitGenericName(node); + + if (ShouldSkip(node)) + return visited; + + return TryQualify(node, visited) ?? visited; + } + + private static bool ShouldSkip(SimpleNameSyntax node) + { + // Right-hand side of a member access (foo.Bar -> Bar), or part of a qualified name. + if (node.Parent is MemberAccessExpressionSyntax ma && ma.Name == node) + return true; + if (node.Parent is QualifiedNameSyntax) + return true; + if (node.Parent is MemberBindingExpressionSyntax) + return true; + return false; + } + + /// + /// Returns the qualified replacement for if + /// binds to something that needs the original type's scope, otherwise null (leave as-is). + /// + private SyntaxNode TryQualify(SimpleNameSyntax original, SimpleNameSyntax toWrap) + { + var symbol = m_Model.GetSymbolInfo(original).Symbol; + if (symbol == null) + return null; + + // `var` (and a `using Alias = Outer.Nested;` alias) binds to a type spelled + // differently from the identifier. Qualifying the identifier would emit + // `Outer.var` / `Outer.Alias`, which does not exist. Roslyn re-infers `var` on + // the rewritten initializer, so leave the spelling alone. + if (symbol is ITypeSymbol && symbol.Name != original.Identifier.ValueText) + return null; + + // Nested type of the type hierarchy (e.g. a private `enum State`) -> ContainingType.Nested. + if (symbol is INamedTypeSymbol nested && nested.ContainingType != null + && InTypeHierarchy(nested.ContainingType)) + return QualifyWithType(toWrap, nested.ContainingType, original); + + if (!IsMemberSymbol(symbol)) + return null; + + if (!InTypeHierarchy(symbol.ContainingType)) + return null; + + // A method GROUP over a new method (delegate argument, event `+=`): the member + // doesn't exist on the compiled type, so `instance.M` can't bind. Wrap it as a + // lambda over the co-emitted static instead. + if (symbol is IMethodSymbol group && m_NewMethods.Contains(group.Name) + && !(original.Parent is InvocationExpressionSyntax inv && inv.Expression == original) + && MethodGroupLambda(group, original, receiver: null) is { } lambda) + return lambda.WithTriviaFrom(toWrap); + + return symbol.IsStatic + ? QualifyWithType(toWrap, symbol.ContainingType, original) + : QualifyWith(toWrap, SyntaxFactory.IdentifierName("instance")); + } + + /// + /// `x.Click` where Click is NEW and not invoked — the member-access form of a method + /// group over a new method. Same lambda rewrite as the bare-identifier form, but the + /// (visited) receiver expression is threaded as the co-emitted static's first argument. + /// + public override SyntaxNode VisitMemberAccessExpression(MemberAccessExpressionSyntax node) + { + if (m_NewMethods.Count > 0 + && !(node.Parent is InvocationExpressionSyntax inv && inv.Expression == node) + && m_Model.GetSymbolInfo(node).Symbol is IMethodSymbol group + && m_NewMethods.Contains(group.Name) + && SymbolEqualityComparer.Default.Equals(group.ContainingType, m_Type)) + { + var visited = (MemberAccessExpressionSyntax)base.VisitMemberAccessExpression(node); + if (MethodGroupLambda(group, node, visited.Expression) is { } lambda) + return lambda.WithTriviaFrom(node); + return visited; + } + return base.VisitMemberAccessExpression(node); + } + + /// + /// Builds ((a0, a1) => M(receiver, a0, a1)) for a method group over a new + /// method, shaped by the delegate type the group converts to (the semantic model's + /// ConvertedType). Null when the conversion target isn't a delegate — the caller + /// falls through, and the compile reports the site. One semantic difference from a + /// real method-group conversion: the receiver expression is evaluated per invocation, + /// not captured at conversion time. + /// + private ExpressionSyntax MethodGroupLambda( + IMethodSymbol group, ExpressionSyntax original, ExpressionSyntax receiver) + { + if (m_Model.GetTypeInfo(original).ConvertedType is not INamedTypeSymbol delegateType + || delegateType.DelegateInvokeMethod is not { } invoke) + return null; + + var argList = new List(); + // Matches the co-emitted signature: instance methods and reloaded (override-shaped) + // methods take the receiver first; new plain statics don't. + if (!group.IsStatic || m_ReloadedMethods.Contains(group.Name)) + argList.Add(SyntaxFactory.Argument(receiver ?? SyntaxFactory.IdentifierName("instance"))); + var parameters = new List(); + for (int i = 0; i < invoke.Parameters.Length; i++) + { + var name = "__mg" + i; + parameters.Add(SyntaxFactory.Parameter(SyntaxFactory.Identifier(name))); + argList.Add(SyntaxFactory.Argument(SyntaxFactory.IdentifierName(name))); + } + var call = SyntaxFactory.InvocationExpression( + SyntaxFactory.IdentifierName(group.Name), + SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(argList))); + return SyntaxFactory.ParenthesizedExpression( + SyntaxFactory.ParenthesizedLambdaExpression( + SyntaxFactory.ParameterList(SyntaxFactory.SeparatedList(parameters)), + call)); + } + + private static bool IsMemberSymbol(ISymbol symbol) + { + switch (symbol.Kind) + { + case SymbolKind.Field: + case SymbolKind.Property: + case SymbolKind.Method: + case SymbolKind.Event: + return true; + default: + return false; + } + } + + private bool InTypeHierarchy(INamedTypeSymbol containingType) + { + if (containingType == null) + return false; + for (var t = m_Type; t != null; t = t.BaseType) + { + if (SymbolEqualityComparer.Default.Equals(t, containingType)) + return true; + } + return false; + } + + /// Qualify with a fully-qualified type name (e.g. global::UnityEngine.Object.X). + private static SyntaxNode QualifyWithType(SimpleNameSyntax node, INamedTypeSymbol type, SimpleNameSyntax original) + { + var typeName = type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); + + // In a type position (local/foreach declaration, cast, array type, generic argument, + // typeof) the parent's slot holds a TypeSyntax, so the replacement must be a + // QualifiedName — a MemberAccessExpression there makes the rewriter's typed rebuild + // throw InvalidCastException. Expression positions keep MemberAccess; both print the + // same text. + if (SyntaxFacts.IsInNamespaceOrTypeContext(original)) + return SyntaxFactory.QualifiedName( + SyntaxFactory.ParseName(typeName), + node.WithoutTrivia()) + .WithTriviaFrom(node); + + return QualifyWith(node, SyntaxFactory.ParseExpression(typeName)); + } + + private static SyntaxNode QualifyWith(SimpleNameSyntax node, ExpressionSyntax qualifier) + { + return SyntaxFactory.MemberAccessExpression( + SyntaxKind.SimpleMemberAccessExpression, + qualifier, + node.WithoutTrivia()) + .WithTriviaFrom(node); + } + } + } + + /// + /// Information about a method's signature for transformation purposes. + /// + class MethodSignatureInfo + { + /// The method's return type name, or "void". + public string ReturnType { get; set; } + /// The method's parameters. + public List Parameters { get; set; } = new List(); + /// True unless is "void". + public bool ReturnsValue => !string.IsNullOrEmpty(ReturnType) && ReturnType != "void"; + } + + /// + /// Information about a method parameter. + /// + class ParameterInfo + { + /// The parameter's type name. + public string Type { get; set; } + /// The parameter's name. + public string Name { get; set; } + /// Whether the parameter has a default value. + public bool HasDefaultValue { get; set; } + /// The parameter's default value expression, if any. + public string DefaultValue { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/SourceCodeTransformer.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/SourceCodeTransformer.cs.meta new file mode 100644 index 0000000..75ef1fb --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/CodeReload/SourceCodeTransformer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 425cdc175cccce547a6a3bf6f73c1f4f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Commands.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Commands.meta new file mode 100644 index 0000000..ed4d613 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Commands.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 67704748e63416c4c959bd6de99b4c4f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Commands/CaptureRuntimeElementCommand.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/CaptureRuntimeElementCommand.cs new file mode 100644 index 0000000..bea5223 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/CaptureRuntimeElementCommand.cs @@ -0,0 +1,144 @@ +#if UNITY_6000_7_OR_NEWER +using System.Collections.Generic; +using System.Linq; +using Unity.Pipeline.Commands; +using UnityEngine; +using UnityEngine.UIElements; +using Object = UnityEngine.Object; + +namespace Unity.Pipeline.Runtime.Commands +{ + /// + /// Captures a UI Toolkit from a live runtime panel to a PNG and + /// returns it base64-encoded (and writes it to disk). Runtime-only so it is available in a + /// development Player as well as the editor's Play mode. + /// + /// A runtime panel is hosted by either a or a . + /// The panel is identified by name (the asset name or the host + /// GameObject name) rather than an asset path, because a Player has no AssetDatabase. + /// + static class CaptureRuntimeElementCommand + { + [CliCommand("capture_runtime_element", + "Capture a UI Toolkit VisualElement (by selector) from a live runtime panel (UIDocument or PanelRenderer) to a PNG; returns path + base64.", + MainThreadRequired = true, RuntimeOnly = true, + Tags = new[] { "capture", "ui" })] + public static CaptureElementResponse CaptureRuntimeElement( + [CliArg("panel", "Name of the target panel: matches the PanelSettings asset name or the host GameObject name (UIDocument or PanelRenderer). Optional when exactly one panel exists.")] string panel = "", + [CliArg("selector", "Element selector: '#name', '.class', a type name (e.g. Button), descendant (space) / child ('>') chains, optional pseudo-states (:checked,:hover,:focus,:active,:enabled,:disabled,:not(...)).", Required = true)] string selector = "", + [CliArg("output", "Output PNG path (absolute, or relative to Application.persistentDataPath). Defaults to a timestamped file under Application.persistentDataPath.")] string output = "") + { + if (string.IsNullOrWhiteSpace(selector)) + return CaptureElementResponse.Fail("A 'selector' is required."); + + var hosts = GatherHosts(); + if (hosts.Count == 0) + return CaptureElementResponse.Fail("No live runtime UI panels found (UIDocument or PanelRenderer). Show the UI first."); + + List matched; + string resolvedName; + if (string.IsNullOrWhiteSpace(panel)) + { + if (hosts.Count > 1) + { + var names = string.Join(", ", hosts.Select(h => h.DisplayName).Distinct()); + return CaptureElementResponse.Fail( + $"Multiple runtime panels exist; specify --panel as one of: {names}."); + } + + matched = hosts; + resolvedName = hosts[0].DisplayName; + } + else + { + matched = hosts.Where(h => h.PanelSettingsName == panel || h.GameObjectName == panel).ToList(); + if (matched.Count == 0) + { + var names = string.Join(", ", hosts.Select(h => h.DisplayName).Distinct()); + return CaptureElementResponse.Fail( + $"No live runtime panel named '{panel}'. Available: {names}."); + } + + resolvedName = panel; + } + + // Lower sorting order is drawn first (further back); query in that order so the topmost + // match is found last only if earlier panels miss. Roots that can't be resolved are skipped. + var roots = matched + .OrderBy(h => h.SortingOrder) + .Select(h => h.GetRoot()) + .Where(r => r != null) + .ToList(); + + if (roots.Count == 0) + return CaptureElementResponse.Fail( + $"Panel '{resolvedName}' has no initialized root VisualElement yet. Show the UI first."); + + var element = VisualElementCaptureSupport.ResolveElement(roots, selector, out _); + if (element == null) + return CaptureElementResponse.Fail( + $"No element matched selector '{selector}' in panel '{resolvedName}'."); + + var dir = Application.persistentDataPath; + return VisualElementCaptureSupport.CaptureAndRespond( + element, selector, $"panel:{resolvedName}", output, + relativeBaseDir: dir, defaultDir: dir, prefix: "element"); + } + + /// A live runtime UI host (UIDocument or PanelRenderer) and how to reach its root. + class Host + { + public string PanelSettingsName; + public string GameObjectName; + public float SortingOrder; + public System.Func GetRoot; + + public string DisplayName => PanelSettingsName ?? GameObjectName; + } + + static List GatherHosts() + { + var hosts = new List(); + + foreach (var doc in PipelineUtils.FindObjectsByType()) + { + var d = doc; + hosts.Add(new Host + { + PanelSettingsName = d.panelSettings != null ? d.panelSettings.name : null, + GameObjectName = d.gameObject.name, + SortingOrder = d.sortingOrder, + GetRoot = () => d.rootVisualElement + }); + } + + // PanelRenderer is a 6000.5+ UI Toolkit API; on older editors only UIDocument panels exist. + foreach (var renderer in PipelineUtils.FindObjectsByType()) + { + var r = renderer; + hosts.Add(new Host + { + PanelSettingsName = r.panelSettings != null ? r.panelSettings.name : null, + GameObjectName = r.gameObject.name, + SortingOrder = r.sortingOrder, + GetRoot = () => GetPanelRendererRoot(r) + }); + } + + return hosts; + } + + // PanelRenderer.rootVisualElement is internal; the public route to its root is a UI-reload + // callback, which fires synchronously when the panel is already initialized. Register, capture + // the root, and immediately unregister. PanelRenderer is a 6000.5+ API. + static VisualElement GetPanelRendererRoot(PanelRenderer renderer) + { + VisualElement captured = null; + PanelRenderer.VersionedUIReloadCallback callback = (pr, root, version) => captured = root; + renderer.RegisterUIReloadCallback(callback); + renderer.UnregisterUIReloadCallback(callback); + return captured; + } + } +} +#endif diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Commands/CaptureRuntimeElementCommand.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/CaptureRuntimeElementCommand.cs.meta new file mode 100644 index 0000000..4437241 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/CaptureRuntimeElementCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 54dc75c59cc13424c9e6e0e7b237e412 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Commands/CodeEvalCommand.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/CodeEvalCommand.cs new file mode 100644 index 0000000..34f1cf9 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/CodeEvalCommand.cs @@ -0,0 +1,163 @@ +using System; +using Unity.Pipeline.Models; +using Unity.Pipeline.Compilation; +using Unity.Pipeline.Telemetry; +using UnityEngine; +using Unity.Pipeline.Commands; + +namespace Unity.Pipeline.Runtime.Commands +{ + /// + /// Command for evaluating C# code dynamically using Roslyn compilation. + /// Requires security token for authorization. + /// + static class CodeEvalCommand + { + [CliCommand("eval", "Evaluate C# code dynamically using Roslyn compiler", MainThreadRequired = true, Tags = new[] { "scripts/eval" })] + public static EvalResponse EvaluateCode( + [CliArg("code", "C# code to evaluate", Required = true)] string code, + [CliArg("timeout", "Timeout in milliseconds")] int timeout = 5000) + { + if (string.IsNullOrWhiteSpace(code)) + return RejectedEval("eval", code, "Code parameter is required and cannot be empty"); + + return EvaluateSource(code, timeout, "eval"); + } + + [CliCommand("eval_file", "Evaluate C# code read from a .cs file on disk", MainThreadRequired = true, Tags = new[] { "scripts/eval" })] + public static EvalResponse EvaluateFile( + [CliArg("file", "Path to a .cs file to evaluate", Required = true)] string file, + [CliArg("timeout", "Timeout in milliseconds")] int timeout = 5000) + { + if (string.IsNullOrWhiteSpace(file)) + return RejectedEval("eval_file", null, "File parameter is required and cannot be empty"); + + if (!file.EndsWith(".cs", StringComparison.OrdinalIgnoreCase)) + return RejectedEval("eval_file", null, "File must have a .cs extension"); + + if (!System.IO.File.Exists(file)) + return RejectedEval("eval_file", null, $"File not found: {file}"); + + string code; + try + { + code = System.IO.File.ReadAllText(file); + } + catch (Exception ex) + { + return RejectedEval("eval_file", null, $"Failed to read file: {ex.Message}"); + } + + if (string.IsNullOrWhiteSpace(code)) + return RejectedEval("eval_file", code, $"File is empty: {file}"); + + return EvaluateSource(code, timeout, "eval_file"); + } + + /// + /// Reject an invocation at validation time AND record it: a rejected eval is still an eval + /// invocation, and skipping telemetry here would undercount report_evals' errorCount / + /// errorRate for exactly the mistakes an agent makes most (empty code, wrong path). + /// + private static EvalResponse RejectedEval(string command, string code, string errorDetails) + { + // Guarded like the RecordInBackground call in EvaluateSource: telemetry must never + // affect eval behavior, so a failure in its synchronous prelude (ResolveDirectory, + // the write-chain lock) can't turn a clean Bad Request into an unhandled exception. + try + { + EvalUsageTelemetry.RecordInBackground(command, code ?? string.Empty, success: false, + error: "Bad Request", executionTimeMs: 0); + } + catch + { + // Telemetry must never affect eval behavior. + } + + return EvalResponse.EvalFailure("Bad Request", errorDetails); + } + + /// Upper bound on a single eval's timeout — 24 hours (CLI-335; was 30s). + private const int MaxTimeoutMs = 86_400_000; + + /// + /// Shared evaluation path: compiles and executes the given C# source and returns the + /// response. Both the eval and eval_file commands funnel their resolved + /// source string into here. Each invocation is recorded to local eval-usage telemetry + /// (AUTHAPI-29) on a best-effort basis before returning. + /// + private static EvalResponse EvaluateSource(string code, int timeout, string commandName) + { + var stopwatch = System.Diagnostics.Stopwatch.StartNew(); + EvalResponse response; + + try + { + // Validate timeout + // Cap raised from 30000ms (CLI-335): long evals are now legitimate — clients + // set custom timeouts or run detached jobs and reattach. 24h bounds abuse. + // (Supersedes the interim 300000ms raise from UUM-148641.) + if (timeout <= 0 || timeout > MaxTimeoutMs) + { + stopwatch.Stop(); + response = EvalResponse.EvalFailure( + "Bad Request", + $"Timeout must be between 1ms and {MaxTimeoutMs}ms", + stopwatch.ElapsedMilliseconds); + } + else + { + // Execute compilation and evaluation. We're already on the main thread + // (MainThreadRequired = true), so call the synchronous path directly. + var result = EvalCodeCompiler.CompileAndExecuteOnMainThread(code, timeout, null); + + stopwatch.Stop(); + + // Update execution time + if (result != null) + { + result.ExecutionTimeMs = stopwatch.ElapsedMilliseconds; + } + + response = result ?? EvalResponse.EvalFailure( + "Unknown Error", + "Compilation returned null result", + stopwatch.ElapsedMilliseconds); + } + } + catch (Exception ex) + { + stopwatch.Stop(); + Debug.LogError($"Pipeline: Eval command failed: {ex.Message}"); + Debug.LogError($"Pipeline: Stack trace: {ex.StackTrace}"); + + response = EvalResponse.EvalFailure( + "Execution Failed", + ex.ToString(), + stopwatch.ElapsedMilliseconds); + } + + // Best-effort local telemetry (editor-only; a no-op in players): fingerprint + shape only + // by default (no raw source unless the explicit opt-in is set). The eval primitives and + // the current settings are snapshotted here on the main thread, then the Roslyn parse and + // file append run on a background task — fire-and-forget, zero latency added to the + // response. RecordInBackground swallows its own errors, but guard here too so an + // unexpected failure can never turn a good eval into a failed command. + try + { + EvalUsageTelemetry.RecordInBackground( + commandName, + code, + response.Success, + response.Error, + response.ExecutionTimeMs ?? stopwatch.ElapsedMilliseconds); + } + catch + { + // Telemetry must never affect eval behavior. + } + + return response; + } + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Commands/CodeEvalCommand.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/CodeEvalCommand.cs.meta new file mode 100644 index 0000000..2d9d584 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/CodeEvalCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bc1d3406462d2c246a5f84dd30dd02c7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Commands/CodeReloadCommands.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/CodeReloadCommands.cs new file mode 100644 index 0000000..06772e5 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/CodeReloadCommands.cs @@ -0,0 +1,455 @@ +using System; +using System.IO; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Compilation; +using Unity.Pipeline.CodeReload; +using Unity.Pipeline.Models; +using UnityEngine; + +namespace Unity.Pipeline.Runtime.Commands +{ + /// + /// CLI commands for code reload operations: apply [CodeReload] edits from a source file, inspect + /// the registry, and clean up saved reload assemblies. + /// + static class CodeReloadCommands + { + [CliCommand("reload_file", "Compile and apply in-place [CodeReload] edits from a source file", MainThreadRequired = true, Tags = new[] { "scripts/codereload" })] + public static CodeReloadResponse ReloadFile( + [CliArg("filename", "Source file containing [CodeReload] methods (e.g. Assets/Scripts/Player.cs)", Required = true)] string filename, + [CliArg("timeout", "Compilation timeout in milliseconds")] int timeout = 30000, + [CliArg("assemblyDir", "Directory to save compiled assemblies to disk (optional, default is in-memory only)")] string assemblyDir = null, + [CliArg("pdb", "Emit debug symbols (portable PDB) mapped to the original source so breakpoints bind in your editor. Compiles unoptimized.")] bool pdb = false) + { + return ReloadFileCore("reload_file", filename, timeout, assemblyDir, pdb, useInterpreter: false); + } + + [CliCommand("reload_file_editor_interpreter", "Compile in-place [CodeReload] edits and run them through the IlInterpreter VM in this process instead of Assembly.Load (IL2CPP-safe; only a minimal host API + the target type are available)", MainThreadRequired = true, Tags = new[] { "scripts/codereload" })] + public static CodeReloadResponse ReloadFileEditorInterpreter( + [CliArg("filename", "Source file containing [CodeReload] methods (e.g. Assets/Scripts/Player.cs)", Required = true)] string filename, + [CliArg("timeout", "Compilation timeout in milliseconds")] int timeout = 30000, + [CliArg("assemblyDir", "Directory to save compiled assemblies to disk (optional, default is in-memory only)")] string assemblyDir = null, + [CliArg("pdb", "Emit debug symbols (portable PDB) mapped to the original source so breakpoints bind in your editor. Compiles unoptimized.")] bool pdb = false) + { + return ReloadFileCore("reload_file_editor_interpreter", filename, timeout, assemblyDir, pdb, useInterpreter: true); + } + + /// Shared body of reload_file and reload_file_editor_interpreter: + /// the two commands differ only in the backend the reloaded methods run on. + private static CodeReloadResponse ReloadFileCore(string commandName, string filename, int timeout, string assemblyDir, bool pdb, bool useInterpreter) + { + var stopwatch = System.Diagnostics.Stopwatch.StartNew(); + + try + { + if (string.IsNullOrWhiteSpace(filename)) + { + stopwatch.Stop(); + return CodeReloadResponse.CmdFailure( + "Bad Request", + "Filename parameter is required and cannot be empty", + stopwatch.ElapsedMilliseconds); + } + + if (!filename.EndsWith(".cs", StringComparison.OrdinalIgnoreCase)) + { + filename += ".cs"; + } + + var fullPath = ResolveSourceFilePath(filename); + if (string.IsNullOrEmpty(fullPath)) + { + stopwatch.Stop(); + return CodeReloadResponse.CmdFailure( + "File Not Found", + $"Could not locate source file: {filename}", + stopwatch.ElapsedMilliseconds); + } + + // In a Player build, the file must be inside the project's build-baked roots. The + // project layout cannot be resolved from a running build, so this is skipped in the + // editor (which resolves files against the live project). + if (!Application.isEditor) + { + var scopeCheck = ValidateReloadPath(fullPath, CodeReloadRegistry.AllowedReloadRoots); + if (!scopeCheck.IsValid) + { + stopwatch.Stop(); + return CodeReloadResponse.CmdFailure( + scopeCheck.Error, + scopeCheck.ErrorDetails, + stopwatch.ElapsedMilliseconds); + } + } + + Debug.Log($"CodeReload: Executing {commandName} command: {fullPath}, timeout: {timeout}ms, assemblyDir: {assemblyDir ?? "in-memory"}, pdb: {pdb}, interpreter: {useInterpreter}"); + + var task = InPlaceReloadProcessor.ProcessSourceFileAsync(fullPath, assemblyDir, pdb, useInterpreter); + task.Wait(); + var result = task.Result; + + stopwatch.Stop(); + + if (result.Success) + { + // Everything matches the compiled baseline: an honest no-op success, not + // "reload successful with 0 methods" against a null assembly name. Reverting + // stale overrides (the edit was undone) is part of the outcome — say so + // instead of unregistering silently. + if (result.AllUpToDate) + { + var upToDate = CodeReloadResponse.CmdSuccess( + string.Empty, + $"Up to date: all {result.UpToDateMethods.Count} [CodeReload] method(s) match the compiled baseline — nothing reloaded" + + (result.RevertedMethods.Count > 0 + ? $"; reverted {result.RevertedMethods.Count} stale override(s): {string.Join(", ", result.RevertedMethods)}" + : "") + ".", + result.RegisteredMethods, + stopwatch.ElapsedMilliseconds); + upToDate.Diagnostics = result.CompilationDiagnostics; + return upToDate; + } + + // "Compiled OK but bound nothing" is a failed reload in practice: the compile + // succeeded but every method was skipped downstream (e.g. an interpreter-unsupported + // construct, or no RuntimePipelineDriver registered the target). Surface the + // reasons from CompilationDiagnostics as a failure instead of a silent success. + if (result.RegisteredMethods.Count == 0 && result.ExtractedMethods.Count > 0) + { + var details = result.CompilationDiagnostics != null && result.CompilationDiagnostics.Count > 0 + ? "Compiled, but no methods were applied:\n- " + string.Join("\n- ", result.CompilationDiagnostics) + : "Compiled, but no methods were applied. Is the target component in the scene " + + "and in play mode (with the runtime Pipeline driver active)?"; + return CodeReloadResponse.CmdFailure( + "No Methods Applied", + details, + stopwatch.ElapsedMilliseconds, + result.CompilationDiagnostics); + } + + CodeReloadRegistry.InvokeReloadCallbacks(result.RegisteredMethods); + + var response = CodeReloadResponse.CmdSuccess( + result.AssemblyName, + $"In-place code reload successful: {result.AssemblyName} with {result.RegisteredMethods.Count} methods" + + (result.RevertedMethods.Count > 0 + ? $"; reverted {result.RevertedMethods.Count} stale override(s): {string.Join(", ", result.RevertedMethods)}" + : ""), + result.RegisteredMethods, + stopwatch.ElapsedMilliseconds); + // Surface partial-skip reasons (some methods bound, others skipped) on success too. + response.Diagnostics = result.CompilationDiagnostics; + return response; + } + + return CodeReloadResponse.CmdFailure( + "In-Place Reload Failed", + result.ErrorMessage ?? "In-place code reload processing failed", + stopwatch.ElapsedMilliseconds, + result.CompilationDiagnostics); + } + catch (Exception ex) + { + stopwatch.Stop(); + Debug.LogError($"CodeReload: {commandName} command failed: {ex.Message}"); + Debug.LogError($"CodeReload: Stack trace: {ex.StackTrace}"); + + return CodeReloadResponse.CmdFailure( + "Execution Failed", + ex.ToString(), + stopwatch.ElapsedMilliseconds); + } + } + + [CliCommand("cleanup_codereload", "Remove old code reload DLL versions and clear registry", MainThreadRequired = true, RuntimeOnly = true, Tags = new[] { "scripts/codereload" })] + public static CodeReloadResponse CleanupCodeReload( + [CliArg("assemblyDir", "Directory containing assemblies to cleanup", Required = true)] string assemblyDir, + [CliArg("force_domain_reload", "Force Unity domain reload after cleanup")] bool forceDomainReload = true) + { + var stopwatch = System.Diagnostics.Stopwatch.StartNew(); + + try + { + Debug.Log($"CodeReload: Executing cleanup_codereload command for directory: {assemblyDir}"); + + // Execute cleanup + var cleanupResult = CodeReloadCompiler.CleanupCodeReloadDlls(assemblyDir); + + stopwatch.Stop(); + + if (cleanupResult.Success) + { + var message = $"Cleanup successful: {cleanupResult.Message}"; + if (cleanupResult.DeletedFiles.Count > 0) + { + message += $" Files removed: {string.Join(", ", cleanupResult.DeletedFiles)}"; + } + + // Force domain reload if requested (interrupts gameplay but ensures clean state) + if (forceDomainReload && Application.isEditor) + { +#if UNITY_EDITOR + Debug.Log("CodeReload: Requesting Unity domain reload to clean memory state"); + UnityEditor.EditorUtility.RequestScriptReload(); + message += " Unity domain reload requested."; +#endif + } + + Debug.Log($"CodeReload: cleanup_codereload completed successfully in {stopwatch.ElapsedMilliseconds}ms"); + + return CodeReloadResponse.CmdSuccess( + "cleanup_completed", + message, + cleanupResult.DeletedFiles, + stopwatch.ElapsedMilliseconds); + } + else + { + return CodeReloadResponse.CmdFailure( + "Cleanup Failed", + cleanupResult.Message, + stopwatch.ElapsedMilliseconds); + } + } + catch (Exception ex) + { + stopwatch.Stop(); + Debug.LogError($"CodeReload: cleanup_codereload command failed: {ex.Message}"); + + return CodeReloadResponse.CmdFailure( + "Execution Failed", + ex.ToString(), + stopwatch.ElapsedMilliseconds); + } + } + + [CliCommand("codereload_status", "Show current code reload registry status and statistics", MainThreadRequired = true, RuntimeOnly = true, Tags = new[] { "scripts/codereload" })] + public static CodeReloadResponse CodeReloadStatus() + { + var stopwatch = System.Diagnostics.Stopwatch.StartNew(); + + try + { + // Get current registry stats + var stats = CodeReloadRegistry.GetStats(); + + stopwatch.Stop(); + + var statusMessage = $"Code Reload Status - " + + $"Reloadable Methods: {stats.ReloadableMethodCount}, " + + $"Active Overrides: {stats.ActiveOverrideCount}, " + + $"Loaded Types: {stats.LoadedTypeCount}"; + + Debug.Log($"CodeReload: {statusMessage}"); + + return CodeReloadResponse.CmdSuccess( + "status_retrieved", + statusMessage, + stats.ActiveOverrideIds, + stopwatch.ElapsedMilliseconds); + } + catch (Exception ex) + { + stopwatch.Stop(); + Debug.LogError($"CodeReload: codereload_status command failed: {ex.Message}"); + + return CodeReloadResponse.CmdFailure( + "Execution Failed", + ex.ToString(), + stopwatch.ElapsedMilliseconds); + } + } + + /// + /// Validate that a resolved file path lives inside one of the allowed project roots and + /// exists on disk. "In scope" means under the Assets folder or a loaded package's location. + /// The path is normalized (collapsing any .. segments) before the scope check, so a + /// path that escapes the allowed roots via traversal is rejected. A null or empty root set + /// matches nothing, so the path is rejected as out of scope. This is a security boundary — + /// it prevents files outside the project from being compiled and injected into the assembly. + /// + public static PathValidationResult ValidateReloadPath(string resolvedPath, System.Collections.Generic.IReadOnlyCollection allowedRoots) + { + if (string.IsNullOrWhiteSpace(resolvedPath)) + { + return PathValidationResult.Invalid("Bad Request", "Resolved file path is empty."); + } + + string fullPath; + try + { + fullPath = Path.GetFullPath(resolvedPath); + } + catch (Exception ex) + { + return PathValidationResult.Invalid("Bad Request", $"Invalid path: {ex.Message}"); + } + + var underAnyRoot = false; + if (allowedRoots != null) + { + foreach (var root in allowedRoots) + { + if (string.IsNullOrWhiteSpace(root)) + { + continue; + } + + string fullRoot; + try + { + fullRoot = Path.GetFullPath(root); + } + catch + { + continue; + } + + if (IsUnderDirectory(fullPath, fullRoot)) + { + underAnyRoot = true; + break; + } + } + } + + if (!underAnyRoot) + { + return PathValidationResult.Invalid( + "Out Of Project Scope", + $"Code reload only accepts files inside the project's baked roots (Assets/ or a loaded " + + $"package). '{fullPath}' is outside the project scope and will not be compiled."); + } + + if (!File.Exists(fullPath)) + { + return PathValidationResult.Invalid("File Not Found", $"Source file not found: {fullPath}"); + } + + return PathValidationResult.Valid(); + } + + /// + /// True when is contained within . + /// Both are expected to be normalized absolute paths. A trailing separator is appended to + /// the directory so that a sibling such as "AssetsExtra" is not treated as being under "Assets". + /// + private static bool IsUnderDirectory(string path, string directory) + { + var prefix = directory.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) + + Path.DirectorySeparatorChar; + + // Windows file systems are case-insensitive; Unix file systems are case-sensitive. + var comparison = Path.DirectorySeparatorChar == '\\' + ? StringComparison.OrdinalIgnoreCase + : StringComparison.Ordinal; + + return path.StartsWith(prefix, comparison); + } + + /// + /// Resolve source file path from various possible locations. + /// + private static string ResolveSourceFilePath(string filename) + { + if (Path.IsPathRooted(filename) && File.Exists(filename)) + { + return filename; + } + + var potentialPaths = new[] + { + Path.Combine("Assets", filename), + Path.Combine("Assets", "Scripts", filename), + filename // Project root + }; + + foreach (var path in potentialPaths) + { + if (File.Exists(path)) + { + return Path.GetFullPath(path); + } + } + + return null; + } + + } + + /// + /// Response model for code reload CLI commands. + /// Provides consistent response format for all code reload operations. + /// + class CodeReloadResponse : CommandExecutionResponse + { + /// + /// Assembly name or operation identifier for successful operations. + /// + public string AssemblyName { get; set; } + + /// + /// List of registered method IDs or files processed. + /// + public System.Collections.Generic.List Items { get; set; } = new System.Collections.Generic.List(); + + /// + /// Compilation or processing diagnostics. + /// + public System.Collections.Generic.List Diagnostics { get; set; } = new System.Collections.Generic.List(); + + /// + /// Create a successful code reload response. + /// + public static CodeReloadResponse CmdSuccess(string assemblyName, string message, System.Collections.Generic.List items, long executionTimeMs) + { + return new CodeReloadResponse + { + Success = true, + AssemblyName = assemblyName, + Message = message, + Items = items ?? new System.Collections.Generic.List(), + ExecutionTimeMs = executionTimeMs, + ExecutedAt = DateTime.UtcNow + }; + } + + /// + /// Create a failed code reload response. + /// + public static CodeReloadResponse CmdFailure(string error, string errorDetails, long executionTimeMs, System.Collections.Generic.List diagnostics = null) + { + return new CodeReloadResponse + { + Success = false, + Error = error, + ErrorDetails = errorDetails, + ExecutionTimeMs = executionTimeMs, + Diagnostics = diagnostics ?? new System.Collections.Generic.List(), + ExecutedAt = DateTime.UtcNow + }; + } + } + + /// + /// Result of validating a code reload source path. is a short category and + /// the human-readable explanation, matching the shape consumed by + /// . + /// + class PathValidationResult + { + public bool IsValid { get; private set; } + public string Error { get; private set; } + public string ErrorDetails { get; private set; } + + public static PathValidationResult Valid() + { + return new PathValidationResult { IsValid = true }; + } + + public static PathValidationResult Invalid(string error, string errorDetails) + { + return new PathValidationResult { IsValid = false, Error = error, ErrorDetails = errorDetails }; + } + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Commands/CodeReloadCommands.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/CodeReloadCommands.cs.meta new file mode 100644 index 0000000..74077bc --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/CodeReloadCommands.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 33ec6e594cb07434cb51fbc751ca37f2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Commands/ConsoleCommand.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/ConsoleCommand.cs new file mode 100644 index 0000000..1ef3856 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/ConsoleCommand.cs @@ -0,0 +1,118 @@ +using System; +using System.Reflection; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Console; +using Unity.Pipeline.Models; + +namespace Unity.Pipeline.Runtime.Commands +{ + /// + /// The console commands: console to read captured output, console_status for its + /// counters alone, and clear_console to empty it. console backs the CLI's + /// console [--tail N] [--level log|warn|error] [--follow]. + /// + /// All three live in the runtime assembly, so they are available from both the Editor and player + /// builds — console capture is driven by , which runs in both + /// contexts. + /// + /// The package has no streaming transport (the HTTP server handles one request at a time), so + /// --follow is realized client-side: the CLI polls this command, prints new entries, and + /// passes the returned back as since on the next + /// call. The flag mapping is: + /// --tail N -> tail + /// --level X -> level (minimum severity threshold) + /// --follow -> repeated calls with since = previous cursor and since_session = previous session + /// + /// Reads only the in-memory buffer and the last ground-truth sample (no Unity main-thread + /// APIs), so it is marked MainThreadRequired = false and keeps answering while the + /// Editor is blocked compiling or importing — which is when a client most needs it. + /// + static class ConsoleCommand + { + /// Default number of entries returned when tail is not supplied. + public const int DefaultTail = 100; + + [CliCommand("console", "Get captured Unity console output (Editor or Player; supports tail, level filtering, and follow via a cursor)", MainThreadRequired = false, Tags = new[] { "observability/console" })] + public static ConsoleLogResponse GetConsole( + [CliArg("tail", "Maximum number of most-recent entries to return")] int tail = DefaultTail, + [CliArg("level", "Minimum severity to include: log | warn | error")] string level = ConsoleLogBuffer.LevelLog, + [CliArg("since", "Cursor: only return entries newer than this seq. Use the 'cursor' from a previous response to follow.")] long since = -1, + [CliArg("since_session", "Session the 'since' cursor came from: pass the 'session' from a previous response. A cursor from another session is refused and the tail returned with reset=true.")] string since_session = null) + { + // Guard against nonsensical tail values; <= 0 would otherwise mean "unlimited" in the + // buffer, which is not what a caller passing e.g. --tail 0 expects. + if (tail <= 0) + tail = DefaultTail; + + var minSeverity = ConsoleLogBuffer.SeverityFromLevelName(level); + var response = ConsoleLogCapture.Buffer.Query(since, tail, minSeverity, since_session); + response.GroundTruth = ReadGroundTruth(); + return response; + } + + [CliCommand("console_status", "Console ground truth and buffer counters without pulling entries: compile-failure flag, Editor console counts, and the buffer's retained counts and cursor.", MainThreadRequired = false, Tags = new[] { "observability/console" })] + public static ConsoleLogResponse GetConsoleStatus() + { + // Same shape as `console` with no entries, so a client polling during a long compile + // gets the counters and the compile-failure flag without paying for the payload. + var response = ConsoleLogCapture.Buffer.Stats(); + response.GroundTruth = ReadGroundTruth(); + return response; + } + + [CliCommand("clear_console", "Clear the captured log buffer and the Unity Editor console.", Tags = new[] { "observability/console" })] + public static object ClearConsole() + { + // Clearing keeps the sequence counter, so a client following the console sees dropped=true + // on its next poll rather than silently skipping the window that was cleared. + ConsoleLogCapture.Buffer.Clear(); + + // Best-effort: also clear Unity's own console window. UnityEditor.LogEntries is internal, + // so reach it by name and swallow any failure (the API is not part of the public contract). + // Resolving the type by string is also what keeps this command in the runtime assembly: + // there is no compile-time UnityEditor dependency, and in a player GetType returns null so + // the chain no-ops and only the captured buffer is cleared. + // LogEntries.Clear is a static, non-public method, so include NonPublic in the binding + // flags — GetMethod("Clear") with no flags only finds public methods and would silently + // return null. + // Note it leaves editor compile errors standing: those are logged as sticky entries, which + // Unity's Clear skips, and only a completed compile removes them. + try + { + Type.GetType("UnityEditor.LogEntries,UnityEditor") + ?.GetMethod("Clear", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static) + ?.Invoke(null, null); + } + catch + { + // Ignore — clearing the Editor console is auxiliary; the buffer is already cleared. + } + + return new { cleared = true }; + } + + /// + /// A copy of the last ground-truth sample with its age filled in. Copied rather than + /// returned directly so the published snapshot stays immutable and shared between callers. + /// + static ConsoleGroundTruth ReadGroundTruth() + { + var sample = ConsoleLogCapture.GroundTruth; + if (sample == null) + return null; + + var ageMs = (long)(DateTime.UtcNow - sample.SampledUtc).TotalMilliseconds; + return new ConsoleGroundTruth + { + SampledUtc = sample.SampledUtc, + AgeMs = ageMs < 0 ? 0 : ageMs, + CompilationFailed = sample.CompilationFailed, + Compiling = sample.Compiling, + ConsoleErrors = sample.ConsoleErrors, + ConsoleWarnings = sample.ConsoleWarnings, + ConsoleLogs = sample.ConsoleLogs, + Seeded = sample.Seeded + }; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Commands/ConsoleCommand.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/ConsoleCommand.cs.meta new file mode 100644 index 0000000..597d4a8 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/ConsoleCommand.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 92be7cfe398a263a7b06a4a8a00a802c diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Commands/EvalTelemetryCommand.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/EvalTelemetryCommand.cs new file mode 100644 index 0000000..2b96be2 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/EvalTelemetryCommand.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using System.Linq; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Telemetry; + +namespace Unity.Pipeline.Runtime.Commands +{ + /// + /// Read-back command for the local eval-usage telemetry (AUTHAPI-29). Aggregates + /// Library/Pipeline/eval-usage.jsonl — merged with the rotated eval-usage.old.jsonl, + /// so the report sees the full retained history (~2× the size cap) — into a ranked report: API + /// fingerprint frequency, one-liner vs multi-statement split, error rate. It cross-references the + /// fingerprints against the live command catalog to flag patterns already coverable by an existing + /// command and the top uncovered patterns. This is the artifact that steers eval-displacement + /// backlog triage (AUTHAPI-24). Read-only and off the main thread, so it stays servable even while + /// the Editor is settling. The ranked lists are capped by top; the report's + /// distinctFingerprints total makes any truncation visible. + /// + static class EvalTelemetryCommand + { + [CliCommand("report_evals", + "Aggregate local eval-usage telemetry into a ranked report: API fingerprint frequency, one-liner percentage, error rate, and command-coverage suggestions.", + MainThreadRequired = false, + Tags = new[] { "observability/eval_usage" })] + public static EvalUsageReport ReportEvals( + [CliArg("top", "Maximum entries in each ranked list (API fingerprints, and uncovered patterns suggested as commands). Accepted range: 0 or greater; negative values fall back to the default (50).")] int top = 50) + { + // Clamp, don't reject: a negative cap has no meaning, so fall back to the default rather + // than fail the command or return an unbounded report. + if (top < 0) + top = EvalUsageAggregator.DefaultFingerprintLimit; + + var records = EvalUsageTelemetry.ReadRecords(EvalUsageTelemetry.ResolveDirectory()); + + // Cross-reference against the live catalog. Discovery is already warm (the server queried + // it to route this very request), so this reads the cache and touches no main-thread API. + var availableCommands = new HashSet( + CommandRegistry.DiscoverCommands().Select(c => c.Name)); + + return EvalUsageAggregator.Build(records, availableCommands, topUncoveredLimit: top, fingerprintLimit: top); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Commands/EvalTelemetryCommand.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/EvalTelemetryCommand.cs.meta new file mode 100644 index 0000000..529634b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/EvalTelemetryCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7ecb5f9bf7384f0186d1e26cf4a355a3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeApplicationCommand.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeApplicationCommand.cs new file mode 100644 index 0000000..3fc4aeb --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeApplicationCommand.cs @@ -0,0 +1,89 @@ +using Unity.Pipeline.Commands; +using UnityEngine; + +namespace Unity.Pipeline.Runtime.Commands +{ + /// + /// Runtime application control commands for Unity Player builds. + /// Provides basic application lifecycle and performance control. + /// + static class RuntimeApplicationCommand + { + [CliCommand("quit", "Gracefully quit the Unity application", MainThreadRequired = true, RuntimeOnly = true, Tags = new[] { "runtime/application" })] + public static string QuitApplication( + [CliArg("exitCode", "Exit code for the application")] int exitCode = 0) + { + // Schedule quit on next frame to allow HTTP response to be sent + var quitObject = new GameObject("PipelineQuitScheduler"); + var quitScheduler = quitObject.AddComponent(); + quitScheduler.Initialize(exitCode); + + return $"Application quit scheduled with exit code {exitCode}"; + } + + [CliCommand("set_target_framerate", "Set the target frame rate for the application", MainThreadRequired = true, RuntimeOnly = true, Tags = new[] { "runtime/application" })] + public static string SetTargetFrameRate( + [CliArg("frameRate", "Target frame rate (-1 for platform default, 0 for unlimited)", Required = true)] int frameRate) + { + var previousFrameRate = Application.targetFrameRate; + Application.targetFrameRate = frameRate; + + var frameRateDescription = frameRate switch + { + -1 => "platform default", + 0 => "unlimited (VSync)", + _ => $"{frameRate} FPS" + }; + + return $"Target frame rate set to {frameRateDescription} (was {previousFrameRate})"; + } + + [CliCommand("set_timescale", "Set the time scale for the application", MainThreadRequired = true, RuntimeOnly = true, Tags = new[] { "runtime/application" })] + public static string SetTimeScale( + [CliArg("scale", "Time scale multiplier (0.0 to pause, 1.0 for normal speed)", Required = true)] float scale) + { + if (scale < 0f) + { + return "Error: Time scale cannot be negative"; + } + + var previousScale = Time.timeScale; + Time.timeScale = scale; + + var scaleDescription = scale switch + { + 0f => "paused", + 1f => "normal speed", + _ => $"{scale}x speed" + }; + + return $"Time scale set to {scaleDescription} (was {previousScale}x)"; + } + + /// + /// MonoBehaviour to handle delayed application quit. + /// Allows HTTP response to be sent before application terminates. + /// + private class QuitScheduler : MonoBehaviour + { + private int m_ExitCode; + private float m_QuitTime; + + public void Initialize(int exitCode) + { + m_ExitCode = exitCode; + m_QuitTime = Time.realtimeSinceStartup + 0.1f; // 100ms delay + DontDestroyOnLoad(gameObject); + } + + private void Update() + { + if (Time.realtimeSinceStartup >= m_QuitTime) + { + Debug.Log($"Pipeline: Quitting application with exit code {m_ExitCode}"); + Application.Quit(m_ExitCode); + } + } + } + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeApplicationCommand.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeApplicationCommand.cs.meta new file mode 100644 index 0000000..d952319 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeApplicationCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e508f97d464c66347816d5281c68e276 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeInputCommand.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeInputCommand.cs new file mode 100644 index 0000000..a4d1375 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeInputCommand.cs @@ -0,0 +1,182 @@ +using System; +using Unity.Pipeline.Commands; +using UnityEngine; +#if ENABLE_INPUT_SYSTEM +using UnityEngine.InputSystem; +using UnityEngine.InputSystem.Controls; +using UnityEngine.InputSystem.LowLevel; +#endif + +namespace Unity.Pipeline.Runtime.Commands +{ + /// + /// + /// Input-simulation commands that drive a running Player by injecting synthetic input — the enabler + /// for automated play-testing (CLI-208). Keyboard and pointer events are injected through the Input + /// System (InputSystem.QueueEvent with a state event captured from the live device), which also + /// drives uGUI / UI Toolkit through the Input System UI module — so a simulated pointer click lands on + /// on-screen UI the same way a real one does. + /// + /// + /// Input stack: device injection requires the Input System package to be present and active + /// (ENABLE_INPUT_SYSTEM). Legacy UnityEngine.Input is poll-only and exposes no injection + /// API, so it is intentionally not supported; when the Input System is absent these commands report an + /// "unavailable" result rather than silently no-op'ing. + /// + /// Safety: these are write/destructive commands. The package has no safety-policy gate yet + /// (CAT-2509 is not implemented), so they follow the existing unguarded write-command model (cf. + /// set_target_framerate). TODO(CAT-2509): route input commands through the safety policy when it + /// lands. + /// + static class RuntimeInputCommand + { + [CliCommand("simulate_key", "Simulate a keyboard key event (Input System). Drives the running app.", + MainThreadRequired = true, RuntimeOnly = true, + Tags = new[] { "runtime/input" })] + public static InputSimulationResponse SimulateKey( + [CliArg("key", "Input System Key name, e.g. Space, W, Enter, LeftArrow", Required = true)] string key, + [CliArg("action", "down | up | press (down+up). Default: press")] string action = "press") + { +#if ENABLE_INPUT_SYSTEM + var keyboard = Keyboard.current; + if (keyboard == null) + return InputSimulationResponse.Fail("simulate_key", "No keyboard device is present."); + + if (!Enum.TryParse(key, ignoreCase: true, out var parsedKey) || parsedKey == Key.None) + return InputSimulationResponse.Fail("simulate_key", $"Unknown key '{key}'. Use an Input System Key name (e.g. Space, W, Enter)."); + + var control = keyboard[parsedKey]; + var act = Normalize(action); + switch (act) + { + case "down": + QueueButton(control, true); + break; + case "up": + QueueButton(control, false); + break; + case "press": + QueueButton(control, true); + QueueButton(control, false); + break; + default: + return InputSimulationResponse.Fail("simulate_key", $"Unknown action '{action}'. Use down | up | press."); + } + + // Flush queued events so the effect is observable synchronously to the caller. + InputSystem.Update(); + return InputSimulationResponse.Ok("simulate_key", $"key={parsedKey} action={act}"); +#else + return InputSimulationResponse.Unavailable("simulate_key"); +#endif + } + + [CliCommand("simulate_pointer", "Simulate a mouse/pointer event at screen coordinates (Input System).", + MainThreadRequired = true, RuntimeOnly = true, + Tags = new[] { "runtime/input" })] + public static InputSimulationResponse SimulatePointer( + [CliArg("x", "Screen X in pixels (origin bottom-left)", Required = true)] float x, + [CliArg("y", "Screen Y in pixels (origin bottom-left)", Required = true)] float y, + [CliArg("action", "move | down | up | click (down+up). Default: click")] string action = "click", + [CliArg("button", "left | right | middle. Default: left")] string button = "left") + { +#if ENABLE_INPUT_SYSTEM + var mouse = Mouse.current; + if (mouse == null) + return InputSimulationResponse.Fail("simulate_pointer", "No mouse/pointer device is present."); + + var position = new Vector2(x, y); + var act = Normalize(action); + + ButtonControl btn; + switch (Normalize(button)) + { + case "left": btn = mouse.leftButton; break; + case "right": btn = mouse.rightButton; break; + case "middle": btn = mouse.middleButton; break; + default: + return InputSimulationResponse.Fail("simulate_pointer", $"Unknown button '{button}'. Use left | right | middle."); + } + + switch (act) + { + case "move": + QueuePointer(mouse, position, null, false); + break; + case "down": + QueuePointer(mouse, position, btn, true); + break; + case "up": + QueuePointer(mouse, position, btn, false); + break; + case "click": + QueuePointer(mouse, position, btn, true); + QueuePointer(mouse, position, btn, false); + break; + default: + return InputSimulationResponse.Fail("simulate_pointer", $"Unknown action '{action}'. Use move | down | up | click."); + } + + InputSystem.Update(); + return InputSimulationResponse.Ok("simulate_pointer", $"pos=({x},{y}) action={act} button={Normalize(button)}"); +#else + return InputSimulationResponse.Unavailable("simulate_pointer"); +#endif + } + +#if ENABLE_INPUT_SYSTEM + // Capture the device's current state into a state event, override a single control, then queue it. + // Capturing current state (rather than sending a zeroed full state) preserves any other controls + // that are already held — so chained down/up calls compose correctly. + private static void QueueButton(InputControl control, bool pressed) + { + using (StateEvent.From(control.device, out var eventPtr)) + { + control.WriteValueIntoEvent(pressed ? 1f : 0f, eventPtr); + InputSystem.QueueEvent(eventPtr); + } + } + + private static void QueuePointer(Mouse mouse, Vector2 position, ButtonControl button, bool pressed) + { + using (StateEvent.From(mouse, out var eventPtr)) + { + mouse.position.WriteValueIntoEvent(position, eventPtr); + if (button != null) + button.WriteValueIntoEvent(pressed ? 1f : 0f, eventPtr); + InputSystem.QueueEvent(eventPtr); + } + } +#endif + + private static string Normalize(string s) => (s ?? string.Empty).Trim().ToLowerInvariant(); + } + + /// + /// Structured result for an input-simulation command: whether the event was injected, and a short + /// human-readable detail (or an error / unavailable reason). + /// + [Serializable] + class InputSimulationResponse + { + public bool Success { get; set; } + public string Command { get; set; } + public string Detail { get; set; } + public string Error { get; set; } + + public static InputSimulationResponse Ok(string command, string detail) => + new InputSimulationResponse { Success = true, Command = command, Detail = detail }; + + public static InputSimulationResponse Fail(string command, string error) => + new InputSimulationResponse { Success = false, Command = command, Error = error }; + + public static InputSimulationResponse Unavailable(string command) => + new InputSimulationResponse + { + Success = false, + Command = command, + Error = "Input simulation requires the Input System package to be present and active " + + "(ENABLE_INPUT_SYSTEM). Legacy input injection is not supported." + }; + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeInputCommand.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeInputCommand.cs.meta new file mode 100644 index 0000000..788ed9d --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeInputCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fa9e0d957acd4b1293e4d40e83bca73f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeLogCommand.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeLogCommand.cs new file mode 100644 index 0000000..72cd1b9 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeLogCommand.cs @@ -0,0 +1,49 @@ +using Unity.Pipeline.Commands; +using UnityEngine; + +namespace Unity.Pipeline.Runtime.Commands +{ + /// + /// Runtime logging commands for Unity Player builds. + /// Provides console logging capabilities from CLI. + /// + static class RuntimeLogCommand + { + [CliCommand("log", "Write a message to Unity console", MainThreadRequired = true, RuntimeOnly = true, Tags = new[] { "observability/console" })] + public static string LogMessage( + [CliArg("message", "Message to log to console", Required = true)] string message, + [CliArg("level", "Log level: info, warning, error")] string level = "info") + { + if (string.IsNullOrWhiteSpace(message)) + { + return "Error: Message cannot be empty"; + } + + Debug.developerConsoleVisible = false; + var logLevel = level?.ToLowerInvariant() ?? "info"; + + switch (logLevel) + { + case "info": + case "log": + Debug.Log($"[Pipeline] {message}"); + return $"Logged info message: {message}"; + + case "warning": + case "warn": + Debug.LogWarning($"[Pipeline] {message}"); + return $"Logged warning message: {message}"; + + case "error": + case "err": + Debug.LogError($"[Pipeline] {message}"); + return $"Logged error message: {message}"; + + default: + Debug.LogWarning($"[Pipeline] Unknown log level '{level}', defaulting to info: {message}"); + Debug.Log($"[Pipeline] {message}"); + return $"Logged message with default level: {message}"; + } + } + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeLogCommand.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeLogCommand.cs.meta new file mode 100644 index 0000000..876ab94 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeLogCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8e82ea92b18fc264faf68d664212e013 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeStatusCommand.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeStatusCommand.cs new file mode 100644 index 0000000..64aa259 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeStatusCommand.cs @@ -0,0 +1,217 @@ +using System; +using System.Collections.Generic; +using Unity.Pipeline; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Runtime.Telemetry; +using UnityEngine; +using UnityEngine.Profiling; + +namespace Unity.Pipeline.Runtime.Commands +{ + /// + /// Runtime status information for Unity Player builds. + /// Provides Player-appropriate status without Editor-specific APIs. + /// + static class RuntimeStatusCommand + { + [CliCommand("runtime_status", "Get comprehensive runtime application status", MainThreadRequired = true, RuntimeOnly = true, Tags = new[] { "runtime" })] + public static RuntimeStatusResponse GetRuntimeStatus() + { + try + { + return new RuntimeStatusResponse + { + // Application info + UnityVersion = Application.unityVersion, + Platform = Application.platform.ToString(), + BuildGuid = Application.buildGUID, + Version = Application.version, + + // Runtime state + IsPlaying = true, // Always true in Player builds + TargetFrameRate = Application.targetFrameRate, + TimeScale = Time.timeScale, + RealTimeSinceStartup = Time.realtimeSinceStartup, + + // Performance info + FrameCount = Time.frameCount, + LoadedLevelName = UnityEngine.SceneManagement.SceneManager.GetActiveScene().name, + LoadedLevelBuildIndex = UnityEngine.SceneManagement.SceneManager.GetActiveScene().buildIndex, + + // Live performance telemetry (fps, frame time, memory, profiler counters) + Performance = BuildPerformanceTelemetry(), + + // The driver's actual state and in-effect config — not just what Project + // Settings currently says, which can differ (live JSON in the Editor vs. the + // snapshot frozen into the Player at build time). + PipelineDriver = BuildDriverStatus(), + + // Timestamp + Timestamp = DateTime.UtcNow + }; + } + catch (Exception ex) + { + Debug.LogError($"Pipeline: Runtime status command failed: {ex.Message}"); + throw; + } + } + + /// + /// Null when no driver was ever bootstrapped (e.g. enableInBuilds was false), otherwise the + /// driver's actual running state and the config values presently governing it. + /// maxWorkItemsPerFrame is read via CurrentMaxWorkItemsPerFrame rather than the config + /// directly, since that field alone can be tuned live after the driver started. + /// + private static RuntimePipelineDriverStatus BuildDriverStatus() + { + var driver = RuntimePipelineBootstrap.Instance; + if (driver == null) + return null; + + var config = driver.Config; + return new RuntimePipelineDriverStatus + { + IsServerRunning = driver.IsServerRunning, + ActualPort = driver.ActualPort, + EnableInBuilds = config != null && config.enableInBuilds, + RequestTimeoutMs = config != null ? config.requestTimeoutMs : 0, + EnableAuditLogging = config != null && config.enableAuditLogging, + AutoStart = config != null && config.autoStart, + MaxWorkItemsPerFrame = driver.CurrentMaxWorkItemsPerFrame + }; + } + + /// + /// Assemble the live performance section from two independent sources: + /// the per-frame (fps / frame time / profiler counters), which only + /// exists while a is feeding it, and the Profiler memory APIs, + /// which can be read on demand at any time. Frame-stat fields stay at their defaults (and + /// stays false) when no sampler is + /// running — e.g. in EditMode tests — so a missing sampler degrades gracefully rather than throwing. + /// + private static RuntimePerformanceTelemetry BuildPerformanceTelemetry() + { + var perf = new RuntimePerformanceTelemetry(); + + var sampler = FrameStatsSampler.Shared; + if (sampler != null) + { + var snap = sampler.GetSnapshot(); + perf.FrameStatsAvailable = snap.Available; + perf.SampleWindow = snap.SampleWindow; + perf.Fps = snap.Fps; + perf.AverageFrameTimeMs = snap.AverageFrameTimeMs; + perf.MinFrameTimeMs = snap.MinFrameTimeMs; + perf.MaxFrameTimeMs = snap.MaxFrameTimeMs; + perf.LastFrameTimeMs = snap.LastFrameTimeMs; + perf.GpuTimingAvailable = snap.GpuTimingAvailable; + perf.CpuFrameTimeMs = snap.CpuFrameTimeMs; + perf.GpuFrameTimeMs = snap.GpuFrameTimeMs; + perf.Counters = snap.Counters; + } + else + { + perf.Counters = new Dictionary(); + } + + // Memory is sampled directly (no per-frame accumulation needed). These return 0 in a + // non-development build where the profiler is stripped, which is reported faithfully. + perf.TotalAllocatedMemory = Profiler.GetTotalAllocatedMemoryLong(); + perf.TotalReservedMemory = Profiler.GetTotalReservedMemoryLong(); + perf.MonoUsedSize = Profiler.GetMonoUsedSizeLong(); + perf.MonoHeapSize = Profiler.GetMonoHeapSizeLong(); + perf.GcMemory = GC.GetTotalMemory(false); + + return perf; + } + } + + /// + /// Response model for runtime status information. + /// + [Serializable] + class RuntimeStatusResponse + { + // Application Information + public string UnityVersion { get; set; } + public string Platform { get; set; } + public string BuildGuid { get; set; } + public string Version { get; set; } + + // Runtime State + public bool IsPlaying { get; set; } // Always true for Player builds + public int TargetFrameRate { get; set; } + public float TimeScale { get; set; } + public float RealTimeSinceStartup { get; set; } + + // Performance Information + public int FrameCount { get; set; } + public string LoadedLevelName { get; set; } + public int LoadedLevelBuildIndex { get; set; } + + // Live performance telemetry + public RuntimePerformanceTelemetry Performance { get; set; } + + // The runtime Pipeline driver's actual state, or null if none was ever bootstrapped. + public RuntimePipelineDriverStatus PipelineDriver { get; set; } + + // Metadata + public DateTime Timestamp { get; set; } + } + + /// + /// The runtime Pipeline driver's actual state: whether its server is running, the port it's + /// actually on, and the config values presently governing it. Distinct from what Project + /// Settings > Pipeline > Runtime currently shows — that's live-editable in the Editor, while a + /// running driver is working from whatever it was initialized with (a Player's is additionally + /// frozen at build time). This is the authoritative "what's actually happening right now" view. + /// + [Serializable] + class RuntimePipelineDriverStatus + { + public bool IsServerRunning { get; set; } + public int ActualPort { get; set; } + public bool EnableInBuilds { get; set; } + public int RequestTimeoutMs { get; set; } + public bool EnableAuditLogging { get; set; } + public bool AutoStart { get; set; } + + /// The value actually governing the dispatcher right now — see RuntimePipelineDriver.CurrentMaxWorkItemsPerFrame. + public int MaxWorkItemsPerFrame { get; set; } + } + + /// + /// Live performance telemetry for a running Player: rolling fps / frame-time statistics, optional + /// CPU/GPU frame timing, memory usage, and a map of profiler counters. Frame-stat and counter fields + /// are populated from the per-frame ; memory fields are read on demand. + /// + [Serializable] + class RuntimePerformanceTelemetry + { + // Frame timing — sampled over a rolling window by the RuntimePipelineDriver. + /// False when no sampler is running; the fps / frame-time fields below are then meaningless. + public bool FrameStatsAvailable { get; set; } + public int SampleWindow { get; set; } + public float Fps { get; set; } + public float AverageFrameTimeMs { get; set; } + public float MinFrameTimeMs { get; set; } + public float MaxFrameTimeMs { get; set; } + public float LastFrameTimeMs { get; set; } + + // CPU/GPU frame timing via FrameTimingManager (not available on every platform). + public bool GpuTimingAvailable { get; set; } + public double CpuFrameTimeMs { get; set; } + public double GpuFrameTimeMs { get; set; } + + // Memory (bytes) via the Profiler API; 0 when the profiler is stripped (non-development build). + public long TotalAllocatedMemory { get; set; } + public long TotalReservedMemory { get; set; } + public long MonoUsedSize { get; set; } + public long MonoHeapSize { get; set; } + public long GcMemory { get; set; } + + // Profiler counters by reported name (e.g. DrawCalls, Triangles, GcAllocInFrame). + public Dictionary Counters { get; set; } + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeStatusCommand.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeStatusCommand.cs.meta new file mode 100644 index 0000000..3ae7365 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/RuntimeStatusCommand.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 846a260c41f6d8f4583f1473632c1d62 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Commands/VisualElementCaptureSupport.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/VisualElementCaptureSupport.cs new file mode 100644 index 0000000..e44fda3 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/VisualElementCaptureSupport.cs @@ -0,0 +1,444 @@ +#if UNITY_6000_7_OR_NEWER +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Text; +using Newtonsoft.Json; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.UIElements; +using Object = UnityEngine.Object; + +namespace Unity.Pipeline.Runtime.Commands +{ + /// + /// Shared, runtime-safe helpers behind the visual-element capture commands + /// (capture_editor_element and capture_runtime_element). Lives in the runtime + /// assembly with no UnityEditor dependency so both the Editor command and the + /// player-side runtime command can use it. + /// + /// Capture uses (runtime + /// module) and encodes the PNG here, rather than the editor-only + /// VisualElementCaptureEditorExtensions.CaptureToPNG, so the same path works in a Player. + /// + /// Element selection maps a small USS-like selector string onto UQuery's public + /// (the engine's USS string parser is internal). Supported: + /// descendant (space) and child (>) combinators; each simple part is + /// Type#name.class1.class2 (any subset); optional pseudo-state suffixes + /// :checked :hover :focus :active :enabled :disabled and :not(<state>). + /// + static class VisualElementCaptureSupport + { + /// + /// Returns a failure response when no GPU is available (batchmode/headless), where a capture + /// would read back a blank image; otherwise returns null (capture may proceed). + /// + public static CaptureElementResponse GpuUnavailableResponse() + { + if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.Null) + return CaptureElementResponse.Fail("No GPU available (batchmode/headless); cannot capture."); + return null; + } + + /// + /// Resolve the first under matching + /// , or null if the selector is empty/invalid or nothing matches. + /// + public static VisualElement ResolveElement(VisualElement root, string selector) + { + if (root == null || string.IsNullOrWhiteSpace(selector)) + return null; + + if (!TryBuildQuery(root, selector, out var query)) + return null; + + return query.First(); + } + + /// + /// Resolve the selector against each root in order, returning the first match (and the root + /// it was found under via ), or null if none match. + /// + public static VisualElement ResolveElement(IEnumerable roots, string selector, + out VisualElement matchedRoot) + { + matchedRoot = null; + if (roots == null) + return null; + + foreach (var root in roots) + { + var element = ResolveElement(root, selector); + if (element != null) + { + matchedRoot = root; + return element; + } + } + + return null; + } + + /// + /// Capture to PNG bytes at its own pixel size. Restores the active + /// RenderTexture and releases all temporaries so the capture leaves no global render state. + /// Throws for camera-drawn (world-space) or detached + /// panels (surfaced from ). + /// + public static byte[] CaptureElementToPng(VisualElement element, out int width, out int height) + { + if (element == null) + throw new ArgumentNullException(nameof(element)); + + var rt = element.CaptureToRenderTexture(); + var prevActive = RenderTexture.active; + Texture2D tex = null; + try + { + width = rt.width; + height = rt.height; + + RenderTexture.active = rt; + tex = new Texture2D(rt.width, rt.height, TextureFormat.RGBA32, false); + tex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0, false); + tex.Apply(false, false); + return tex.EncodeToPNG(); + } + finally + { + RenderTexture.active = prevActive; + rt.Release(); + DestroyObject(rt); + if (tex != null) + DestroyObject(tex); + } + } + + /// + /// Resolve the output path. An explicit rooted path is used as-is; an explicit relative path + /// is resolved against ; an empty path produces a + /// timestamped <prefix>_yyyyMMdd_HHmmss_fff.png file under + /// . + /// + public static string ResolveOutputPath(string output, string relativeBaseDir, string defaultDir, string prefix) + { + if (!string.IsNullOrWhiteSpace(output)) + { + return Path.IsPathRooted(output) + ? output + : Path.GetFullPath(Path.Combine(relativeBaseDir, output)); + } + + var stamp = DateTime.Now.ToString("yyyyMMdd_HHmmss_fff", CultureInfo.InvariantCulture); + return Path.Combine(defaultDir, $"{prefix}_{stamp}.png"); + } + + /// Write PNG bytes to , creating the directory if needed. + public static void WritePng(string path, byte[] png) + { + var dir = Path.GetDirectoryName(path); + if (!string.IsNullOrEmpty(dir)) + Directory.CreateDirectory(dir); + File.WriteAllBytes(path, png); + } + + /// + /// Capture the resolved , write the PNG to disk, and build a + /// populated success response (or a failure response if the panel cannot be captured). This + /// is the shared tail both commands run once they have an element + a panel root. + /// + public static CaptureElementResponse CaptureAndRespond(VisualElement element, string selector, + string source, string output, string relativeBaseDir, string defaultDir, string prefix) + { + var gpuGuard = GpuUnavailableResponse(); + if (gpuGuard != null) + return gpuGuard; + + try + { + var png = CaptureElementToPng(element, out var width, out var height); + var path = ResolveOutputPath(output, relativeBaseDir, defaultDir, prefix); + WritePng(path, png); + + return new CaptureElementResponse + { + Success = true, + Selector = selector, + Source = source, + Path = path, + Width = width, + Height = height, + Encoding = "png", + Base64 = Convert.ToBase64String(png), + Bytes = png.Length, + Message = $"Captured {source} to {path}" + }; + } + catch (InvalidOperationException ex) + { + // The capture API throws this for camera-drawn (world-space) or detached panels. + return CaptureElementResponse.Fail(ex.Message); + } + catch (Exception ex) + { + return CaptureElementResponse.Fail($"Failed to capture '{selector}' from {source}: {ex.Message}"); + } + } + + // ---- Selector parsing ------------------------------------------------------------------- + + // Build a UQuery from the selector, mapping tokens onto the public UQueryBuilder fluent API. + static bool TryBuildQuery(VisualElement root, string selector, out UQueryBuilder query) + { + query = root.Query(); + + var parts = Tokenize(selector); + if (parts.Count == 0) + return false; + + for (int i = 0; i < parts.Count; i++) + { + var (isChild, partStr) = parts[i]; + if (!TryParsePart(partStr, out var part)) + return false; + + if (i == 0) + query = query.Name(part.Name); + else + query = isChild + ? query.Children(part.Name) + : query.Descendents(part.Name); + + foreach (var cls in part.Classes) + query = query.Class(cls); + + if (part.Type != null) + { + var typeName = part.Type; + query = query.Where(e => TypeNameMatches(e, typeName)); + } + + foreach (var pseudo in part.Pseudos) + { + if (!TryApplyPseudo(ref query, pseudo.Name, pseudo.Negate)) + return false; + } + } + + return true; + } + + // Split a selector into simple parts, flagging each with whether it follows a '>' (child) + // combinator. Whitespace separates descendant parts; '>' is treated as its own token. + static List<(bool isChild, string part)> Tokenize(string selector) + { + var result = new List<(bool, string)>(); + var raw = selector.Replace(">", " > ") + .Split((char[])null, StringSplitOptions.RemoveEmptyEntries); + + bool nextIsChild = false; + foreach (var token in raw) + { + if (token == ">") + { + nextIsChild = true; + continue; + } + + result.Add((nextIsChild, token)); + nextIsChild = false; + } + + return result; + } + + class SelectorPart + { + public string Type; + public string Name; + public readonly List Classes = new List(); + public readonly List<(bool Negate, string Name)> Pseudos = new List<(bool, string)>(); + } + + // Parse "Type#name.class1.class2" with optional ":pseudo" / ":not(pseudo)" suffixes. + static bool TryParsePart(string raw, out SelectorPart part) + { + part = new SelectorPart(); + + var simple = ExtractPseudos(raw, part.Pseudos); + if (simple == null) + return false; + + int i = 0; + var sb = new StringBuilder(); + + // Leading run (before any '#' or '.') is the type token. + while (i < simple.Length && simple[i] != '#' && simple[i] != '.') + sb.Append(simple[i++]); + if (sb.Length > 0) + { + var type = sb.ToString(); + if (type != "*") + part.Type = type; + } + + while (i < simple.Length) + { + char kind = simple[i++]; + sb.Clear(); + while (i < simple.Length && simple[i] != '#' && simple[i] != '.') + sb.Append(simple[i++]); + + var value = sb.ToString(); + if (value.Length == 0) + return false; // dangling '#' or '.' + + if (kind == '#') + { + if (part.Name != null) + return false; // more than one id + part.Name = value; + } + else + { + part.Classes.Add(value); + } + } + + return true; + } + + // Strip ":pseudo" and ":not(pseudo)" suffixes into 'pseudos', returning the simple-selector + // remainder, or null if a pseudo is malformed. + static string ExtractPseudos(string raw, List<(bool Negate, string Name)> pseudos) + { + int idx; + while ((idx = raw.IndexOf(':')) >= 0) + { + var head = raw.Substring(0, idx); + var rest = raw.Substring(idx + 1); + + if (rest.StartsWith("not(", StringComparison.Ordinal)) + { + int close = rest.IndexOf(')'); + if (close < 0) + return null; + var inner = rest.Substring(4, close - 4).Trim().TrimStart(':'); + if (inner.Length == 0) + return null; + pseudos.Add((true, inner.ToLowerInvariant())); + raw = head + rest.Substring(close + 1); + } + else + { + int next = rest.IndexOf(':'); + var name = next < 0 ? rest : rest.Substring(0, next); + if (name.Length == 0) + return null; + pseudos.Add((false, name.ToLowerInvariant())); + raw = head + (next < 0 ? string.Empty : rest.Substring(next)); + } + } + + return raw; + } + + // Apply one pseudo-state to the query, honoring negation. Returns false for an unknown state. + static bool TryApplyPseudo(ref UQueryBuilder query, string name, bool negate) + { + bool on = !negate; + switch (name) + { + case "checked": query = on ? query.Checked() : query.NotChecked(); return true; + case "hover": query = on ? query.Hovered() : query.NotHovered(); return true; + case "focus": query = on ? query.Focused() : query.NotFocused(); return true; + case "active": query = on ? query.Active() : query.NotActive(); return true; + case "enabled": query = on ? query.Enabled() : query.NotEnabled(); return true; + case "disabled": query = on ? query.NotEnabled() : query.Enabled(); return true; + default: return false; + } + } + + // Match a type token against the element's runtime type name or any of its base type names, + // so "Button" matches a Button and "VisualElement" matches everything. Avoids reflecting the + // generic OfType over a runtime-resolved Type. + static bool TypeNameMatches(VisualElement element, string typeName) + { + for (var t = element.GetType(); t != null && t != typeof(object); t = t.BaseType) + { + if (string.Equals(t.Name, typeName, StringComparison.Ordinal)) + return true; + } + return false; + } + + static void DestroyObject(Object obj) + { +#if UNITY_EDITOR + if (!Application.isPlaying) + { + Object.DestroyImmediate(obj); + return; + } +#endif + Object.Destroy(obj); + } + } + + /// + /// Result of a visual-element capture command: the PNG payload (base64), its dimensions, the + /// panel/source it was rendered from, and the path it was written to. JSON property names mirror + /// the GameView capture command's result shape (PR #13) for easy convergence later. + /// + [Serializable] + class CaptureElementResponse + { + /// Whether the capture succeeded. + [JsonProperty("success")] + public bool Success { get; set; } + + /// Human-readable message (the error text on failure). + [JsonProperty("message")] + public string Message { get; set; } + + /// The selector used to locate the element. + [JsonProperty("selector")] + public string Selector { get; set; } + + /// What was captured, e.g. "window:Inspector" or "panel:MainUI". + [JsonProperty("source")] + public string Source { get; set; } + + /// Absolute filesystem path the PNG was written to. + [JsonProperty("path")] + public string Path { get; set; } + + /// Captured width in pixels. + [JsonProperty("width")] + public int Width { get; set; } + + /// Captured height in pixels. + [JsonProperty("height")] + public int Height { get; set; } + + /// Image encoding; always "png". + [JsonProperty("encoding")] + public string Encoding { get; set; } + + /// Base64-encoded PNG bytes. + [JsonProperty("base64")] + public string Base64 { get; set; } + + /// Length of the raw PNG byte array. + [JsonProperty("bytes")] + public int Bytes { get; set; } + + public static CaptureElementResponse Fail(string message) => new CaptureElementResponse + { + Success = false, + Message = message + }; + } +} +#endif diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Commands/VisualElementCaptureSupport.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/VisualElementCaptureSupport.cs.meta new file mode 100644 index 0000000..4c2af27 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Commands/VisualElementCaptureSupport.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3e2225ea88f5b5a4c9be3afc9c5d9f4e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Common.meta new file mode 100644 index 0000000..614ed4a --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c9f4a11d82a4dd54d93200f6c3aa4678 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/BasePipelineServer.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Common/BasePipelineServer.cs new file mode 100644 index 0000000..ee4edb7 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/BasePipelineServer.cs @@ -0,0 +1,2713 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using Unity.Pipeline.Models; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Security; +using Unity.Pipeline.Threading; +using UnityEngine; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Unity.Pipeline +{ + /// + /// HTTP server that enables CLI tools to execute commands in Unity Editor. + /// Represents an Instance that can serve as a Pipeline Element for automation. + /// + public abstract class BasePipelineServer + { + private const long DefaultMaxRequestBodyBytes = 1 * 1024 * 1024; + + /// + /// Maximum accepted request body size. Larger requests are rejected with 413, bounding the memory + /// one remote request can force the server to buffer. Settable so a server whose clients + /// legitimately post larger documents can raise it without every other server paying for it. + /// + public long MaxRequestBodyBytes { get; set; } = DefaultMaxRequestBodyBytes; + + /// + /// Upper bound on how many bytes we read-and-discard from an over-limit request body before + /// sending the 413. HttpListener resets the TCP connection if we close the response while the + /// client is still uploading, and the client then sees a connection error instead of the 413. + /// Draining lets the client finish so it can read the response. Kept comfortably above + /// to cover clients only slightly over the cap, while still + /// bounding the work a single abusive request can force (a larger body simply resets). + /// + private const long MaxDrainBytes = 8 * 1024 * 1024; + + /// + /// Maximum accepted body size for /api/job/cancel (4 KiB). The body is just an + /// {"id": "..."} object, so it needs far less headroom than . + /// + private const long MaxCancelBodyBytes = 4 * 1024; + + /// + /// Dispatcher wait for a detached job's main-thread execution. Nothing is synchronously + /// waiting on this thread (the job's HTTP response was already sent), so this only needs + /// to be larger than any command's own timeout (e.g. eval's 24h cap) rather than bounded + /// by an HTTP-facing default. + /// + private const int UnboundedJobDispatcherTimeoutMs = int.MaxValue; + + private bool m_IsRunning; + private int m_Port; + + /// + /// Serializes /api/exec command execution now that requests are processed + /// concurrently: execs queue exactly as they did when the accept loop was serial, + /// while read-only endpoints (/api/status, /api/progress, …) answer immediately. + /// + private readonly SemaphoreSlim m_ExecGate = new SemaphoreSlim(1, 1); + private HttpListener m_HttpListener; + private readonly Dispatcher m_Dispatcher = new Dispatcher(); + + /// This server's own progress-reporting state (see CliProgress). + internal CliProgressState Progress { get; } = new CliProgressState(); + + /// This server's own modal-dialog state (see EditorDialogStateMirror, Task 7). + internal DialogStateTracker Dialogs { get; } = new DialogStateTracker(); + + /// This server's own detached-job registry (see PipelineCancellation, /api/job). + internal PipelineJobRegistry JobRegistry { get; } = new PipelineJobRegistry(); + + /// + /// The server instance currently executing a command on this thread, if any. Set only + /// around the actual command invocation (see ) so + /// CliProgress.Report/PipelineCancellation — called from arbitrary command code with no + /// reference to "which server is running me" — resolve to the right instance. Correct + /// regardless of which physical thread ends up running the command, since the push/read/pop + /// all happen within one synchronous call frame; a command that awaits and resumes on a + /// different thread before calling either API would not see it (no command does today). + /// + [ThreadStatic] private static BasePipelineServer m_CurrentServer; + internal static BasePipelineServer CurrentServer => m_CurrentServer; + + private bool m_WatchdogEnabled; + private bool m_WatchdogArmed; + private DateTime m_LastWatchdogCheck; + + /// + /// This server's own main-thread dispatcher. Each server instance owns one (no global + /// singleton), so tests that start their own server never affect any other server's + /// dispatch. Pump it via ProcessWorkQueue from the main thread (auto-pumped on + /// EditorApplication.update in the editor; pumped by RuntimePipelineDriver.Update in a + /// player; pumped explicitly by tests). + /// + public Dispatcher Dispatcher => m_Dispatcher; + + /// + /// Whether the server is running AND its HTTP listener is actually listening. More accurate + /// than the internal running flag alone: returns false if the listener was stopped/disposed + /// (e.g. by a domain reload) even when the flag is stale-true. Cheap and non-blocking. + /// + /// A self-HTTP probe was considered for "does it actually respond" but rejected: the server + /// processes requests strictly one-at-a-time (HandleRequests awaits ProcessRequest), so a + /// self-probe deadlocks if issued from within a handler and false-negatives whenever a + /// request is in flight — unsafe for a watchdog. IsListening reliably catches the realistic + /// failure (listener stopped by a domain reload), which is what we need. + /// + public bool IsRunning => m_IsRunning && m_HttpListener != null && m_HttpListener.IsListening; + + /// + /// When enabled, the server periodically checks its own HTTP listener and re-opens it in + /// place if it died without going through (e.g. an unexpected listener + /// fault). The server instance survives such failures — only the listener dies — so it can + /// self-heal without an external restart. Default OFF: transient/test servers must not + /// watchdog. The editor owner enables it for the live server. + /// + /// Setting this while the server is running arms/disarms the watchdog immediately; otherwise + /// it takes effect on the next . Domain reloads are NOT handled here (the + /// instance is torn down and recreated by [InitializeOnLoad]); the watchdog only revives a + /// listener that died while the instance is still alive. + /// + public bool WatchdogEnabled + { + get => m_WatchdogEnabled; + set + { + if (m_WatchdogEnabled == value) + return; + m_WatchdogEnabled = value; + if (!m_IsRunning) + return; + if (value) + ArmWatchdog(); + else + DisarmWatchdog(); + } + } + + /// + /// How often the watchdog checks the listener (seconds). Default 5. + /// + public double WatchdogIntervalSeconds { get; set; } = 5.0; + + /// + /// Port number the server is listening on. 0 if not running. + /// Range: 7800-7899 for Editor, 7900-7999 for Runtime (avoids unity-tools port range 37800-37899). + /// + public int Port => m_Port; + + /// UTC time this server instance started listening. + public abstract DateTime StartedAt { get; } + + /// + /// Whether this server writes/deletes the shared instance descriptor (.unity-pipeline-port). + /// Test servers override this to false so they never clobber the live server's descriptor — + /// the test already knows its port, so no discovery file is needed. + /// + protected virtual bool WritesDescriptor => true; + + /// + /// Whether this server advertises commands marked [CliCommand(RuntimeOnly = true)] in + /// its /api/commands listing. Runtime servers list them; Editor servers hide them so a + /// client connected to an Editor only sees the Editor command surface. + /// + protected virtual bool IncludeRuntimeOnlyCommands => true; + + /// + /// Whether requests from a sandboxed browser frame (Origin: null) are accepted. Off by default; + /// an ordinary web page is refused either way, and a sandboxed one still needs the bearer token, + /// which lives in a file no browser can read. + /// + public bool AllowSandboxedBrowserClients + { + get => m_AllowSandboxedBrowserClients; + set => m_AllowSandboxedBrowserClients = value; + } + + // Read on the listener thread, so volatile: a value set on the main thread must be seen there. + private volatile bool m_AllowSandboxedBrowserClients; + + /// The only Origin a sandboxed frame reports; a real page sends its own origin. + private const string SandboxedOrigin = "null"; + + /// Write the shared instance descriptor file so clients can discover this server. + protected abstract void CreateInstanceDescriptor(); + /// Remove the shared instance descriptor file on shutdown. + protected abstract void DeleteInstanceDescriptor(); + /// Refresh the descriptor's heartbeat timestamp so discovery can detect a live server. + protected abstract void UpdateHeartBeat(); + /// Build the host-specific payload for /api/status (Editor vs. Player fields differ). + /// The status payload. + protected abstract object GetServerStatus(); + /// The bearer token clients must present to authenticate requests. + /// The current token. + protected abstract string GetToken(); + + /// + /// Optional wire features this server understands, advertised on /api/status and in the + /// port descriptor. + /// + /// One array feeds both carriers so they cannot drift: a server that claims a capability + /// it lacks is worse than one that claims nothing, because a client's fallback is keyed on + /// the claim. Absence of the key entirely means the server is too old to have it, and + /// clients must then assume no raw command-line support. + /// + internal static readonly string[] Capabilities = { "exec.argv", "exec.commandLine" }; + + /// Hook invoked once the listener is accepting requests. No-op by default. + protected virtual void ServerStarted() + { + + } + + /// + /// Busy probe for the /api/exec gate: return a non-null, human-readable reason when the + /// host cannot service right now (e.g. the Editor is still + /// importing/compiling while settling after a cold start), or null to let it run. A busy + /// command is rejected with HTTP 503 and a structured, retryable envelope — before sync + /// execution and before a detached job is created — instead of executing into a + /// half-ready host and failing opaquely (AUTHAPI-35). Called on the request thread, so + /// implementations must only read thread-safe state. Default: never busy. + /// + /// The command about to be dispatched. + /// A human-readable busy reason, or null to let the command run. + protected virtual string GetBusyReason(CommandInfo command) => null; + + /// + /// For a command otherwise blocked by the dialog gate, an optional cached-but-still-valid + /// result to serve as a normal 200 success instead of the 503 (e.g. editor_status: nothing + /// about compilation/play-mode/domain-reload can change while the main thread is stuck + /// inside the dialog's native message loop, so a snapshot taken just before it blocked + /// stays correct for the whole window — see EditorPipelineServer's override). Called on the + /// request thread, so implementations must only read thread-safe state. Default: no + /// fallback exists, so every MainThreadRequired command stays hard-gated. + /// + /// Internal, not protected: DialogInfo is internal, and a protected member can't expose a + /// less-accessible type in its signature — a subclass outside this assembly (without + /// InternalsVisibleTo) couldn't reference DialogInfo to override it. EditorPipelineServer + /// overrides this from Unity.Pipeline.Editor, which already has that grant (same as + /// Dialogs and BuildDialogPayload above). + /// + internal virtual object TryGetDialogBlockedFallback(CommandInfo command, DialogInfo blockingDialog) => null; + + /// Hook invoked once the listener has stopped accepting requests. No-op by default. + protected virtual void ServerStopped() + { + + } + + /// + /// This server's current auth token. Exposed to the test assembly (via InternalsVisibleTo) + /// so the test client can authenticate without re-deriving the token. + /// + internal string Token => GetToken(); + + /// + /// Whether was picked from this server's range rather than requested by + /// the caller. Recorded at bind time, so it still describes the running listener after the + /// settings asset is edited. + /// + internal bool PortAutoAssigned { get; private set; } + + /// + /// Start the HTTP server on the specified port or auto-assign from range. + /// + /// Port to bind to, or 0 for auto-assignment from server-specific range + public void Start(int port = 0) + { + if (m_IsRunning) + return; + + m_Port = port == 0 ? FindAvailablePort() : port; + PortAutoAssigned = port == 0; + + try + { + // Initialize this server's own dispatcher (captures the main thread; Start() is + // always called from the main thread). + m_Dispatcher.Initialize(); + + // Warm the token cache on the main thread before the listener accepts requests: + // per-request auth runs on background threads and the Editor token is SessionState- + // backed (main-thread-only). Re-runs after every domain reload via [InitializeOnLoad]. + SecurityTokenManager.GetOrCreateToken(); + + // Mark running before opening the listener so HandleRequests' loop guard stays true + // as soon as it starts on the threadpool. + m_IsRunning = true; + OpenListener(); + + System.Console.WriteLine($"Start HTTP server: port:{m_Port}"); + + if (WritesDescriptor) + CreateInstanceDescriptor(); + + ArmWatchdog(); + + ServerStarted(); + } + catch (Exception) + { + m_IsRunning = false; + m_HttpListener?.Stop(); + m_HttpListener = null; + throw; + } + } + + /// + /// Create the HTTP listener, bind it, and start the request-handling loop. Extracted from + /// so the watchdog can re-open a dead listener in place without + /// re-running the rest of startup (dispatcher init, descriptor). Caller sets m_IsRunning. + /// + private void OpenListener() + { + m_HttpListener = new HttpListener(); + AddLoopbackPrefixes(m_HttpListener, m_Port); + m_HttpListener.Start(); + + // Start request handling + _ = Task.Run(HandleRequests); + } + + /// + /// Bind a wildcard-host prefix so the listener accepts any Host header ("127.0.0.1", + /// "localhost", "::1") no matter how a client — or its DNS resolver — resolves the name. + /// This is required because Mono's HttpListener binds a hostname prefix to a single resolved + /// address family and then matches the request's Host literally per prefix: an + /// explicit "http://127.0.0.1/" prefix rejects "Host: localhost" (and vice-versa) with a + /// 400. A wildcard sidesteps that. The wildcard binds all interfaces at the socket level, so + /// access is confined to the local machine by the loopback check in + /// (plus bearer-token auth). + /// + private static void AddLoopbackPrefixes(HttpListener listener, int port) + { + listener.Prefixes.Add($"http://+:{port}/"); + } + + /// + /// Stop the HTTP server and clean up resources. + /// + public void Stop() + { + if (!m_IsRunning) + return; + + m_IsRunning = false; + + DisarmWatchdog(); + System.Console.WriteLine("Pipeline Server stopped"); + + try + { + if (WritesDescriptor) + DeleteInstanceDescriptor(); + + m_HttpListener?.Stop(); + m_HttpListener?.Close(); + + ServerStopped(); + } + catch + { + // Ignore cleanup errors + } + finally + { + m_HttpListener = null; + m_Dispatcher.Shutdown(); + } + // Note: Keep port value for diagnostic purposes + } + + /// + /// Arm the watchdog (no-op if disabled or already armed). In the editor the tick rides + /// EditorApplication.update; in a player it is driven by RuntimePipelineDriver.Update via + /// . + /// + private void ArmWatchdog() + { + if (!m_WatchdogEnabled || m_WatchdogArmed) + return; + + m_WatchdogArmed = true; + m_LastWatchdogCheck = DateTime.UtcNow; +#if UNITY_EDITOR + UnityEditor.EditorApplication.update += WatchdogTick; +#endif + } + + private void DisarmWatchdog() + { + if (!m_WatchdogArmed) + return; + + m_WatchdogArmed = false; +#if UNITY_EDITOR + UnityEditor.EditorApplication.update -= WatchdogTick; +#endif + } + + /// + /// Watchdog heartbeat: throttled to , re-opens the HTTP + /// listener in place if it died while the server is still meant to be running. Safe to call + /// every frame. In the editor it is subscribed to EditorApplication.update by ArmWatchdog; + /// in a player RuntimePipelineDriver.Update calls it. + /// + public void WatchdogTick() + { + if (!m_WatchdogArmed) + return; + +#if UNITY_EDITOR + // Don't fight domain reloads / asset updates — the listener is expected to be torn down + // then, and [InitializeOnLoad] recreates the server afterwards. + if (UnityEditor.EditorApplication.isCompiling || UnityEditor.EditorApplication.isUpdating) + return; +#endif + + var now = DateTime.UtcNow; + if ((now - m_LastWatchdogCheck).TotalSeconds < WatchdogIntervalSeconds) + return; + m_LastWatchdogCheck = now; + + if (m_HttpListener != null && m_HttpListener.IsListening) + return; // healthy + + try + { + // Dispose the dead listener so it releases the port binding before we re-bind a new + // one on the same port (a stopped-but-not-closed listener can keep the port held). + try { m_HttpListener?.Close(); } catch { } + m_HttpListener = null; + + // The instance is alive and the watchdog is armed → the server is meant to be + // listening. Re-open the listener in place. + m_IsRunning = true; + OpenListener(); + Debug.Log($"Pipeline watchdog re-opened HTTP listener on port {m_Port}"); + } + catch (Exception ex) + { + Debug.LogWarning($"Pipeline watchdog failed to re-open listener on port {m_Port}: {ex.Message}"); + } + } + + /// + /// Handle incoming HTTP requests with routing to appropriate endpoints. + /// + private async Task HandleRequests() + { + while (m_IsRunning && m_HttpListener != null && m_HttpListener.IsListening) + { + try + { + var context = await m_HttpListener.GetContextAsync(); + // Process detached so the accept loop keeps serving while a long command + // holds its /api/exec connection open. Without this, ANY in-flight exec + // blocked every other request — including /api/status probes and the + // /api/progress polls that exist precisely for that situation (CLI-488; + // the "editor is unresponsive until the command finishes" report in + // CLI-335). Command execution itself stays strictly serialized via + // m_ExecGate below, so exec ordering semantics are unchanged. + _ = ProcessRequestDetached(context); + } + catch (ObjectDisposedException) + { + // Listener was stopped, exit gracefully + break; + } + catch (HttpListenerException) + { + // Listener was stopped, exit gracefully + break; + } + catch (Exception ex) + { + Debug.LogError(ex); + } + } + m_IsRunning = false; + } + + /// + /// Run ProcessRequest without the accept loop awaiting it; a per-request failure is + /// logged and must never tear down the listener loop. + /// + private async Task ProcessRequestDetached(HttpListenerContext context) + { + try + { + await ProcessRequest(context); + } + catch (Exception ex) + { + Debug.LogError(ex); + } + } + + /// + /// Process individual HTTP request and route to appropriate handler. + /// + /// The incoming HTTP request/response context. + /// A task that completes once the response has been written. + protected virtual async Task ProcessRequest(HttpListenerContext context) + { + var request = context.Request; + var response = context.Response; + + try + { + // Confine access to the local machine. The listener binds a wildcard host (see + // AddLoopbackPrefixes) so it accepts any Host header, which also means it accepts + // connections on non-loopback interfaces — reject anything that isn't loopback + // before doing any other work. Bearer-token auth is still enforced below. + var remoteAddress = request.RemoteEndPoint?.Address; + if (remoteAddress == null || !IPAddress.IsLoopback(remoteAddress)) + { + await SendStatusResponse(response, 403, "Forbidden", "Only loopback connections are allowed"); + return; + } + + // Reject browser-originated requests. Legitimate non-browser clients (CLI, CI) never + // send an Origin header; emitting no CORS headers and refusing any request that + // carries one prevents a website in the developer's browser from reaching this + // local server (and short-circuits CORS preflights). A server that opts into + // AllowSandboxedBrowserClients additionally admits Origin: null. + var origin = request.Headers["Origin"]; + if (!string.IsNullOrEmpty(origin)) + { + if (!AllowSandboxedBrowserClients || origin != SandboxedOrigin) + { + await SendStatusResponse(response, 403, "Forbidden", "Cross-origin requests are not allowed"); + return; + } + + // "*" rather than echoing "null": the gate above already decides who is served, no + // credentials are involved, and it is better supported for an opaque origin. + response.AddHeader("Access-Control-Allow-Origin", "*"); + response.AddHeader("Vary", "Origin"); + } + + // Preflight is answered before auth by necessity: the browser sends OPTIONS with no + // Authorization header, so requiring the token here would fail every real request. + if (request.HttpMethod == "OPTIONS") + { + if (string.IsNullOrEmpty(origin)) + { + await SendStatusResponse(response, 405, "Method Not Allowed", "OPTIONS is only used for CORS preflight"); + return; + } + + response.AddHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS"); + response.AddHeader("Access-Control-Allow-Headers", "Authorization, Content-Type"); + response.AddHeader("Access-Control-Max-Age", "600"); + // Chrome's Private Network Access: a page on the public internet reaching a loopback + // address must be granted it explicitly, or the preflight fails. + if (!string.IsNullOrEmpty(request.Headers["Access-Control-Request-Private-Network"])) + response.AddHeader("Access-Control-Allow-Private-Network", "true"); + response.StatusCode = 204; + response.ContentLength64 = 0; + response.OutputStream.Close(); + return; + } + + // Authenticate every request with the bearer token before routing. + if (!IsAuthorized(request)) + { + await SendStatusResponse(response, 401, "Unauthorized", "Missing or invalid authentication token"); + return; + } + + // Route to appropriate endpoint + var path = request.Url.AbsolutePath.ToLowerInvariant(); + + switch (path) + { + case "/api/status": + await HandleStatusRequest(response); + break; + case "/api/editor_status": + await HandleEditorStatusRequest(response); + break; + case "/api/commands": + await HandleCommandsRequest(request, response); + break; + case "/api/exec": + if (request.HttpMethod == "POST") + await HandleExecRequest(request, response); + else + await HandleMethodNotAllowed(response, "POST"); + break; + case "/api/test-status": + await HandleTestStatusRequest(response); + break; + case "/api/progress": + await HandleProgressRequest(request, response); + break; + case "/api/dialog": + await HandleDialogRequest(response); + break; + case "/api/job": + if (request.HttpMethod == "GET") + await HandleJobStatusRequest(request, response); + else + await HandleMethodNotAllowed(response, "GET"); + break; + case "/api/job/cancel": + if (request.HttpMethod == "POST") + await HandleJobCancelRequest(request, response); + else + await HandleMethodNotAllowed(response, "POST"); + break; + default: + await HandleNotFound(response); + break; + } + } + catch (Exception e) + { + // A silent 500 leaves the client with nothing to go on; name the request and the fault. + Debug.LogError($"Pipeline: unhandled error serving {request.HttpMethod} " + + $"{request.Url?.AbsolutePath}: {e}"); + + // Ensure response is always closed + try + { + if (response.OutputStream.CanWrite) + { + response.StatusCode = 500; + response.OutputStream.Close(); + } + } + catch { } + } + } + + /// + /// Validate the request's bearer token against this server's token. + /// + private bool IsAuthorized(HttpListenerRequest request) + { + var header = request.Headers["Authorization"]; + if (string.IsNullOrEmpty(header)) + return false; + + const string prefix = "Bearer "; + if (!header.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) + return false; + + var token = header.Substring(prefix.Length).Trim(); + return SecurityTokenManager.ConstantTimeEquals(token, GetToken()); + } + + /// + /// Send a structured JSON error response with an explicit HTTP status code. + /// + private async Task SendStatusResponse(HttpListenerResponse response, int statusCode, string error, string details) + { + try + { + response.StatusCode = statusCode; + response.ContentType = "application/json"; + var json = JsonConvert.SerializeObject(BaseResponse.Failure(error, details), Formatting.Indented); + var buffer = Encoding.UTF8.GetBytes(json); + response.ContentLength64 = buffer.Length; + + await response.OutputStream.WriteAsync(buffer, 0, buffer.Length); + response.OutputStream.Close(); + } + catch + { + try { response.OutputStream.Close(); } catch { } + } + } + + /// + /// Parse the omit_nulls query parameter (snake_case like the other query + /// parameters, e.g. group_by) — the GET-endpoint equivalent of exec's omitNulls + /// JSON body flag, for /api/job, /api/job/cancel, and /api/progress. Accepted values: + /// "true"/"false", case-insensitive; absent means false. Any other value (e.g. + /// omit_nulls=1) is NOT silently coerced to false: it yields false plus a + /// the caller surfaces in the response's "warnings" array, so + /// an agent learns the accepted spelling instead of guessing why nulls are still present. + /// (Exec body requests don't need this: JSON deserialization coerces their boolean.) + /// + private static bool ParseOmitNulls(HttpListenerRequest request, out string warning) + { + warning = null; + var raw = request.QueryString["omit_nulls"]; + if (raw == null) + { + // A bare "?omit_nulls" (no '=') is not the same as absent: .NET files valueless + // query tokens under the null key, so look there to warn instead of silently + // treating an intended opt-in as false. + var valueless = request.QueryString.GetValues(null); + if (valueless != null && Array.IndexOf(valueless, "omit_nulls") >= 0) + warning = "omit_nulls given without a value ignored; use omit_nulls=true"; + return false; + } + if (string.Equals(raw, "true", StringComparison.OrdinalIgnoreCase)) + return true; + if (string.Equals(raw, "false", StringComparison.OrdinalIgnoreCase)) + return false; + + warning = $"omit_nulls='{raw}' ignored; expected 'true' or 'false'"; + return false; + } + + /// + /// Serialize and send it as the JSON body. Null fields are + /// INCLUDED by default — on /api/job and /api/progress every field is payload (there is + /// no envelope/payload split like /api/exec's), and an absent key is indistinguishable + /// from a nonexistent or misspelled one. Callers pass from + /// the endpoint's omit_nulls query parameter (see ) + /// to opt out (AUTHAPI-21). + /// Shares 's write guard: a failure while writing + /// (e.g. the client disconnected mid-response) is swallowed here instead of propagating + /// into the caller's own catch block, which would otherwise attempt a second response on + /// the now-dead connection. + /// + private async Task SendJsonResponse(HttpListenerResponse response, int statusCode, object payload, bool omitNulls = false) + { + try + { + var json = JsonConvert.SerializeObject(payload, + new JsonSerializerSettings + { + NullValueHandling = omitNulls ? NullValueHandling.Ignore : NullValueHandling.Include + }); + + response.StatusCode = statusCode; + response.ContentType = "application/json"; + var buffer = Encoding.UTF8.GetBytes(json); + response.ContentLength64 = buffer.Length; + + await response.OutputStream.WriteAsync(buffer, 0, buffer.Length); + response.OutputStream.Close(); + } + catch + { + try { response.OutputStream.Close(); } catch { } + } + } + + /// + /// Handle /api/status endpoint - returns basic server health information. + /// No Editor API access required, always fast response. + /// + private async Task HandleStatusRequest(HttpListenerResponse response) + { + try + { + var basicStatus = GetServerStatus(); + var json = JsonConvert.SerializeObject(basicStatus, Formatting.Indented); + + response.StatusCode = 200; + response.ContentType = "application/json"; + + var buffer = Encoding.UTF8.GetBytes(json); + response.ContentLength64 = buffer.Length; + + await response.OutputStream.WriteAsync(buffer, 0, buffer.Length); + response.OutputStream.Close(); + } + catch (Exception ex) + { + Debug.LogError($"HandleStatusRequest failed: {ex.Message}"); + await SendErrorResponse(response, "Status Error", $"Failed to get status: {ex.Message}"); + } + } + + /// + /// Handle /api/editor_status endpoint - returns detailed Editor state via command execution. + /// Executes the "editor_status" command to get rich Editor information. + /// + private async Task HandleEditorStatusRequest(HttpListenerResponse response) + { + try + { + // TODO: should this be implemented as a command?? + + // Queue behind the same gate as /api/exec so this doesn't run concurrently with + // an in-flight exec (or another editor_status/test_status call): it dispatches + // onto the main thread just like exec does, so left ungated it would race rather + // than queue the way it did under the old serial accept loop. + object result; + await m_ExecGate.WaitAsync(); + try + { + result = await ExecuteCommandByName("editor_status", new JObject()); + } + finally + { + m_ExecGate.Release(); + } + + // The editor_status command returns a StatusResponse directly + var editorStatus = result as StatusResponse; + if (editorStatus != null) + { + // Update with server-specific information + UpdateStatusWithServerInfo(editorStatus); + + var json = JsonConvert.SerializeObject(editorStatus, Formatting.Indented); + + response.StatusCode = 200; + response.ContentType = "application/json"; + + var buffer = Encoding.UTF8.GetBytes(json); + response.ContentLength64 = buffer.Length; + + await response.OutputStream.WriteAsync(buffer, 0, buffer.Length); + response.OutputStream.Close(); + } + else + { + Debug.LogError($"HandleEditorStatusRequest: editor_status command returned wrong type: {result?.GetType().FullName ?? "null"}"); + await SendErrorResponse(response, "Editor Status Error", "editor_status command did not return valid StatusResponse"); + } + } + catch (Exception ex) + { + var errorMessage = !string.IsNullOrEmpty(ex.Message) ? ex.Message : "[EMPTY EXCEPTION MESSAGE]"; + Debug.LogError($"HandleEditorStatusRequest failed:"); + Debug.LogError($" Exception Type: {ex.GetType().FullName}"); + Debug.LogError($" Message: '{errorMessage}'"); + Debug.LogError($" Full Exception: {ex}"); + + await SendErrorResponse(response, "Editor Status Error", $"Failed to get editor status: {errorMessage}"); + } + } + + /// + /// Update StatusResponse with server-specific information. + /// Used by /api/editor_status to add server metadata to command result. + /// + private void UpdateStatusWithServerInfo(StatusResponse editorStatus) + { + UpdateHeartBeat(); + // Ensure heartbeat is current + editorStatus.LastHeartbeat = DateTime.UtcNow; + } + + /// + /// Handle /api/commands endpoint - returns the available CLI commands. + /// + /// Optional query parameters (filters combine with AND): + /// - detail: 'full' (default) includes parameters and the generated JSON schema; + /// 'compact' returns a lightweight index (name, description, tags, package) so a + /// client can cheaply browse, then fetch full detail only for the commands it + /// intends to invoke. + /// - query: case-insensitive substring match on name, description, or any tag. + /// - tag: scope to a tag subtree via segment-aware prefix match ('assets' matches + /// 'assets' and 'assets/import' but not 'assetsx'). + /// - group_by: 'flat' (default) returns a 'commands' array; 'package' and 'tag' + /// return a 'groups' array instead ('tag' is a nested tree mirroring tag/subtag; + /// untagged commands land in a node with an empty tag). + /// - sort: 'name' (default) or 'package' (originating package, name as tiebreak); + /// order: 'asc' (default) or 'desc'. Sorting applies to the flat list before + /// pagination and grouping. + /// - offset / limit: paginate the filtered, sorted flat list (applied before + /// grouping, so pages are deterministic); 'total' reports the match count before + /// pagination while 'count' is the number of commands actually returned. + /// + private async Task HandleCommandsRequest(HttpListenerRequest request, HttpListenerResponse response) + { + try + { + var queryString = request.QueryString; + + var detail = queryString["detail"] ?? "full"; + bool fullDetail; + if (string.Equals(detail, "full", StringComparison.OrdinalIgnoreCase)) + fullDetail = true; + else if (string.Equals(detail, "compact", StringComparison.OrdinalIgnoreCase)) + fullDetail = false; + else + { + await SendStatusResponse(response, 400, "Invalid Request", + $"Unknown detail value '{detail}'. Accepted values: compact, full"); + return; + } + + var groupBy = queryString["group_by"] ?? "flat"; + var groupByPackage = string.Equals(groupBy, "package", StringComparison.OrdinalIgnoreCase); + var groupByTag = string.Equals(groupBy, "tag", StringComparison.OrdinalIgnoreCase); + if (!groupByPackage && !groupByTag && !string.Equals(groupBy, "flat", StringComparison.OrdinalIgnoreCase)) + { + await SendStatusResponse(response, 400, "Invalid Request", + $"Unknown group_by value '{groupBy}'. Accepted values: flat, package, tag"); + return; + } + + var sort = queryString["sort"] ?? "name"; + var sortByPackage = string.Equals(sort, "package", StringComparison.OrdinalIgnoreCase); + if (!sortByPackage && !string.Equals(sort, "name", StringComparison.OrdinalIgnoreCase)) + { + await SendStatusResponse(response, 400, "Invalid Request", + $"Unknown sort value '{sort}'. Accepted values: name, package"); + return; + } + + var order = queryString["order"] ?? "asc"; + var descending = string.Equals(order, "desc", StringComparison.OrdinalIgnoreCase); + if (!descending && !string.Equals(order, "asc", StringComparison.OrdinalIgnoreCase)) + { + await SendStatusResponse(response, 400, "Invalid Request", + $"Unknown order value '{order}'. Accepted values: asc, desc"); + return; + } + + var offset = 0; + if (queryString["offset"] != null + && (!int.TryParse(queryString["offset"], out offset) || offset < 0)) + { + await SendStatusResponse(response, 400, "Invalid Request", + $"Invalid offset value '{queryString["offset"]}'. Expected a non-negative integer"); + return; + } + + int? limit = null; + if (queryString["limit"] != null) + { + if (!int.TryParse(queryString["limit"], out var parsedLimit) || parsedLimit < 0) + { + await SendStatusResponse(response, 400, "Invalid Request", + $"Invalid limit value '{queryString["limit"]}'. Expected a non-negative integer"); + return; + } + limit = parsedLimit; + } + + var query = queryString["query"]; + var tag = queryString["tag"]; + + var filtered = CommandRegistry.DiscoverCommands() + .Where(c => IncludeRuntimeOnlyCommands || !c.RuntimeOnly) + .Where(c => MatchesQuery(c, query) && MatchesTagSubtree(c, tag)); + var matching = SortCommands(filtered, sortByPackage, descending).ToList(); + + // Paginate the flat, sorted list before any grouping so pages are deterministic. + IEnumerable window = matching.Skip(offset); + if (limit.HasValue) + window = window.Take(limit.Value); + var page = window.ToList(); + + Func project = c => + fullDetail ? BuildFullCommandResponse(c) : BuildCompactCommandResponse(c); + + var responseData = new Dictionary(); + if (groupByPackage) + responseData["groups"] = BuildPackageGroups(page, project); + else if (groupByTag) + responseData["groups"] = BuildTagTree(page, project); + else + responseData["commands"] = page.Select(project).ToList(); + responseData["count"] = page.Count; + responseData["total"] = matching.Count; + responseData["offset"] = offset; + responseData["limit"] = limit; + responseData["server"] = new + { + version = "0.0.1", // TODO: Get from package.json + port = m_Port, + startTime = StartedAt + }; + + var json = JsonConvert.SerializeObject(responseData, Formatting.Indented); + + response.StatusCode = 200; + response.ContentType = "application/json"; + + var buffer = Encoding.UTF8.GetBytes(json); + response.ContentLength64 = buffer.Length; + + await response.OutputStream.WriteAsync(buffer, 0, buffer.Length); + response.OutputStream.Close(); + } + catch (Exception ex) + { + Debug.LogError($"Failed to handle /api/commands request: {ex.Message}"); + + // Return error response + response.StatusCode = 500; + response.ContentType = "application/json"; + + var errorResponse = new { error = "Internal server error", message = ex.Message }; + var errorJson = JsonConvert.SerializeObject(errorResponse); + var errorBuffer = Encoding.UTF8.GetBytes(errorJson); + response.ContentLength64 = errorBuffer.Length; + + await response.OutputStream.WriteAsync(errorBuffer, 0, errorBuffer.Length); + response.OutputStream.Close(); + } + } + + /// + /// Build the lightweight index entry for a single command (detail=compact). + /// + private static object BuildCompactCommandResponse(CommandInfo command) + { + return new + { + name = command.Name, + description = command.Description, + tags = command.Tags, + package = command.Package + }; + } + + /// + /// Build the complete JSON response object for a single command (detail=full). + /// + private object BuildFullCommandResponse(CommandInfo command) + { + var entry = BuildCommandEntry(command); + entry["schema"] = JsonSchemaGenerator.GenerateCommandSchema(command); + return entry; + } + + /// + /// One command's catalog entry: everything /api/commands serves for it except the + /// generated JSON schema. + /// + /// Shared by the catalog and by an argument-error envelope, so a client's entry renderer + /// consumes both unchanged and the two cannot drift. The error path takes this directly + /// rather than building the full response and dropping the schema, because generating and + /// serializing a schema nobody reads is pure waste on the interactive retry path. + /// + private JObject BuildCommandEntry(CommandInfo command) + { + return JObject.FromObject(new + { + name = command.Name, + description = command.Description, + tags = command.Tags, + package = command.Package, + mainThreadRequired = command.MainThreadRequired, + runtimeOnly = command.RuntimeOnly, + parameters = command.Parameters.Select(p => new + { + name = p.Name, + description = p.Description, + type = p.ParameterType.Name, + required = p.Required, + defaultValue = p.DefaultValue + }).ToList() + }); + } + + /// + /// Attaches the bound-parameter echo for raw-form requests, and only for those, leaving + /// the structured path's envelope unchanged. + /// + /// The value is exactly what the binder stored, so the echo cannot disagree with what the + /// command executes with. A client that does not bind locally has no other way to report + /// what the command received. + /// + private static CommandExecutionResponse WithBoundParameters( + CommandExecutionResponse response, CommandExecutionRequest request) + { + if (request.IsRawForm) + response.BoundParameters = request.Parameters ?? new JObject(); + return response; + } + + /// + /// Renders argument problems as English prose for errorDetails. + /// + /// This is the fallback, not the primary channel: a client that understands + /// argProblems renders and localizes them itself. This text serves curl, MCP, and + /// any client that meets a kind it does not recognize, so it must stay useful on + /// its own. + /// + private static string DescribeArgProblems(CommandInfo command, List problems) + { + if (problems == null || problems.Count == 0) + return "Invalid arguments"; + + var parts = new List(problems.Count); + foreach (var problem in problems) + { + switch (problem.Kind) + { + case ArgProblemKind.EmptyName: + parts.Add($"'{problem.Token}' is not a valid flag: the name is empty."); + break; + case ArgProblemKind.EmptyValue: + parts.Add($"--{problem.Name} needs a value."); + break; + case ArgProblemKind.SingleDash: + parts.Add($"'{problem.Token}' is not a valid flag: single-dash flags are not supported. Use a double dash, or pass it after -- to send it as a value."); + break; + case ArgProblemKind.Duplicate: + parts.Add($"--{problem.Name} was given more than once."); + break; + case ArgProblemKind.UnknownName: + parts.Add(problem.Suggestion != null + ? $"{command.Name} has no parameter --{problem.Name}. Did you mean --{problem.Suggestion}?" + : $"{command.Name} has no parameter --{problem.Name}. Valid parameters: {DescribeParameterNames(command)}."); + break; + case ArgProblemKind.BareAssignment: + parts.Add($"'{problem.Token}' looks like a flag written without dashes. Use --name value instead."); + break; + case ArgProblemKind.ExcessPositional: + parts.Add($"{command.Name} takes {problem.Capacity} argument(s) but {problem.Given} were given (starting at '{problem.Token}')."); + break; + case ArgProblemKind.PositionalConflict: + parts.Add($"--{problem.Name} is already set by an explicit flag, so there is no slot for '{problem.Token}'."); + break; + case ArgProblemKind.TypeMismatch: + parts.Add($"--{problem.Name} expects {problem.ExpectedType}, but got '{problem.Token}'.{DescribeValidValues(command, problem.Name)}"); + break; + default: + parts.Add($"{problem.Kind}: {problem.Token ?? problem.Name}"); + break; + } + } + + return string.Join(" ", parts); + } + + /// Every declared parameter of the command, flag-spelled, or "(none)". + private static string DescribeParameterNames(CommandInfo command) + { + if (command.Parameters.Count == 0) + return "(none)"; + return string.Join(", ", command.Parameters.Select(p => "--" + p.Name)); + } + + /// + /// For an enum parameter, the legal names, following the same enumerate-the-valid-set + /// convention used for unknown command names and query values. Empty for every other type. + /// + private static string DescribeValidValues(CommandInfo command, string parameterName) + { + foreach (var parameter in command.Parameters) + { + if (!string.Equals(parameter.Name, parameterName, StringComparison.OrdinalIgnoreCase)) + continue; + var type = Nullable.GetUnderlyingType(parameter.ParameterType) ?? parameter.ParameterType; + if (type.IsEnum) + return " Valid values: " + string.Join(", ", Enum.GetNames(type)) + "."; + break; + } + return string.Empty; + } + + /// + /// Order the filtered command list: by name, or by originating package with name as + /// tiebreak. Both keys follow the requested direction. + /// + private static IEnumerable SortCommands(IEnumerable commands, bool byPackage, bool descending) + { + if (byPackage) + { + var byPkg = descending + ? commands.OrderByDescending(c => c.Package ?? string.Empty, StringComparer.Ordinal) + : commands.OrderBy(c => c.Package ?? string.Empty, StringComparer.Ordinal); + return descending + ? byPkg.ThenByDescending(c => c.Name, StringComparer.Ordinal) + : byPkg.ThenBy(c => c.Name, StringComparer.Ordinal); + } + return descending + ? commands.OrderByDescending(c => c.Name, StringComparer.Ordinal) + : commands.OrderBy(c => c.Name, StringComparer.Ordinal); + } + + /// + /// Case-insensitive substring match on the command's name, description, or any tag. + /// A null/empty query matches everything. + /// + private static bool MatchesQuery(CommandInfo command, string query) + { + if (string.IsNullOrEmpty(query)) + return true; + return command.Name.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0 + || command.Description.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0 + || command.Tags.Any(t => t.IndexOf(query, StringComparison.OrdinalIgnoreCase) >= 0); + } + + /// + /// Segment-aware tag subtree match: 'assets' matches tags 'assets' and 'assets/import' + /// but not 'assetsx'. A null/empty tag matches everything. + /// + private static bool MatchesTagSubtree(CommandInfo command, string tag) + { + if (string.IsNullOrEmpty(tag)) + return true; + return command.Tags.Any(t => t.Equals(tag, StringComparison.OrdinalIgnoreCase) + || t.StartsWith(tag + "/", StringComparison.OrdinalIgnoreCase)); + } + + /// + /// Group a page of commands by originating package, sorted by package name. + /// + private static List BuildPackageGroups(List commands, Func project) + { + return commands + .GroupBy(c => c.Package ?? string.Empty) + .OrderBy(g => g.Key, StringComparer.Ordinal) + .Select(g => (object)new + { + package = g.Key, + count = g.Count(), + commands = g.Select(project).ToList() + }) + .ToList(); + } + + /// + /// Node of the group_by=tag tree. A command appears in the node of each tag it carries; + /// untagged commands land in a top-level node with an empty tag. + /// + private class TagTreeNode + { + public readonly List Commands = new List(); + public readonly SortedDictionary Children = + new SortedDictionary(StringComparer.Ordinal); + } + + /// + /// Build the nested group_by=tag tree mirroring the tag/subtag hierarchy. Each node's + /// 'count' covers its whole subtree (a command tagged with several tags under the same + /// node counts once per tag entry). + /// + private static List BuildTagTree(List commands, Func project) + { + var root = new TagTreeNode(); + foreach (var command in commands) + { + if (command.Tags.Count == 0) + { + GetOrAddChild(root, string.Empty).Commands.Add(command); + continue; + } + foreach (var tag in command.Tags) + { + var node = root; + foreach (var segment in tag.Split('/')) + node = GetOrAddChild(node, segment); + node.Commands.Add(command); + } + } + return root.Children + .Select(kv => ToTagGroup(kv.Key, kv.Value, project)) + .ToList(); + } + + private static TagTreeNode GetOrAddChild(TagTreeNode node, string key) + { + if (!node.Children.TryGetValue(key, out var child)) + { + child = new TagTreeNode(); + node.Children[key] = child; + } + return child; + } + + private static object ToTagGroup(string path, TagTreeNode node, Func project) + { + return new + { + tag = path, + count = SubtreeCommandCount(node), + commands = node.Commands.Select(project).ToList(), + children = node.Children + .Select(kv => ToTagGroup(path.Length == 0 ? kv.Key : path + "/" + kv.Key, kv.Value, project)) + .ToList() + }; + } + + private static int SubtreeCommandCount(TagTreeNode node) + { + return node.Commands.Count + node.Children.Values.Sum(SubtreeCommandCount); + } + + /// + /// Handle 404 Not Found responses. + /// + private async Task HandleNotFound(HttpListenerResponse response) + { + response.StatusCode = 404; + response.ContentType = "text/plain"; + + var responseText = "Not Found"; + var buffer = Encoding.UTF8.GetBytes(responseText); + response.ContentLength64 = buffer.Length; + + await response.OutputStream.WriteAsync(buffer, 0, buffer.Length); + response.OutputStream.Close(); + } + + /// + /// Handle 405 Method Not Allowed responses. + /// + private async Task HandleMethodNotAllowed(HttpListenerResponse response, string allowedMethod) + { + await SendErrorResponse(response, "Method Not Allowed", + $"This endpoint only supports {allowedMethod} requests", statusCode: 405); + } + + /// + /// Handle /api/test-status endpoint - returns status of async test execution. + /// + private async Task HandleTestStatusRequest(HttpListenerResponse response) + { + try + { + // Queue behind the same gate as /api/exec/editor_status — see the comment in + // HandleEditorStatusRequest. (In practice this rarely blocks: the async-test-status + // workflow polls this only once run_tests --async_tests has already returned and + // released the gate.) + object result; + await m_ExecGate.WaitAsync(); + try + { + result = await ExecuteCommandByName("test_status", new JObject()); + } + finally + { + m_ExecGate.Release(); + } + + string jsonResponse; + if (result is string statusString) + { + // test_status command returns JSON string directly + jsonResponse = statusString; + } + else + { + // Fallback - serialize whatever was returned + jsonResponse = JsonConvert.SerializeObject(result ?? new { status = "no_tests", message = "No test run in progress" }); + } + + response.StatusCode = 200; + response.ContentType = "application/json"; + + var buffer = Encoding.UTF8.GetBytes(jsonResponse); + response.ContentLength64 = buffer.Length; + + await response.OutputStream.WriteAsync(buffer, 0, buffer.Length); + response.OutputStream.Close(); + } + catch (Exception ex) + { + Debug.LogError($"HandleTestStatusRequest failed: {ex.Message}"); + await SendErrorResponse(response, "Test Status Error", $"Failed to get test status: {ex.Message}"); + } + } + + /// + /// Runs under the exec gate: tracks the in-flight count for + /// /api/progress ("active" while any exec runs) via CliProgress's own atomic + /// BeginExecutionCount/EndExecutionCount, owns CliProgress for the duration + /// (BeginExecution/EndExecution) so a queued execution can't surface the previous one's + /// stale progress, and resets the explicit report when the last in-flight execution + /// completes. Shared by the synchronous /api/exec path and so + /// the two copies of this scaffold can't drift apart. + /// + /// Id CliProgress.Report calls during this execution are attributed to. + /// The gated work to run once the exec gate is acquired. + /// Runs after the gate is acquired but before + /// CliProgress.BeginExecution; returning false skips entirely + /// (used by the job path to honor a cancellation requested while still queued). + private async Task ExecuteGated(string executionId, Func body, Func preStartCheck = null) + { + Progress.BeginExecutionCount(); + try + { + await m_ExecGate.WaitAsync(); + try + { + if (preStartCheck != null && !preStartCheck()) + return; + + Progress.BeginExecution(executionId); + try + { + await body(); + } + finally + { + Progress.EndExecution(executionId); + } + } + finally + { + m_ExecGate.Release(); + } + } + finally + { + Progress.EndExecutionCount(); + } + } + + /// + /// Execute a detached job (CLI-335). A cancellation requested while the job is still + /// queued prevents it from starting; a running job is only cooperatively cancelable (see + /// PipelineCancellation). + /// + private async Task RunJobDetached(PipelineJobRecord record, CommandInfo command, CommandExecutionRequest commandRequest) + { + // Set once the command actually starts, so a job canceled while still queued reports + // nothing at all. + var ran = false; + var succeeded = false; + var timer = new System.Diagnostics.Stopwatch(); + try + { + await ExecuteGated(record.Id, async () => + { + JobRegistry.MarkRunning(record); + ran = true; + timer.Start(); + try + { + var result = await ExecuteCommandByName(command, commandRequest.Parameters, + UnboundedJobDispatcherTimeoutMs); + if (record.CancellationRequested) + { + // The code honored (or raced) a cancellation request; report + // canceled rather than a half-relevant result. + JobRegistry.MarkCanceled(record); + } + else + { + succeeded = IsSuccessfulResult(result); + JobRegistry.MarkCompleted(record, result); + } + } + catch (OperationCanceledException) + { + JobRegistry.MarkCanceled(record); + } + catch (ArgumentException ex) + { + // Match the synchronous handler, which classifies ArgumentException as + // "Parameter Validation Failed": without this arm a client polling + // GET /api/job cannot tell bad input from a command that ran and failed. + if (record.CancellationRequested) + { + JobRegistry.MarkCanceled(record); + } + else + { + JobRegistry.MarkFailed(record, "Parameter Validation Failed", ex.Message); + } + } + catch (Exception ex) + { + // The command layer wraps thrown exceptions (an + // OperationCanceledException from PipelineCancellation surfaces as + // a wrapped execution failure) — after a cancellation request, any + // failure is reported as the cancellation taking effect. + if (record.CancellationRequested) + { + JobRegistry.MarkCanceled(record); + } + else + { + JobRegistry.MarkFailed(record, "Command Execution Failed", ex.Message); + } + } + finally + { + timer.Stop(); + } + }, + preStartCheck: () => + { + if (record.CancellationRequested) + { + JobRegistry.MarkCanceled(record); + return false; + } + return true; + }); + } + catch (Exception ex) + { + // The runner is fire-and-forget; a failure here must be recorded, never thrown. + Debug.LogError($"RunJobDetached failed: {ex.Message}"); + JobRegistry.MarkFailed(record, "Internal Server Error", ex.Message); + } + + // The submission already reported its own transaction, which could only say the job was + // queued. This is the point where the command's real result is known. + if (ran) + OnCommandDone(CommandExecutionInfo.ForDetachedJob(command, succeeded, timer.ElapsedMilliseconds, + commandRequest.Parameters)); + } + + /// + /// Project a progress snapshot to the {title,info,current,total,pct} wire shape + /// shared by /api/progress and a running job's progress field — kept as one helper + /// so the two can't drift out of sync with each other or the documented contract. + /// + private static object BuildProgressPayload(CliProgressState.Snapshot snapshot) + { + if (!snapshot.HasReport) + return null; + + return new + { + title = snapshot.Title, + info = snapshot.Info, + current = snapshot.Current, + total = snapshot.Total, + pct = snapshot.Progress01 + }; + } + + /// Serialize one job record to the wire shape shared by the job endpoints. + private object BuildJobResponse(PipelineJobRecord record, string warning = null) + { + lock (record.Gate) + { + var running = record.State == PipelineJobState.Running; + var progress = running ? BuildProgressPayload(Progress.Current) : null; + + return new + { + jobId = record.Id, + command = record.Command, + state = record.State.ToString().ToLowerInvariant(), + cancellationRequested = record.CancellationRequested, + enqueuedAt = record.EnqueuedAt, + startedAt = record.StartedAt, + completedAt = record.CompletedAt, + result = record.Result, + error = record.Error, + errorDetails = record.ErrorDetails, + progress, + // Corrective guidance for the caller (e.g. an unparseable omit_nulls value); + // null when there is nothing to say. + warnings = warning == null ? null : new[] { warning } + }; + } + } + + /// + /// Handle GET /api/job?id=… — a detached job's state, progress, and (once terminal) + /// its retained result (CLI-335 poll/reattach). Served on the listener thread. + /// + private async Task HandleJobStatusRequest(HttpListenerRequest request, HttpListenerResponse response) + { + try + { + var id = request.QueryString["id"]; + if (string.IsNullOrEmpty(id)) + { + await SendStatusResponse(response, 400, "Bad Request", "Query parameter 'id' is required"); + return; + } + if (!JobRegistry.TryGet(id, out var record)) + { + await SendStatusResponse(response, 404, "Job Not Found", $"No job with id '{id}' (jobs do not survive domain reloads and are pruned after retention)"); + return; + } + + var omitNulls = ParseOmitNulls(request, out var omitNullsWarning); + await SendJsonResponse(response, 200, BuildJobResponse(record, omitNullsWarning), omitNulls); + } + catch (Exception ex) + { + Debug.LogError($"HandleJobStatusRequest failed: {ex.Message}"); + await SendErrorResponse(response, "Job Status Error", $"Failed to get job status: {ex.Message}"); + } + } + + /// + /// Handle POST /api/job/cancel — request cancellation of a detached job (CLI-335). + /// A queued job never starts; a running job gets the cooperative + /// PipelineCancellation flag (synchronous code cannot be aborted from outside). + /// + private async Task HandleJobCancelRequest(HttpListenerRequest request, HttpListenerResponse response) + { + try + { + if (request.ContentLength64 > MaxCancelBodyBytes) + { + await DrainRequestBody(request, MaxDrainBytes); + await SendStatusResponse(response, 413, "Payload Too Large", + $"Request body exceeds the maximum allowed size of {MaxCancelBodyBytes} bytes"); + return; + } + + string body; + try + { + using (var limited = new MaxLengthStream(request.InputStream, MaxCancelBodyBytes, leaveOpen: true)) + using (var reader = new StreamReader(limited)) + { + body = await reader.ReadToEndAsync(); + } + } + catch (RequestTooLargeException ex) + { + await DrainRequestBody(request, MaxDrainBytes); + await SendStatusResponse(response, 413, "Payload Too Large", ex.Message); + return; + } + finally + { + request.InputStream.Dispose(); + } + + string id = null; + try + { + var parsed = JObject.Parse(string.IsNullOrEmpty(body) ? "{}" : body); + id = parsed["id"]?.ToString(); + } + catch (JsonException) + { + // Fall through to the missing-id error below. + } + + if (string.IsNullOrEmpty(id)) + { + await SendStatusResponse(response, 400, "Bad Request", "Request body must be JSON with an 'id' field"); + return; + } + if (!JobRegistry.RequestCancel(id, out var record)) + { + await SendStatusResponse(response, 404, "Job Not Found", $"No job with id '{id}'"); + return; + } + + var omitNulls = ParseOmitNulls(request, out var omitNullsWarning); + await SendJsonResponse(response, 200, BuildJobResponse(record, omitNullsWarning), omitNulls); + } + catch (Exception ex) + { + Debug.LogError($"HandleJobCancelRequest failed: {ex.Message}"); + await SendErrorResponse(response, "Job Cancel Error", $"Failed to cancel job: {ex.Message}"); + } + } + + /// + /// Handle /api/progress endpoint — the currently executing command's task progress + /// (CLI-488): the server side of the CLI's terminal progress bars, the pipeline + /// equivalent of EditorUtility.DisplayProgressBar. + /// + /// Served entirely on the listener thread from CliProgress's lock-protected snapshot — + /// never marshaled to the main thread — so it stays responsive while a long synchronous + /// command has the main thread blocked (exactly when progress matters most). + /// + /// Contract (all progress fields optional; pct is 0–1; an idle server returns + /// {"active":false,"progress":null}): + /// {"active":true,"progress":{"title":"…","info":"…","current":42,"total":100,"pct":0.42}} + /// + private async Task HandleProgressRequest(HttpListenerRequest request, HttpListenerResponse response) + { + try + { + var active = Progress.IsActive; + var progress = active ? BuildProgressPayload(Progress.Current) : null; + + var omitNulls = ParseOmitNulls(request, out var omitNullsWarning); + await SendJsonResponse(response, 200, new + { + active, + progress, + // Corrective guidance for the caller (e.g. an unparseable omit_nulls value); + // null when there is nothing to say. + warnings = omitNullsWarning == null ? null : new[] { omitNullsWarning } + }, omitNulls); + } + catch (Exception ex) + { + Debug.LogError($"HandleProgressRequest failed: {ex.Message}"); + await SendErrorResponse(response, "Progress Error", $"Failed to get progress: {ex.Message}"); + } + } + + /// + /// Handle /api/dialog endpoint — currently-open modal dialogs, mirroring /api/progress's + /// shape and thread-safety: served entirely from DialogStateTracker's lock-protected + /// state, never marshaled to the main thread, so it answers even while a synchronous + /// command has the main thread blocked inside a modal dialog (exactly when it matters + /// most). + /// + /// Contract: {"active":true,"dialogs":[{"id","source","title","message","level","buttons","openedAt","dismissedAt"}]} + /// + /// "active": false means no dialog of a COVERED kind is open, not that the Editor isn't + /// blocked by some other popup — coverage is mechanism-based (see + /// UnityEditor.EditorDialogEvents' remarks in trunk): native message boxes and EditorWindow + /// modals are covered; OS file/folder pickers and any other dialog mechanism are not. A + /// caller still needs a fallback signal (e.g. a command timeout) for the uncovered cases. + /// + private async Task HandleDialogRequest(HttpListenerResponse response) + { + try + { + var dialogs = Dialogs.CurrentlyOpen; + await SendJsonResponse(response, 200, new + { + active = dialogs.Count > 0, + dialogs = dialogs.Select(BuildDialogPayload).ToList() + }); + } + catch (Exception ex) + { + Debug.LogError($"HandleDialogRequest failed: {ex.Message}"); + await SendErrorResponse(response, "Dialog Error", $"Failed to get dialog state: {ex.Message}"); + } + } + + /// + /// Shared wire projection of a DialogInfo, used by /api/dialog, dialogsDuringExecution, the + /// busy-gate, and (internal, via InternalsVisibleTo) EditorPipelineServer's /api/status. + /// + internal static object BuildDialogPayload(DialogInfo info) => new + { + id = info.Id, + source = info.Source, + title = info.Title, + message = info.Message, + level = info.Level, + buttons = info.Buttons, + openedAt = info.OpenedAtUtc, + dismissedAt = info.DismissedAtUtc + }; + + /// Human-readable one-line summary of a dialog for the busy-gate message. Message/Level are null for a ManagedCustomWindow source, so both are omitted when absent. + private static string FormatDialogSummary(DialogInfo info) + { + var levelPrefix = string.IsNullOrEmpty(info.Level) ? "" : $"[{info.Level}] "; + var messageSuffix = string.IsNullOrEmpty(info.Message) ? "" : $": {info.Message}"; + return $"{levelPrefix}{info.Title}{messageSuffix}"; + } + + /// + /// Handle /api/exec endpoint - execute CLI commands with parameters. + /// + private async Task HandleExecRequest(HttpListenerRequest request, HttpListenerResponse response) + { + var cmd = ""; + // Stay false for pre-parse failures (413/empty/invalid JSON), which cannot honor the + // request's flags; set from the request as soon as it deserializes — before structure + // validation, so a verbose request gets a verbose validation failure. (AUTHAPI-21) + var verbose = false; + var omitNulls = false; + string requestBody = null; + // The execution half of the info reported to OnCommandDone. Both stay at their + // defaults on every branch that answers without running a command, and the timer is + // readable from the catch blocks below because it is started inside the gated body. + CommandInfo executed = null; + JObject executedParameters = null; + var timer = new System.Diagnostics.Stopwatch(); + try + { + // Reject oversized bodies up front via Content-Length (cheap, before reading anything). + if (request.ContentLength64 > MaxRequestBodyBytes) + { + // Drain the body first so the client can read the 413 (see DrainRequestBody). + await DrainRequestBody(request, MaxDrainBytes); + await SendExecResponse(response, 413, + BaseResponse.Failure("Payload Too Large", + $"Request body exceeds the maximum allowed size of {MaxRequestBodyBytes} bytes"), null); + return; + } + + // Read request body, enforcing the same cap while reading in case Content-Length is + // absent or untruthful (e.g. chunked transfer-encoding). + try + { + // leaveOpen: on an over-limit read we still need the raw InputStream open to drain + // the unsent remainder before responding, so it must outlive the reader/wrapper. + using (var limited = new MaxLengthStream(request.InputStream, MaxRequestBodyBytes, leaveOpen: true)) + using (var reader = new StreamReader(limited)) + { + requestBody = await reader.ReadToEndAsync(); + } + } + catch (RequestTooLargeException ex) + { + // Drain the body first so the client can read the 413 (see DrainRequestBody). + await DrainRequestBody(request, MaxDrainBytes); + await SendExecResponse(response, 413, + BaseResponse.Failure("Payload Too Large", ex.Message), null); + return; + } + finally + { + // MaxLengthStream left the InputStream open; dispose it now that any read/drain is done. + request.InputStream.Dispose(); + } + + if (string.IsNullOrEmpty(requestBody)) + { + await SendExecResponse(response, 400, + BaseResponse.Failure("Bad Request", "Request body is required"), requestBody); + return; + } + + // Parse command request + CommandExecutionRequest commandRequest; + try + { + commandRequest = JsonConvert.DeserializeObject(requestBody); + } + catch (JsonException ex) + { + await SendExecResponse(response, 400, + BaseResponse.Failure("Invalid JSON", $"Failed to parse request body: {ex.Message}"), requestBody); + return; + } + + // A body of literal JSON "null" parses without error but deserializes to null — + // reject it here so everything below can rely on a non-null request (previously + // this slid through the null-conditional validation and NRE'd at the Command read). + if (commandRequest == null) + { + await SendExecResponse(response, 400, + BaseResponse.Failure("Invalid Request", "Request body must be a JSON object"), requestBody); + return; + } + + // Honor the reply-shape flags from here on: the request has deserialized, so even + // the structure-validation failure below can respect them. + verbose = commandRequest.Verbose; + omitNulls = commandRequest.OmitNulls; + + // Validate request structure + var requestValidationError = commandRequest.Validate(); + if (!string.IsNullOrEmpty(requestValidationError)) + { + await SendExecResponse(response, 400, + BaseResponse.Failure("Invalid Request", requestValidationError), requestBody, verbose, omitNulls); + return; + } + + // Raw command-line forms. Tokenize `commandLine`, or take `argv` as-is (it is + // already split; re-splitting would corrupt any value containing a space), then + // normalize the request IN PLACE by assigning the command name. Normalizing here + // rather than deeper down is what leaves the rest of this method unchanged: + // RunJobDetached re-reads commandRequest, so `job` needs no special handling, and + // the CmdSuccess command echo stays correct. + // + // Placed after Validate() so transport concerns do not depend on the command + // registry, after the reply-shape flags are captured so a malformed line still + // honours verbose/omitNulls, and before ResolveCommand so an unknown raw command + // name produces the same Command Not Found envelope as the structured path. + List rawTokens = null; + if (commandRequest.IsRawForm) + { + if (commandRequest.Argv != null) + { + rawTokens = commandRequest.Argv; + } + else if (!CommandLineTokenizer.TryTokenize(commandRequest.CommandLine, out rawTokens, out var tokenizeError)) + { + // Reported as a malformed request shape, not as an argument error: no + // command was resolved, so there is no schema and no argProblems to carry. + // INVALID_COMMAND_ARGS promises a client both of those. + await SendExecResponse(response, 400, + BaseResponse.Failure("Invalid Request", tokenizeError), + requestBody, verbose, omitNulls); + return; + } + + // A blank first token is as malformed as no token at all, and it is reachable: + // a commandLine of `"" --message hi` is a NONBLANK source string, so Validate() + // passes, yet it tokenizes to an empty command name. Left unchecked that became + // a Command Not Found, telling the caller an empty command is merely + // unavailable. `argv` with an empty first element is already rejected by + // Validate(), so both raw forms answer the same way here. + if (rawTokens.Count == 0 || string.IsNullOrWhiteSpace(rawTokens[0])) + { + await SendExecResponse(response, 400, + BaseResponse.Failure("Invalid Request", "Command name is required"), + requestBody, verbose, omitNulls); + return; + } + + commandRequest.Command = rawTokens[0]; + } + + cmd = commandRequest.Command; + + // Resolve the command once — the busy gate and the execution path share this + // single registry lookup instead of scanning twice per request. An unknown name + // throws here and surfaces as the usual Command Not Found via the catch below + // (for a "job": true submission that now happens BEFORE a job is created, so a + // misnamed command fails fast instead of producing a job that fails later). + var command = ResolveCommand(cmd); + + // Bind the remaining tokens and normalize in place, so everything from + // ExtractCommandParameters downwards sees exactly one shape. + // + // Before the busy gate: a malformed command line is a deterministic client fault, + // and answering 503-retryable first would send clients into a retry loop over an + // error that will never clear. Also before job creation, so a mistyped parameter + // can never return a job id and exit 0. + if (rawTokens != null) + { + var args = rawTokens.GetRange(1, rawTokens.Count - 1); + if (!CommandLineBinder.TryBind(command, args, out var bound, out var argProblems)) + { + await SendExecResponse(response, 400, + CommandExecutionResponse.CmdInvalidArgs(cmd, + DescribeArgProblems(command, argProblems), argProblems, + BuildCommandEntry(command)), + requestBody, verbose, omitNulls); + return; + } + + commandRequest.Parameters = bound; + + // Refuse a known-invalid raw submission before the busy gate and before job + // creation. Binding SUCCEEDS when a required parameter simply was not supplied + // — that rule belongs to parameter validation, not the binder — so without + // this check `{"argv":["log_editor"],"job":true}` reached job creation, was + // acknowledged with a job id and a 200, and only failed later inside the + // detached run. The client would be told a deterministically invalid request + // had been accepted. + var missingRequired = ValidateRequiredParametersBound(command, bound); + if (!string.IsNullOrEmpty(missingRequired)) + { + await SendExecResponse(response, 400, + CommandExecutionResponse.CmdFailure(cmd, "Parameter Validation Failed", missingRequired), + requestBody, verbose, omitNulls); + return; + } + } + + // Dialog busy gate: checked before the settling gate below. A modal dialog genuinely + // blocks the main thread inside a nested OS message loop (unlike settling, which + // merely delays), so it's true regardless of settle state and is the more actionable + // fact for a caller — settling resolves on its own, a dialog needs a human. + // TryGetDialogBlockedFallback is the one exception: a command whose result can be + // served from a cached snapshot instead of running for real (editor_status). + if (command.MainThreadRequired) + { + var openDialogs = Dialogs.CurrentlyOpen; + if (openDialogs.Count > 0) + { + object fallback = TryGetDialogBlockedFallback(command, openDialogs[0]); + if (fallback != null) + { + await SendExecResponse(response, 200, + WithBoundParameters( + CommandExecutionResponse.CmdSuccess(cmd, fallback), commandRequest), + requestBody, verbose, omitNulls); + return; + } + + var summary = FormatDialogSummary(openDialogs[0]); + var separator = summary.EndsWith(".") || summary.EndsWith("!") || summary.EndsWith("?") ? " " : ". "; + var busyResponse = CommandExecutionResponse.CmdBusy(cmd, + $"A modal dialog is currently open and blocking the main thread: {summary}{separator}" + + "Poll GET /api/dialog for details, or retry once it is dismissed.", + "blocked_by_dialog"); + busyResponse.Dialogs = openDialogs.Select(BuildDialogPayload).ToList(); + await SendExecResponse(response, 503, busyResponse, requestBody, verbose, omitNulls); + return; + } + } + + // Busy gate (AUTHAPI-35): while the host is settling after startup, reject + // not-yet-serviceable commands up front — before sync execution AND before a + // detached job is created (a queued job would otherwise run into the half-ready + // Editor in the background). 503 with a retryable envelope, distinguishable from + // a genuine command failure. Only the exec endpoint gates; the status endpoints + // keep working so the busy state itself stays observable. + var busyReason = GetBusyReason(command); + if (busyReason != null) + { + // The busy reply is a standard exec envelope, so it follows the request's + // reply-shape flags like every other branch: lean drops the command echo and + // envelope metadata; verbose restores them (AUTHAPI-21 x AUTHAPI-35). + await SendExecResponse(response, 503, + CommandExecutionResponse.CmdBusy(cmd, busyReason, "settling"), requestBody, verbose, omitNulls); + return; + } + + // Detached job (CLI-335): reply with a job id immediately and run the command + // in the background — the client polls GET /api/job?id=… to reattach and + // collect the result after its own HTTP timeout would have expired. + if (commandRequest.Job) + { + if (!JobRegistry.TryCreate(commandRequest.Command, out var jobRecord)) + { + await SendExecResponse(response, 429, + CommandExecutionResponse.CmdFailure(commandRequest.Command, "Too Many Queued Jobs", + "Too many jobs are queued or running; wait for some to finish and retry."), requestBody, verbose, omitNulls); + return; + } + _ = RunJobDetached(jobRecord, command, commandRequest); + // Standard exec envelope; the job handle is the command's "result". + await SendExecResponse(response, 200, + WithBoundParameters( + CommandExecutionResponse.CmdSuccess(commandRequest.Command, + new { jobId = jobRecord.Id, state = "queued" }), commandRequest), + requestBody, verbose, omitNulls); + return; + } + + // Execute command using shared execution logic (see ExecuteGated: one command at + // a time, exactly as when the accept loop was serial). + DateTime execStartUtc = default; + object result = null; + await ExecuteGated(Guid.NewGuid().ToString("N"), async () => + { + // Claimed here rather than before ExecuteGated, so that a request which never + // gets past the gate reports no execution at all, and so that the wait for the + // one-at-a-time gate counts as queueing rather than as time the command ran. + executed = command; + executedParameters = commandRequest.Parameters; + execStartUtc = DateTime.UtcNow; + timer.Start(); + try + { + result = await ExecuteCommandByName(command, commandRequest.Parameters, + commandRequest.Timeout ?? 60000); + } + finally + { + timer.Stop(); + } + }); + + // Send success response, attaching any dialog(s) that opened during this call + // (dialogsDuringExecution) so a caller learns about them even without polling + // /api/dialog concurrently while the call was in flight. + var successResponse = WithBoundParameters( + CommandExecutionResponse.CmdSuccess(commandRequest.Command, result), commandRequest); + var dialogEvents = Dialogs.EventsSince(execStartUtc); + if (dialogEvents.Count > 0) + successResponse.DialogsDuringExecution = dialogEvents.Select(BuildDialogPayload).ToList(); + + await SendExecResponse(response, 200, successResponse, requestBody, verbose, omitNulls, + executed, IsSuccessfulResult(result), timer.ElapsedMilliseconds, commandRequest.Parameters); + } + catch (ArgumentException ex) + { + // Parameter validation errors + await SendExecResponse(response, 400, + CommandExecutionResponse.CmdFailure(cmd, "Parameter Validation Failed", ex.Message), requestBody, verbose, omitNulls, + executed, false, timer.ElapsedMilliseconds, executedParameters); + } + catch (InvalidOperationException ex) when (ex.Message.Contains("No command named")) + { + // Command not found errors + await SendExecResponse(response, 400, + CommandExecutionResponse.CmdFailure(cmd, "Command Not Found", ex.Message), requestBody, verbose, omitNulls, + executed, false, timer.ElapsedMilliseconds, executedParameters); + } + catch (InvalidOperationException ex) + { + // Command execution errors + await SendExecResponse(response, 400, + CommandExecutionResponse.CmdFailure(cmd, "Command Execution Failed", ex.Message), requestBody, verbose, omitNulls, + executed, false, timer.ElapsedMilliseconds, executedParameters); + } + catch (Exception ex) + { + Debug.LogError($"Failed to handle /api/exec request: {ex.Message}"); + await SendExecResponse(response, 400, + CommandExecutionResponse.CmdFailure(cmd, "Internal Server Error", ex.Message), requestBody, verbose, omitNulls, + executed, false, timer.ElapsedMilliseconds, executedParameters); + } + } + + /// + /// Read and discard the remaining request body, up to bytes. + /// When we reject a request early (e.g. 413) the client may still be uploading; if we close the + /// response while unread data is in flight, HttpListener resets the TCP connection and the client + /// sees a connection error instead of our HTTP response. Draining lets the upload complete so the + /// response is delivered. Best-effort and bounded: a body larger than the budget stops draining + /// (and may reset), which is acceptable for an abusive request. + /// + private static async Task DrainRequestBody(HttpListenerRequest request, long maxDrainBytes) + { + try + { + var input = request.InputStream; + var buffer = new byte[16 * 1024]; + long drained = 0; + while (drained < maxDrainBytes) + { + var read = await input.ReadAsync(buffer, 0, buffer.Length); + if (read <= 0) + break; + drained += read; + } + } + catch + { + // Best-effort: if the client already closed the connection or the stream is gone, + // there is nothing left to drain and the response send below will handle the rest. + } + } + + /// + /// Send error response with structured JSON format. + /// + private async Task SendErrorResponse(HttpListenerResponse response, string error, string details = null, int statusCode = 400) + { + try + { + var errorResponse = BaseResponse.Failure(error, details); + await SendResponse(response, statusCode, errorResponse); + } + catch + { + // Ignore errors in error handling + } + } + + private async Task SendResponse(HttpListenerResponse response, int statusCode, BaseResponse pipelineResponse) + { + response.StatusCode = statusCode; + response.ContentType = "application/json"; + var json = JsonConvert.SerializeObject(pipelineResponse, Formatting.Indented); + var buffer = Encoding.UTF8.GetBytes(json); + response.ContentLength64 = buffer.Length; + + await response.OutputStream.WriteAsync(buffer, 0, buffer.Length); + response.OutputStream.Close(); + } + + /// + /// Send an /api/exec response and report the finished interaction to + /// . Single send point for the exec handler so every branch + /// (success and error) is captured uniformly. + /// + /// The executed* arguments carry the execution half of the info. Branches that reject a + /// request before any command runs (413, malformed body, busy host, job queue full) leave + /// them at their defaults, which reports an info with no command. + /// + private async Task SendExecResponse(HttpListenerResponse response, int statusCode, + BaseResponse body, string requestJson, bool verbose = false, bool omitNulls = false, + CommandInfo executedCommand = null, bool executedSuccess = false, long executedDurationMs = 0, + JObject executedParameters = null) + { + response.StatusCode = statusCode; + response.ContentType = "application/json"; + // Lean, compact serialization by default; the request's `verbose` flag opts into the + // full envelope and `omitNulls` drops payload nulls. Single contract shared with the + // byte-size regression test. (AUTHAPI-21) + var json = ExecResponseSerializer.Serialize(body, verbose, omitNulls); + var buffer = Encoding.UTF8.GetBytes(json); + response.ContentLength64 = buffer.Length; + + await response.OutputStream.WriteAsync(buffer, 0, buffer.Length); + response.OutputStream.Close(); + + OnCommandDone(new CommandExecutionInfo(requestJson, json, executedCommand, executedSuccess, executedDurationMs, + executedParameters)); + } + + /// + /// Hook invoked once per finished /api/exec interaction, and once more when a detached job + /// completes. The single place to hang post-command work: the Editor server writes the + /// transaction log here and queues its analytics from here. No-op by default (the Player + /// does neither). + /// + /// Runs on the background HTTP thread, so an implementation must either stick to + /// thread-safe work or marshal to the main thread itself. It must also never throw — + /// an exception here would surface as a failed request for work the caller never asked for. + /// + /// The finished interaction: its transaction, its execution, or both. + protected virtual void OnCommandDone(in CommandExecutionInfo info) { } + + /// + /// Whether a command reported success. A command fails in two ways: by throwing, which the + /// caller has already accounted for, or by RETURNING a response that carries its own + /// failure — eval, code reload, run_script and test runs all do the latter, so nothing + /// throws and the outer envelope says success while the inner result says otherwise. + /// + private static bool IsSuccessfulResult(object result) + { + switch (result) + { + case CommandExecutionResponse commandResponse: + return commandResponse.Success; + case BaseResponse baseResponse: + return string.IsNullOrEmpty(baseResponse.Error); + default: + return true; + } + } + + /// + /// Convert a single JSON parameter token to the command's parameter type. + /// + /// Agents and the CLI frequently pass structured parameters (e.g. float[] position, + /// JObject properties) as a JSON-ENCODED STRING — e.g. position "[0,0,0]" or + /// properties "{\"m_Mass\":0.17}". Newtonsoft's JValue(string).ToObject(float[]) + /// (and likewise for JObject) returns null, so the parameter silently drops out: + /// set_transform applies nothing and set_component_properties fails Required-parameter + /// validation (CLI-219 / CLI-220). To fix this generally — without special-casing any command — + /// when the token is a string but the target type is NOT string AND the trimmed string starts + /// with '{' or '[', we re-parse it as a JSON document before converting. + /// + /// The '{'/'[' guard is deliberate and narrow: ordinary string params (and ObjectRef string + /// handles like "/Player", "Assets/Foo.prefab", "guid:..." — none of which start with '{'/'[') + /// fall straight through to token.ToObject, so the class-level + /// and plain-string parameters keep + /// working unchanged. A re-parse that fails falls through to the normal conversion path (the + /// caller's try/catch then handles any remaining failure). + /// + /// + /// Internal rather than private so can DRY-RUN the exact + /// converter the executor will use. Binding against a different conversion would let a + /// command line pass validation and then fail during execution. + /// + internal static object ConvertParameterToken(Newtonsoft.Json.Linq.JToken token, System.Type targetType) + { + if (token == null) + return null; + + if (token.Type == Newtonsoft.Json.Linq.JTokenType.String + && targetType != typeof(string) + && !targetType.IsPrimitive + && !targetType.IsEnum) + { + var s = token.Value(); + if (!string.IsNullOrWhiteSpace(s)) + { + var t = s.TrimStart(); + if (t.Length > 0 && (t[0] == '{' || t[0] == '[')) + { + try { return Newtonsoft.Json.Linq.JToken.Parse(s).ToObject(targetType); } + catch (Newtonsoft.Json.JsonException) { /* fall through to the direct conversion */ } + } + } + } + + return token.ToObject(targetType); + } + + /// + /// Extract command parameters from JSON request and convert to appropriate types. + /// reports arguments that could not be converted to + /// the parameter's type. Substituting the default there gives the caller a different result + /// than it asked for with no way to detect it — an ignored limit returns more than was + /// asked, an ignored timeout waits longer than allowed. The slot still gets the default + /// so the array stays well-formed, but the callers reject the request. + /// + private object[] ExtractCommandParameters(CommandInfo command, Newtonsoft.Json.Linq.JObject parametersJson, out string conversionError) + { + StringBuilder conversionErrors = null; + var parameterValues = new object[command.Parameters.Count]; + + for (int i = 0; i < command.Parameters.Count; i++) + { + var paramInfo = command.Parameters[i]; + var paramName = paramInfo.Name; + + // Try to get value from JSON parameters + object jsonValue = null; + if (parametersJson != null && parametersJson.ContainsKey(paramName)) + { + var token = parametersJson[paramName]; + try + { + jsonValue = ConvertParameterToken(token, paramInfo.ParameterType); + + // A converter can DECLINE a token by returning null instead of throwing — + // ObjectRefConverter does exactly that for unsupported kinds, so + // {"parent": true} would otherwise read as an omitted argument and the + // command would run against the default. Anything that converts to null + // without being one of the intentional null forms is a conversion failure. + if (jsonValue == null && !IsIntentionalNullToken(token)) + { + RecordConversionError(ref conversionErrors, paramName, paramInfo, + $"unsupported JSON value ({token.Type})"); + } + } + catch (Exception ex) + { + // Record it rather than logging and moving on: a console warning is invisible + // to the HTTP caller, which is the only party that can act on it. + RecordConversionError(ref conversionErrors, paramName, paramInfo, ex.Message); + } + } + + // Use provided value or default value + if (jsonValue != null) + { + parameterValues[i] = jsonValue; + } + else if (paramInfo.DefaultValue != null) + { + parameterValues[i] = paramInfo.DefaultValue; + } + else + { + // Use type's default value for value types, null for reference types + parameterValues[i] = paramInfo.ParameterType.IsValueType + ? Activator.CreateInstance(paramInfo.ParameterType) + : null; + } + } + + conversionError = conversionErrors?.ToString(); + return parameterValues; + } + + /// + /// The token forms a converter may legitimately turn into null, as opposed to declining a + /// value it cannot represent: an explicit JSON null, and an empty or whitespace-only string. + /// The latter is a documented contract, not a quirk — ObjectRefConverter.FromString + /// returns null for it, and set_parent advertises "Omit (or empty) to move the object + /// to the scene root", so {"parent":""} must keep detaching rather than 400. + /// + private static bool IsIntentionalNullToken(JToken token) + { + if (token == null || token.Type == JTokenType.Null) + return true; + + return token.Type == JTokenType.String && string.IsNullOrWhiteSpace(token.Value()); + } + + /// Appends one parameter-conversion failure to the accumulated report. + private static void RecordConversionError( + ref StringBuilder errors, string paramName, CommandParameterInfo paramInfo, string detail) + { + if (errors == null) + errors = new StringBuilder(); + else + errors.Append("; "); + errors.Append( + $"Parameter '{paramName}' could not be converted to {paramInfo.ParameterType.Name}: {detail}"); + } + + /// + /// The one wording for a missing required parameter. Shared by the two validators below so + /// the structured and raw request forms cannot diagnose the same mistake differently. + /// + private static string MissingRequiredParameterMessage(string parameterName) + { + return $"Required parameter '{parameterName}' is missing or empty"; + } + + /// + /// Validates required parameters against a BOUND parameter object, before anything runs. + /// + /// applies the same rule to already-extracted CLR + /// values, but it runs inside command execution — which for a detached job is after the job + /// id has already been handed to the client. A raw submission missing a required parameter + /// would be acknowledged as accepted and only fail later, in the background. Checking the + /// bound object first lets that request be refused up front, with the same envelope the + /// synchronous path produces. + /// + /// The rule itself is shared, not reimplemented: both this and the extracted-value check + /// normalize to a CLR value and call , so the raw and + /// structured paths cannot drift on what counts as missing. + /// + private static string ValidateRequiredParametersBound(CommandInfo command, JObject parameters) + { + for (var i = 0; i < command.Parameters.Count; i++) + { + var paramInfo = command.Parameters[i]; + if (!paramInfo.Required) + continue; + + if (IsMissingRequiredValue(AsRequiredValue(parameters?[paramInfo.Name]))) + { + return MissingRequiredParameterMessage(paramInfo.Name); + } + } + + return null; + } + + /// + /// The one rule for "this required parameter was not supplied": absent, null, or the empty + /// string. Both the bound-JSON and extracted-CLR checks normalize to a CLR value and share + /// this, so a future change to what counts as missing cannot be applied to one path and + /// forgotten on the other. + /// + private static bool IsMissingRequiredValue(object value) + { + return value == null || (value is string text && string.IsNullOrEmpty(text)); + } + + /// + /// A bound JSON value as the CLR value expects. A JSON + /// null is a CLR null; a JSON string is its text; anything else is present by definition + /// and stands in for itself. + /// + private static object AsRequiredValue(JToken value) + { + if (value == null || value.Type == JTokenType.Null) + return null; + return value.Type == JTokenType.String ? value.Value() : (object)value; + } + + /// + /// Validate that all required command parameters are provided. + /// + private string ValidateCommandParameters(CommandInfo command, object[] parameters) + { + for (int i = 0; i < command.Parameters.Count; i++) + { + var paramInfo = command.Parameters[i]; + + if (paramInfo.Required && IsMissingRequiredValue(parameters[i])) + { + return MissingRequiredParameterMessage(paramInfo.Name); + } + } + + return null; // No validation errors + } + + /// + /// Resolve a command name to its , or throw the standard + /// Command Not Found error. Single registry scan — /api/exec resolves once and shares + /// the result between the busy gate and execution. + /// + private static CommandInfo ResolveCommand(string commandName) + { + var commands = CommandRegistry.DiscoverCommands().ToList(); + var command = commands.FirstOrDefault(c => c.Name == commandName); + if (command == null) + { + var availableCommands = string.Join(", ", commands.Select(c => c.Name)); + var errorMessage = $"No command named '{commandName}' is available. Available: [{availableCommands}]"; + Debug.LogError($"ExecuteCommandByName: {errorMessage}"); + throw new InvalidOperationException(errorMessage); + } + return command; + } + + /// + /// Execute a command by name with JSON parameters. + /// Handles command lookup, parameter validation, and execution. + /// Used by callers that only hold a name (status endpoints, detached job runner); the + /// /api/exec handler resolves the command itself and uses the CommandInfo overload. + /// + private async Task ExecuteCommandByName(string commandName, JObject parametersJson, int dispatcherTimeoutMs = 60000) + { + return await ExecuteCommandByName(ResolveCommand(commandName), parametersJson, dispatcherTimeoutMs); + } + + /// + /// Execute a pre-resolved command with JSON parameters (parameter extraction, required + /// validation, threading). + /// + private async Task ExecuteCommandByName(CommandInfo command, JObject parametersJson, int dispatcherTimeoutMs = 60000) + { + // Extract parameters + var parameters = ExtractCommandParameters(command, parametersJson, out var conversionError); + + // Reject unconvertible arguments rather than silently running with the default + if (!string.IsNullOrEmpty(conversionError)) + { + Debug.LogError($"ExecuteCommandByName: Parameter conversion failed: {conversionError}"); + throw new ArgumentException(conversionError); + } + + // Validate required parameters + var validationError = ValidateCommandParameters(command, parameters); + if (!string.IsNullOrEmpty(validationError)) + { + Debug.LogError($"ExecuteCommandByName: Parameter validation failed: {validationError}"); + throw new ArgumentException(validationError); + } + + // Execute command with appropriate threading + return await ExecuteCommand(command, parameters, dispatcherTimeoutMs); + } + + /// + /// Execute the command method with provided parameters. + /// Handles main thread execution if required. + /// + private async Task ExecuteCommand(CommandInfo command, object[] parameters, int dispatcherTimeoutMs = 60000) + { + object raw; + if (command.MainThreadRequired) + { + // Execute on the main thread using THIS server's dispatcher. + if (m_Dispatcher.IsMainThread()) + { + raw = ExecuteCommandDirect(command, parameters); + } + else + { + // If the command declares its own int "timeout" parameter (e.g. eval/eval_file), + // honor it as the wait budget instead of the caller-provided dispatcher budget + // (UUM-148641) — that's the only mechanism that actually enforces such a + // command's requested deadline end-to-end, in both directions: a request below + // the dispatcher default must time out early, not wait it out. Detached jobs + // are the one exception: they pass an unbounded budget (CLI-335) and rely on + // cooperative cancellation, so the requested value must not re-bound them. + var requestedTimeoutMs = ResolveRequestedTimeoutMs(command, parameters); + var waitBudgetMs = dispatcherTimeoutMs == UnboundedJobDispatcherTimeoutMs + ? dispatcherTimeoutMs + : requestedTimeoutMs ?? dispatcherTimeoutMs; + raw = await Task.Run(() => m_Dispatcher.Invoke(() => ExecuteCommandDirect(command, parameters), waitBudgetMs)); + } + } + else + { + // Execute on background thread + raw = await Task.Run(() => ExecuteCommandDirect(command, parameters)); + } + + return await UnwrapResult(raw); + } + + /// + /// Commands whose own "timeout" parameter is documented in milliseconds and is meant to bound + /// the whole main-thread call. Other commands happen to also declare a "timeout" parameter + /// (e.g. run_tests, in seconds) with different semantics, so this can't be a blanket + /// name/type match — it has to be opted into per command. + /// + private static readonly HashSet CommandsWithMillisecondTimeoutParameter = new HashSet { "eval", "eval_file", "run_script" }; + + /// + /// For commands in , return the value the + /// caller passed for their own "timeout" parameter. Returns null otherwise, in which case the + /// caller should fall back to Dispatcher.Invoke's own default wait. + /// + private static int? ResolveRequestedTimeoutMs(CommandInfo command, object[] parameters) + { + if (!CommandsWithMillisecondTimeoutParameter.Contains(command.Name)) + return null; + + for (int i = 0; i < command.Parameters.Count; i++) + { + // eval/eval_file name their budget "timeout"; run_script names it "timeout_ms". + var pName = command.Parameters[i].Name; + if ((pName == "timeout" || pName == "timeout_ms") && command.Parameters[i].ParameterType == typeof(int)) + { + // A non-positive value cannot be a meaningful wait budget. Forwarding it would + // make Dispatcher.Invoke fail with its own opaque timeout before the command + // ever runs — fall back to the default budget instead, so the command's own + // friendly "timeout must be between …" validation is what answers the caller. + var requested = (int)parameters[i]; + return requested > 0 ? requested : (int?)null; + } + } + + return null; + } + + /// + /// Commands declared as `async Task`/`Task<T>` return their Task from reflection Invoke. + /// Await it here (on the calling background thread, leaving the main thread free to pump the + /// dispatcher) so the actual value is serialized rather than the Task itself, and so a faulted + /// command surfaces its real exception to the request handler instead of being masked when + /// Newtonsoft reads Task.Result during serialization. + /// + private static async Task UnwrapResult(object result) + { + if (result is Task task) + { + await task.ConfigureAwait(false); + // Task<T> exposes a Result property; non-generic Task does not. + var resultProperty = task.GetType().GetProperty("Result"); + return resultProperty?.GetValue(task); + } + + return result; + } + + /// + /// Extract, validate, and invoke a pre-resolved command with JSON parameters synchronously on + /// the current main thread, returning its unwrapped result. This is the exact parameter + /// extraction, required-parameter validation, reflection invoke, and Task unwrap that the + /// /api/exec path () uses, + /// exposed for composite commands (e.g. batch) that re-dispatch other registered + /// commands from inside their own main-thread execution — so each sub-operation behaves, and + /// its result is shaped, identically to a standalone call. + /// + /// MUST be called on the main thread. A composite command is itself + /// MainThreadRequired, so it already runs there; calling off the main thread throws. + /// A command that throws surfaces exactly as it would through /api/exec + /// ( preserved, other exceptions wrapped in + /// ) so the caller can record a per-operation failure. + /// + internal object DispatchCommandOnMainThread(CommandInfo command, JObject parametersJson) + { + if (command == null) + throw new ArgumentNullException(nameof(command)); + if (!m_Dispatcher.IsMainThread()) + throw new InvalidOperationException( + "DispatchCommandOnMainThread must be called on the main thread."); + + var parameters = ExtractCommandParameters(command, parametersJson, out var conversionError); + + // Same contract as ExecuteCommandByName: an argument that could not be converted is a + // rejected request, not a silent fallback to the parameter's default. + if (!string.IsNullOrEmpty(conversionError)) + throw new ArgumentException(conversionError); + + var validationError = ValidateCommandParameters(command, parameters); + if (!string.IsNullOrEmpty(validationError)) + throw new ArgumentException(validationError); + + var raw = ExecuteCommandDirect(command, parameters); + // Unwrap a Task result inline. WARNING: this GetResult() blocks the main thread, so it is + // only safe for results that are already complete (synchronous commands, or async methods + // that happened to complete synchronously). An async command driven to completion by + // EditorApplication.update callbacks (run_tests/list_tests) could NEVER finish here — + // update cannot pump while this call blocks — and the Editor would freeze permanently. + // That is why composite callers (batch) must reject commands with Task return types + // before dispatching them through this path. + return UnwrapResult(raw).GetAwaiter().GetResult(); + } + + /// + /// Direct command execution using reflection. Sets for the + /// duration so CliProgress/PipelineCancellation calls inside the command body resolve to + /// this server, regardless of which thread this ends up running on. + /// + private object ExecuteCommandDirect(CommandInfo command, object[] parameters) + { + var previousServer = m_CurrentServer; + m_CurrentServer = this; + try + { + // Target is null for every attribute-declared command (they are static) and carries + // the receiver for a dynamically registered instance-method handler. + return command.Method.Invoke(command.Target, parameters); + } + catch (System.Reflection.TargetInvocationException tie) when (tie.InnerException != null) + { + // Reflection wraps the command's own exception in a TargetInvocationException; surface + // the inner message so callers (and agents) get an actionable error instead of the + // generic "Exception has been thrown by the target of an invocation." + var inner = tie.InnerException; + Debug.LogError($"Command '{command.Name}' failed: {inner.Message}"); + + // Preserve validation-oriented exceptions so HandleExecRequest's dedicated + // catch (ArgumentException) classifies them as "Parameter Validation Failed" rather than + // collapsing them into "Command Execution Failed". Rethrow the original with its stack. + if (inner is ArgumentException) + System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(inner).Throw(); + + throw new InvalidOperationException($"Command '{command.Name}' failed: {inner.Message}", inner); + } + catch (Exception ex) + { + Debug.LogError($"Command execution failed: {ex.Message}"); + throw new InvalidOperationException($"Command '{command.Name}' failed: {ex.Message}", ex); + } + finally + { + m_CurrentServer = previousServer; + } + } + + + /// + /// Get the port range for this server type. + /// Editor servers use 7800-7899, Runtime servers use 7900-7999. + /// + /// The inclusive port range to try when binding the listener. + protected virtual (int basePort, int maxPort) GetPortRange() + { + return (7800, 7849); // Editor production (test editor servers use 7850-7899) + } + + /// + /// Find an available port in the pipeline server range. + /// + private int FindAvailablePort() + { + var (basePort, maxPort) = GetPortRange(); + + for (int port = basePort; port <= maxPort; port++) + { + if (IsPortAvailable(port)) + { + return port; + } + } + + throw new InvalidOperationException($"No available ports in range {basePort}-{maxPort}"); + } + + /// + /// Check if a specific port is available for binding. + /// + private bool IsPortAvailable(int port) + { + try + { + using (var listener = new HttpListener()) + { + AddLoopbackPrefixes(listener, port); + listener.Start(); + listener.Stop(); + return true; + } + } + catch + { + return false; + } + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/BasePipelineServer.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Common/BasePipelineServer.cs.meta new file mode 100644 index 0000000..85365bd --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/BasePipelineServer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b6905de2a6949fc40bea9d708751b0fe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/CliArgAttribute.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CliArgAttribute.cs new file mode 100644 index 0000000..9a17523 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CliArgAttribute.cs @@ -0,0 +1,51 @@ +using System; + +namespace Unity.Pipeline.Commands +{ + /// + /// Attribute to mark parameters of CLI command methods. + /// Provides parameter metadata for CLI validation and help generation. + /// Adapted from unity-tools [Parameter] attribute for Pipeline organization requirements. + /// + /// Also valid on the fields/properties of an DTO, where it + /// describes a member of a nested object schema (same Name/Description/Required semantics). + /// + [AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false)] + public class CliArgAttribute : Attribute + { + /// + /// Name of the parameter as it appears in CLI arguments. + /// Used in "unity request command_name --param_name value" syntax. + /// + public string Name { get; } + + /// + /// Human-readable description of the parameter. + /// Used in CLI help text and parameter documentation. + /// + public string Description { get; } + + /// + /// Whether this parameter is required for command execution. + /// Default: false (parameter is optional). + /// + public bool Required { get; set; } = false; + + /// + /// Default value for the parameter if not provided. + /// Must be compatible with the parameter type. + /// + public object DefaultValue { get; set; } + + /// + /// Create a new CLI parameter attribute. + /// + /// Parameter name for CLI arguments + /// Human-readable description + public CliArgAttribute(string name, string description) + { + Name = name ?? throw new ArgumentNullException(nameof(name)); + Description = description ?? throw new ArgumentNullException(nameof(description)); + } + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/CliArgAttribute.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CliArgAttribute.cs.meta new file mode 100644 index 0000000..debe1ba --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CliArgAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ac8886d9f7e92d844b4f1728ce2e2cab +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/CliCommandAttribute.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CliCommandAttribute.cs new file mode 100644 index 0000000..c35c534 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CliCommandAttribute.cs @@ -0,0 +1,57 @@ +using System; + +namespace Unity.Pipeline.Commands +{ + /// + /// Attribute to mark static methods as CLI-accessible commands. + /// Commands with this attribute can be executed remotely via Pipeline Server. + /// Adapted from unity-tools [Tool] attribute for Pipeline organization requirements. + /// + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public class CliCommandAttribute : Attribute + { + /// + /// Unique name of the command for CLI execution. + /// Used in "unity request command_name" syntax. + /// + public string Name { get; } + + /// + /// Human-readable description of what the command does. + /// Used in CLI help text and command discovery. + /// + public string Description { get; } + + /// + /// Whether this command requires Unity main thread execution. + /// Default: true (most Unity APIs require main thread). + /// + public bool MainThreadRequired { get; set; } = true; + + /// + /// Whether this command belongs to the runtime (Player) command surface only. + /// Runtime-only commands are hidden from an Editor server's command listing + /// (they remain executable, but are not advertised when connected to an Editor). + /// Default: false (listed on the Editor server). + /// + public bool RuntimeOnly { get; set; } = false; + + /// + /// Optional hierarchical tags used to group and browse commands. + /// Path-style: a '/' separates tag from subtag (e.g. "assets", "assets/import"). + /// Default: empty (untagged). + /// + public string[] Tags { get; set; } = Array.Empty(); + + /// + /// Create a new CLI command attribute. + /// + /// Unique command name for CLI execution + /// Human-readable description + public CliCommandAttribute(string name, string description) + { + Name = name ?? throw new ArgumentNullException(nameof(name)); + Description = description ?? throw new ArgumentNullException(nameof(description)); + } + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/CliCommandAttribute.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CliCommandAttribute.cs.meta new file mode 100644 index 0000000..325d86d --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CliCommandAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ee4da62af1984f442af8ada30f3eee83 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/CliProgress.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CliProgress.cs new file mode 100644 index 0000000..877fc66 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CliProgress.cs @@ -0,0 +1,234 @@ +using System; + +namespace Unity.Pipeline +{ + /// + /// Per-server progress-reporting state. Owned one-per- (the + /// same pattern as Dispatcher) so a test server's execution can never cross-attribute + /// progress with the live server's. See for the public static + /// façade that arbitrary command code calls. + /// + internal sealed class CliProgressState + { + /// Immutable copy of the current progress state (thread-safe to hand across threads). + internal readonly struct Snapshot + { + public readonly bool HasReport; + public readonly string Title; + public readonly string Info; + public readonly long? Current; + public readonly long? Total; + public readonly double? Progress01; + + public Snapshot(string title, string info, long? current, long? total, double? progress01) + { + HasReport = true; + Title = title; + Info = info; + Current = current; + Total = total; + Progress01 = progress01; + } + } + + readonly object m_Gate = new object(); + Snapshot m_Explicit; + string m_ExplicitOwnerId; + string m_CurrentOwnerId; + Snapshot m_Ambient; + int m_ActiveCount; + + /// Whether any execution is currently in flight. Read by /api/progress. + internal bool IsActive + { + get + { + lock (m_Gate) + { + return m_ActiveCount > 0; + } + } + } + + /// Marks one more execution in flight (see ). + internal void BeginExecutionCount() + { + lock (m_Gate) + { + m_ActiveCount++; + } + } + + /// + /// Marks one execution finished, resetting the explicit-report state when this was the + /// last one in flight. The decrement and the reset-on-zero check happen under the same + /// lock as , so a new execution starting in the gap can never + /// have its fresh BeginExecution/Report wiped by this reset — the previous implementation + /// decremented a separate counter and reset separately, leaving a window where a finishing + /// execution could decrement to zero, get preempted, and then wipe a new execution's + /// owner id and early report once it resumed. + /// + internal void EndExecutionCount() + { + lock (m_Gate) + { + m_ActiveCount--; + if (m_ActiveCount == 0) + { + m_Explicit = default; + m_ExplicitOwnerId = null; + m_CurrentOwnerId = null; + } + } + } + + /// + /// Report the current task's progress so a connected CLI can render it live. + /// Safe to call from any thread, at any frequency (the server samples on poll). + /// + /// Short task title, e.g. "Generating World". + /// Detail line, e.g. "Processing 42/100". + /// Current step, when the task has countable steps. + /// Total steps, when the task has countable steps. + /// Completion in the 0–1 range; omit for indeterminate tasks + /// (when omitted and both and are + /// present, the CLI derives a percentage from them). + internal void Report(string title, string info = null, long? current = null, long? total = null, double? progress = null) + { + var clamped = progress.HasValue ? Math.Max(0d, Math.Min(1d, progress.Value)) : (double?)null; + lock (m_Gate) + { + m_Explicit = new Snapshot(title, info, current, total, clamped); + m_ExplicitOwnerId = m_CurrentOwnerId; + } + } + + /// Clear an explicit (e.g. when the reported task finishes). + internal void Clear() + { + lock (m_Gate) + { + m_Explicit = default; + m_ExplicitOwnerId = null; + } + } + + /// Ambient-source mirror (UnityEditor.Progress items). Explicit reports win. + internal void ReportAmbient(string title, string info, long? current, long? total, double? progress01) + { + lock (m_Gate) + { + m_Ambient = new Snapshot(title, info, current, total, progress01); + } + } + + /// Clear the ambient mirror (no running UnityEditor.Progress items remain). + internal void ClearAmbient() + { + lock (m_Gate) + { + m_Ambient = default; + } + } + + /// + /// Marks the start of the execution identified by (a job id, + /// or a synthetic id for a plain /api/exec). Clears any leftover explicit report + /// from whatever ran before it and becomes the only owner will + /// accept explicit reports from until is called — so a queued + /// execution can never surface the previous one's progress before reporting its own. + /// + internal void BeginExecution(string ownerId) + { + lock (m_Gate) + { + m_CurrentOwnerId = ownerId; + m_Explicit = default; + m_ExplicitOwnerId = null; + } + } + + /// + /// Marks the end of the execution identified by . A no-op if + /// some other execution is already current (e.g. called after a swallowed exception), + /// so callers can call this unconditionally in a finally. + /// + internal void EndExecution(string ownerId) + { + lock (m_Gate) + { + if (m_CurrentOwnerId == ownerId) + { + m_CurrentOwnerId = null; + } + } + } + + /// + /// The snapshot the /api/progress endpoint serves: the explicit report, but only when it + /// was made by the currently executing owner (see ); falls + /// back to the ambient mirror otherwise. + /// + internal Snapshot Current + { + get + { + lock (m_Gate) + { + var explicitValid = m_Explicit.HasReport && m_ExplicitOwnerId == m_CurrentOwnerId; + return explicitValid ? m_Explicit : m_Ambient; + } + } + } + } + + /// + /// Structured progress reporting for long-running pipeline commands — the server side of the + /// CLI's terminal progress bars (CLI-488, coordinated with CLI-335). + /// + /// While a command executes over /api/exec, the CLI polls GET /api/progress and + /// renders whatever is reported here (a progress bar in a terminal, NDJSON progress frames in + /// machine formats). Command authors call from any thread — including a + /// main thread that is blocked inside a long synchronous command, which is exactly the + /// EditorUtility.DisplayProgressBar scenario this exists for. The state is read by the + /// HTTP listener thread, never the main thread, so progress stays visible even while the + /// Editor is busy. + /// + /// This is a thin static façade over the executing server's own + /// (resolved via ) so command code — which has + /// no reference to "which server is running me" — can keep calling this the same way + /// regardless of which server dispatched it. + /// + /// Ambient UnityEditor.Progress items are mirrored in by the Editor assembly + /// (EditorProgressMirror), targeting the live server directly; an explicit + /// always wins over the ambient mirror. Every execution (a plain + /// /api/exec or a detached job) is bracketed with BeginExecution/EndExecution on the + /// server's own , which tags who the current explicit report is + /// allowed to belong to — so a job queued behind one that just finished never inherits its + /// stale progress before making its own first report, no matter how long that job takes to + /// get around to reporting anything. + /// + public static class CliProgress + { + /// + /// Report the current task's progress so a connected CLI can render it live. + /// Safe to call from any thread, at any frequency (the server samples on poll). A no-op + /// when called outside a command's own execution (no server to attribute it to). + /// + /// Short title for the operation. + /// Optional detail text (e.g. current step). + /// Current progress amount, if determinate. + /// Total amount, if determinate. + /// Progress in [0, 1], used instead of current/total when set. + public static void Report(string title, string info = null, long? current = null, long? total = null, double? progress = null) + { + BasePipelineServer.CurrentServer?.Progress.Report(title, info, current, total, progress); + } + + /// Clear an explicit (e.g. when the reported task finishes). + public static void Clear() + { + BasePipelineServer.CurrentServer?.Progress.Clear(); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/CliProgress.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CliProgress.cs.meta new file mode 100644 index 0000000..2ba2887 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CliProgress.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 314bec0f00e544458e7558fde1168e82 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetVersion: 1 diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandExecutionInfo.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandExecutionInfo.cs new file mode 100644 index 0000000..4acd0b8 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandExecutionInfo.cs @@ -0,0 +1,91 @@ +using Newtonsoft.Json.Linq; +using Unity.Pipeline.Commands; + +namespace Unity.Pipeline +{ + /// + /// Everything known about one finished /api/exec interaction, handed to + /// . + /// + /// The transaction half and the execution half are independent, because the two are not the + /// same set: a request can produce a transaction without executing anything (rejected for + /// size, malformed JSON, unknown command, busy host, job queue full), and a detached job + /// executes long after its own response was sent, producing no transaction at all. Consumers + /// read the half they care about and skip the ones that lack it. + /// + public readonly struct CommandExecutionInfo + { + /// + /// Raw request JSON, or null when there is no transaction to report — a detached job + /// completing after its submission response was already sent. + /// + public string RequestJson { get; } + + /// + /// Raw response JSON as it went on the wire, or null alongside a null + /// . + /// + public string ResponseJson { get; } + + /// + /// The command that ran, or null when the request was rejected before any command + /// executed. + /// + public CommandInfo Command { get; } + + /// + /// The parameters the command was invoked with, or null when no command ran. Lets a consumer + /// answer questions about WHAT was asked, not just which command served it — the analytics + /// reporter reads an eval body from here to decide whether a concrete command already covers + /// it. Never serialized anywhere: it is in-memory only, for the moment between the command + /// finishing and the post-command work running. + /// + public JObject Parameters { get; } + + /// + /// Whether the command reported success. False when it threw AND when it returned a + /// response carrying its own failure (eval, code reload and test runs all do the latter). + /// Meaningless when is null. + /// + public bool Success { get; } + + /// + /// Wall-clock milliseconds spent inside the command itself, excluding the wait for the + /// one-command-at-a-time execution gate. Zero when is null. + /// + public long DurationMs { get; } + + /// Create an info describing one finished interaction. + /// Raw request JSON, or null when there is no transaction. + /// Raw response JSON, or null alongside a null request. + /// The command that ran, or null when none did. + /// Whether the command reported success. + /// Milliseconds spent inside the command. + /// The parameters the command was invoked with, or null. + public CommandExecutionInfo(string requestJson, string responseJson, CommandInfo command, + bool success, long durationMs, JObject parameters = null) + { + RequestJson = requestJson; + ResponseJson = responseJson; + Command = command; + Success = success; + DurationMs = durationMs; + Parameters = parameters; + } + + /// + /// A detached job that just finished: an execution with no transaction, since the client + /// already received its job handle. + /// + /// The command the job ran. + /// Whether the command reported success. + /// Milliseconds spent inside the command. + /// The parameters the job ran the command with. + /// An info carrying the execution and no transaction. + public static CommandExecutionInfo ForDetachedJob(CommandInfo command, bool success, long durationMs, + JObject parameters = null) + { + return new CommandExecutionInfo(null, null, command, success, durationMs, parameters); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandExecutionInfo.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandExecutionInfo.cs.meta new file mode 100644 index 0000000..0c2cdfa --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandExecutionInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 36cede5ed8322f54ab8790b9b19b6647 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandInfo.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandInfo.cs new file mode 100644 index 0000000..aad35bd --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandInfo.cs @@ -0,0 +1,101 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Reflection; + +namespace Unity.Pipeline.Commands +{ + /// + /// Information about a discovered CLI command. + /// Contains metadata needed for command execution and CLI help generation. + /// + public class CommandInfo + { + /// + /// Unique name of the command for CLI execution. + /// + public string Name { get; } + + /// + /// Human-readable description of the command. + /// + public string Description { get; } + + /// + /// Whether this command requires Unity main thread execution. + /// + public bool MainThreadRequired { get; } + + /// + /// Whether this command is part of the runtime (Player) command surface only. + /// Editor servers hide runtime-only commands from their command listing. + /// + public bool RuntimeOnly { get; } + + /// + /// Hierarchical tags used to group and browse commands (path-style, '/'-separated). + /// Empty for untagged commands; never null. + /// + public IReadOnlyList Tags { get; } + + /// + /// Name of the assembly this command originates from, used to group and filter + /// commands by contributing package/source. + /// + public string Package { get; } + + /// + /// Method that implements this command. + /// + public MethodInfo Method { get; } // TODO Maybe look at generating a dynamic Delegate to increase performance of the command call. + + /// + /// Parameters that this command accepts. + /// + public IReadOnlyList Parameters { get; } + + /// + /// Instance to invoke on, or null when is static. + /// Commands declared with a [CliCommand] attribute are always static and leave this null; + /// a dynamically registered command bound to an instance method carries its receiver here. + /// + public object Target { get; } + + /// + /// Create command information from discovery. + /// + /// Unique name of the command for CLI execution. + /// Human-readable description of the command. + /// Whether this command requires Unity main thread execution. + /// Method that implements this command. + /// Parameters that this command accepts. + /// Whether this command is part of the runtime (Player) command surface only. + /// Hierarchical tags used to group and browse commands. + /// Name of the assembly this command originates from. + /// + /// Instance to invoke on, or null when it is static. Only a + /// dynamically registered command bound to an instance method supplies one. + /// + public CommandInfo(string name, string description, bool mainThreadRequired, + MethodInfo method, IReadOnlyList parameters, bool runtimeOnly = false, + IReadOnlyList tags = null, string package = null, object target = null) + { + Name = name ?? throw new ArgumentNullException(nameof(name)); + Description = description ?? throw new ArgumentNullException(nameof(description)); + Method = method ?? throw new ArgumentNullException(nameof(method)); + Parameters = parameters ?? throw new ArgumentNullException(nameof(parameters)); + MainThreadRequired = mainThreadRequired; + RuntimeOnly = runtimeOnly; + Tags = tags ?? Array.Empty(); + Package = package; + Target = target; + } + + /// A short diagnostic summary of the command. + /// The summary string. + public override string ToString() + { + return $"{Name} MainThreadRequired:{MainThreadRequired} Parameters:{Parameters.Count}"; + } + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandInfo.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandInfo.cs.meta new file mode 100644 index 0000000..3c57877 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 40290d720d0d35b44a9fa5843a5ee294 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandLineBinder.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandLineBinder.cs new file mode 100644 index 0000000..0f0d293 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandLineBinder.cs @@ -0,0 +1,537 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using Newtonsoft.Json.Linq; +using Unity.Pipeline.Commands; + +namespace Unity.Pipeline +{ + /// + /// Binds argv tokens (the tokens AFTER the command name) to a command's declared + /// parameters, producing the same a client would have sent as + /// structured parameters. + /// + /// Values are stored as the structured form would carry them. For a parameter with a + /// declared type that means a string JValue, never pre-converted — the single most important + /// constraint here, because it makes {"commandLine":"log_editor hi"} and + /// {"command":"log_editor","parameters":{"message":"hi"}} indistinguishable from + /// ExtractCommandParameters downwards, so there is exactly one execution path and + /// one place where coercion can differ. An UNTYPED parameter has no type to coerce toward, so + /// there the token's shape decides — see StoreValue. + /// + /// Every defect is accumulated rather than bailing on the first, so a user fixing a command + /// line sees all of its problems at once. Required-parameter checking deliberately stays + /// OUT of here — ValidateCommandParameters owns it, so the message and error type are + /// byte-identical across both request forms. + /// + /// Grammar: --key value, --key=value, bare --key. A follower is + /// consumed unless it starts with --, which is what makes --path -foo work. + /// -- ends flag parsing. No short flags, no -abc bundling, no --no-x, + /// no repeated-flag-becomes-array. + /// + internal static class CommandLineBinder + { + private static readonly CommandParameterInfo[] k_NoParameters = new CommandParameterInfo[0]; + + /// + /// Binds against . Returns true only + /// when no problems were found; is always populated as far + /// as binding got, so a caller may inspect a partial bind. + /// + public static bool TryBind(CommandInfo command, IReadOnlyList args, + out JObject parameters, out List problems) + { + if (command == null) + throw new ArgumentNullException(nameof(command)); + + parameters = new JObject(); + problems = new List(); + + var declared = command.Parameters ?? (IReadOnlyList)k_NoParameters; + if (args == null || args.Count == 0) + return true; + + // Pass 1 - classify flags. Positionals are collected with a flag recording whether + // they appeared after "--", which exempts them from the -foo and key=value + // heuristics below. + var flagFilled = new HashSet(StringComparer.OrdinalIgnoreCase); + // Which parameters were set by a BARE flag. Tracked rather than inferred from the + // stored value being boolean: an untyped parameter given the literal token `true` + // also stores a boolean, and conflating the two reported a phantom missing value. + // The token as typed, per parameter, so a type error can quote the user verbatim even + // when the stored value was literal-parsed into a non-string. + var rawTokens = new Dictionary(StringComparer.OrdinalIgnoreCase); + var bareFlagged = new HashSet(StringComparer.OrdinalIgnoreCase); + var positionals = new List(); + var positionalExempt = new List(); + var endOfFlags = false; + + for (var i = 0; i < args.Count; i++) + { + var arg = args[i] ?? string.Empty; + + if (!endOfFlags && arg == "--") + { + endOfFlags = true; + continue; + } + + if (endOfFlags || !arg.StartsWith("--", StringComparison.Ordinal)) + { + positionals.Add(arg); + positionalExempt.Add(endOfFlags); + continue; + } + + var body = arg.Substring(2); + var equals = body.IndexOf('='); + var name = equals >= 0 ? body.Substring(0, equals) : body; + var inlineValue = equals >= 0 ? body.Substring(equals + 1) : null; + + if (name.Length == 0) + { + problems.Add(new ArgProblem { Kind = ArgProblemKind.EmptyName, Token = arg }); + continue; + } + + var parameter = FindParameter(declared, name); + if (parameter == null) + { + problems.Add(new ArgProblem + { + Kind = ArgProblemKind.UnknownName, + Name = name, + Suggestion = SuggestParameterName(name, declared), + }); + // Swallow what was clearly meant as this flag's value, so it does not + // resurface as a spurious excess positional. + if (inlineValue == null && HasConsumableFollower(args, i)) + i++; + continue; + } + + // Checked before the empty-value bail below: a second `--key=` is BOTH a + // duplicate and an empty value, and reporting only the second would let a user + // fix what they were told about and still be duplicating the flag. + if (flagFilled.Contains(parameter.Name)) + problems.Add(new ArgProblem { Kind = ArgProblemKind.Duplicate, Name = parameter.Name }); + + if (inlineValue != null && inlineValue.Length == 0) + { + problems.Add(new ArgProblem { Kind = ArgProblemKind.EmptyValue, Name = parameter.Name }); + continue; + } + + JToken value; + if (inlineValue != null) + { + value = inlineValue; + } + else if (HasConsumableFollower(args, i)) + { + // Absence and emptiness are different: `--message ""` is the empty string, + // not the boolean true. + value = args[++i] ?? string.Empty; + } + else + { + value = new JValue(true); + bareFlagged.Add(parameter.Name); + } + + if (value.Type == JTokenType.String) + { + var text = value.Value(); + parameters[parameter.Name] = StoreValue(parameter, text); + rawTokens[parameter.Name] = text; + } + else + { + parameters[parameter.Name] = value; + } + flagFilled.Add(parameter.Name); + } + + // Pass 2 - positional slots: required parameters in declaration order, then + // optional in declaration order. A slot already filled by a flag is SKIPPED, not + // overwritten, so the explicit flag always wins its own slot. + var slots = new List(declared.Count); + for (var i = 0; i < declared.Count; i++) + if (declared[i].Required) + slots.Add(declared[i]); + for (var i = 0; i < declared.Count; i++) + if (!declared[i].Required) + slots.Add(declared[i]); + + var free = new List(slots.Count); + for (var i = 0; i < slots.Count; i++) + if (!flagFilled.Contains(slots[i].Name)) + free.Add(slots[i]); + + var next = 0; + var firstOverflow = -1; + + for (var i = 0; i < positionals.Count; i++) + { + var token = positionals[i]; + + if (!positionalExempt[i]) + { + // Both of these are reported but STILL consume a slot: the token was + // clearly meant as a positional, and pretending otherwise would cascade + // into misleading downstream problems. + if (IsSingleDashFlag(token)) + { + problems.Add(new ArgProblem { Kind = ArgProblemKind.SingleDash, Token = token }); + } + else if (next < free.Count && IsBareAssignmentNamingItsOwnSlot(token, free[next])) + { + problems.Add(new ArgProblem { Kind = ArgProblemKind.BareAssignment, Token = token }); + } + } + + if (next < free.Count) + { + var slot = free[next++]; + parameters[slot.Name] = StoreValue(slot, token); + rawTokens[slot.Name] = token; + } + else if (firstOverflow < 0) + { + firstOverflow = i; + } + } + + // Pass 3 - coerce, as a DRY RUN only. We never rewrite what we stored: the executor + // re-converts from the same string, so binding and execution cannot diverge. + for (var i = 0; i < declared.Count; i++) + { + var parameter = declared[i]; + var value = parameters[parameter.Name]; + if (value == null) + continue; + + rawTokens.TryGetValue(parameter.Name, out var rawToken); + var problem = CheckCoercible( + value, parameter, bareFlagged.Contains(parameter.Name), rawToken); + if (problem != null) + problems.Add(problem); + } + + if (firstOverflow >= 0) + { + // Which of the two overflow kinds this is depends on the slot the token WOULD + // have taken, not on whether the request used a flag anywhere. Positionals fill + // `free` in order, so the token at index n would have taken slots[n]: if that + // slot exists and a flag claimed it, the token collided with that flag and the + // parameter can be named. Otherwise the command simply received more values than + // it declares parameters. + var collided = firstOverflow < slots.Count && flagFilled.Contains(slots[firstOverflow].Name) + ? slots[firstOverflow] + : null; + + problems.Add(collided != null + ? new ArgProblem + { + Kind = ArgProblemKind.PositionalConflict, + Name = collided.Name, + Token = positionals[firstOverflow], + } + : new ArgProblem + { + Kind = ArgProblemKind.ExcessPositional, + Token = positionals[firstOverflow], + // Capacity and given must be commensurable, because they are rendered as + // one sentence: slots still FREE after the flags took theirs, against + // positionals supplied. Pairing the declared total with the positional + // count compares two different things and reads as nonsense whenever a + // flag is involved ("takes 2 but got 2"). + Capacity = free.Count, + Given = positionals.Count, + }); + } + + return problems.Count == 0; + } + + /// + /// Decides what JSON type a token is stored as. + /// + /// For a parameter with a DECLARED type the answer is always a string: the type + /// itself disambiguates, and ConvertParameterToken widens it downstream. That is + /// also the fix over the CLI's old client-side guessing, which turned 007 into the + /// number 7 even for a declared string. + /// + /// An UNTYPED parameter (JToken/JObject/JArray/object — + /// 14 of them across 12 shipped commands, e.g. set_serialized_field.value) has + /// nothing to coerce toward, so the token's shape is the only signal there is. Those keep + /// the literal rules the CLI used, or a working --value 5 would silently start + /// sending the string "5". + /// + private static JToken StoreValue(CommandParameterInfo parameter, string token) + { + return IsUntypedTarget(parameter.ParameterType) && TryParseLiteral(token, out var literal) + ? literal + : token; + } + + /// A declared type that can hold any JSON value, so it constrains nothing. + private static bool IsUntypedTarget(Type type) + { + return type == typeof(object) || typeof(JToken).IsAssignableFrom(type); + } + + /// + /// Whether a bare flag's implied true is a value this parameter could hold. + /// JObject and JArray are untyped but still cannot, so this is narrower + /// than . + /// + private static bool CanHoldBoolean(Type type) + { + var underlying = Nullable.GetUnderlyingType(type) ?? type; + return underlying == typeof(bool) + || underlying == typeof(object) + || underlying == typeof(JToken) + || underlying == typeof(JValue); + } + + /// + /// The CLI's own literal rules, reproduced exactly: true/false + /// case-insensitively, an all-digit integer with an optional sign (so 07 is 7 — no + /// radix handling), and a single-dot decimal. Everything else stays a string, which is why + /// 1.2.3, a bare - and asset paths pass through untouched. + /// + private static bool TryParseLiteral(string token, out JToken value) + { + value = null; + if (string.IsNullOrEmpty(token)) + return false; + + var lowered = token.ToLowerInvariant(); + if (lowered == "true") { value = new JValue(true); return true; } + if (lowered == "false") { value = new JValue(false); return true; } + + var body = token[0] == '-' ? token.Substring(1) : token; + if (body.Length == 0) + return false; + + var dot = body.IndexOf('.'); + if (dot < 0) + { + if (!AllAsciiDigits(body)) + return false; + if (long.TryParse(token, NumberStyles.Integer, CultureInfo.InvariantCulture, out var whole)) + { + value = new JValue(whole); + return true; + } + return false; + } + + // Exactly one dot, digits on both sides. + if (dot == 0 || dot == body.Length - 1 + || body.IndexOf('.', dot + 1) >= 0 + || !AllAsciiDigits(body.Substring(0, dot)) + || !AllAsciiDigits(body.Substring(dot + 1))) + { + return false; + } + + if (double.TryParse(token, NumberStyles.Float, CultureInfo.InvariantCulture, out var real)) + { + value = new JValue(real); + return true; + } + return false; + } + + private static bool AllAsciiDigits(string s) + { + for (var i = 0; i < s.Length; i++) + if (s[i] < '0' || s[i] > '9') + return false; + return s.Length > 0; + } + + /// + /// Dry-runs the executor's own converter against a bound value and reports the defect, + /// or null when the value is acceptable. + /// + /// Three distinct failures fold into one report: the converter throwing; the converter + /// returning NULL for a non-empty token, which would otherwise make the parameter vanish + /// and let the command run with a default; and a bare flag on a non-bool parameter, which + /// JValue(true).ToObject<string>() would happily turn into the word "True". + /// + private static ArgProblem CheckCoercible( + JToken value, CommandParameterInfo parameter, bool wasBareFlag, string rawToken) + { + var targetType = parameter.ParameterType; + + // A bare flag implied `true`. On a parameter that cannot hold a boolean at all the + // user simply omitted the value, which reads better as EmptyValue than as a type + // error. Untyped is not the same as bool-capable: `object`, `JToken` and `JValue` + // hold `true` happily, while `JObject` and `JArray` cannot, and letting the implied + // `true` reach the converter reported those as a type error instead. + if (wasBareFlag && !CanHoldBoolean(targetType)) + { + return new ArgProblem { Kind = ArgProblemKind.EmptyValue, Name = parameter.Name }; + } + + // The token as the user typed it. An untyped target stores a literal-parsed JValue, + // so the stored value is not always a string and its text is not always the token + // (`007` parses to 7) — reading it back from the value dropped or altered the quote + // the diagnostic exists to show. + var token = rawToken ?? (value.Type == JTokenType.String ? value.Value() : null); + + // Enums are NOT pre-matched against Enum.GetNames. The converter accepts a [Flags] + // comma combination and a numeric value; a hand-rolled name match rejects both, which + // would make the raw form refuse what the structured form binds. TypeMismatch already + // unwraps Nullable for the type name and the prose appends the valid values, so + // deferring costs the message nothing. + try + { + var converted = BasePipelineServer.ConvertParameterToken(value, targetType); + if (converted == null && !string.IsNullOrEmpty(token)) + return TypeMismatch(parameter, token, targetType); + } + catch (Exception) + { + return TypeMismatch(parameter, token, targetType); + } + + return null; + } + + private static ArgProblem TypeMismatch(CommandParameterInfo parameter, string token, Type targetType) + { + return new ArgProblem + { + Kind = ArgProblemKind.TypeMismatch, + Name = parameter.Name, + Token = token, + ExpectedType = (Nullable.GetUnderlyingType(targetType) ?? targetType).Name, + }; + } + + /// + /// True when the token after should be taken as the current + /// flag's value. Anything starting with -- is the next flag, not a value; a + /// single-dash token IS consumable, which is the escape hatch for values like + /// --message -foo. + /// + private static bool HasConsumableFollower(IReadOnlyList args, int index) + { + if (index + 1 >= args.Count) + return false; + var follower = args[index + 1]; + return follower == null || !follower.StartsWith("--", StringComparison.Ordinal); + } + + private static CommandParameterInfo FindParameter(IReadOnlyList declared, string name) + { + for (var i = 0; i < declared.Count; i++) + if (string.Equals(declared[i].Name, name, StringComparison.OrdinalIgnoreCase)) + return declared[i]; + return null; + } + + /// + /// A -x token in positional position: a single dash followed by a LETTER. + /// + /// Letter-anchored, deliberately matching the `unity` CLI's own rule byte for byte. + /// The CLI keeps this check client-side so a typo costs nothing (no Editor boot, no CI + /// license seat), which only stays safe while the local check is a strict SUBSET of this + /// one — any divergence would surface as the server rejecting what the CLI let through. + /// A looser test such as "not parseable as a number" would do exactly that for tokens + /// like -5x. Negative numbers and a bare - remain valid positionals. + /// + private static bool IsSingleDashFlag(string token) + { + return token != null && token.Length >= 2 && token[0] == '-' && IsAsciiLetter(token[1]); + } + + private static bool IsAsciiLetter(char c) + { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); + } + + /// + /// A bare key=value positional whose left side names — the + /// very parameter the token is about to fill, which is what makes it a misremembered + /// --key value rather than a value. + /// + /// Testing the token against its OWN slot, rather than against every declared name, + /// is what keeps legal code clean: eval "timeout=5;" lands on code, and + /// timeout is a different parameter, so the token is a statement. Matching any + /// declared name rejected it while the equivalent structured request succeeded. + /// + /// A token that assigns its own slot (eval "code=1;") stays ambiguous by + /// nature and is still reported; -- is the documented way through. + /// + private static bool IsBareAssignmentNamingItsOwnSlot(string token, CommandParameterInfo slot) + { + if (string.IsNullOrEmpty(token) || token[0] == '-') + return false; + var equals = token.IndexOf('='); + if (equals <= 0) + return false; + return string.Equals(slot.Name, token.Substring(0, equals), StringComparison.OrdinalIgnoreCase); + } + + /// + /// Closest declared parameter name within an edit-distance budget that scales with + /// length, or null. Budget is min(3, max(1, longest/3)): tight enough that an + /// unrelated name gets no suggestion at all, loose enough to catch real typos. + /// + private static string SuggestParameterName(string name, IReadOnlyList declared) + { + string best = null; + var bestDistance = int.MaxValue; + + for (var i = 0; i < declared.Count; i++) + { + var candidate = declared[i].Name; + var budget = Math.Min(3, Math.Max(1, Math.Max(name.Length, candidate.Length) / 3)); + var distance = EditDistance(name, candidate); + if (distance <= budget && distance < bestDistance) + { + bestDistance = distance; + best = candidate; + } + } + + return best; + } + + /// Case-insensitive Levenshtein distance. + private static int EditDistance(string a, string b) + { + a = a.ToLowerInvariant(); + b = b.ToLowerInvariant(); + + var previous = new int[b.Length + 1]; + var current = new int[b.Length + 1]; + + for (var j = 0; j <= b.Length; j++) + previous[j] = j; + + for (var i = 1; i <= a.Length; i++) + { + current[0] = i; + for (var j = 1; j <= b.Length; j++) + { + var substitution = previous[j - 1] + (a[i - 1] == b[j - 1] ? 0 : 1); + var deletion = previous[j] + 1; + var insertion = current[j - 1] + 1; + current[j] = Math.Min(substitution, Math.Min(deletion, insertion)); + } + + var swap = previous; + previous = current; + current = swap; + } + + return previous[b.Length]; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandLineBinder.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandLineBinder.cs.meta new file mode 100644 index 0000000..fb26250 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandLineBinder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eb75a7888547abb419286040fb9a0a58 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandLineTokenizer.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandLineTokenizer.cs new file mode 100644 index 0000000..0ae172f --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandLineTokenizer.cs @@ -0,0 +1,139 @@ +using System.Collections.Generic; +using System.Text; + +namespace Unity.Pipeline +{ + /// + /// Splits a raw command line into argv tokens for /api/exec's commandLine form. + /// + /// The dialect is POSIX-ish and is the pipeline's own — not the caller's shell, and + /// identical on every OS, so the same string tokenizes the same way from cmd.exe, bash, an + /// MCP client or a chat box. It is documented as a versioned contract in + /// Documentation~/connectivity.md; CommandLineTokenizerTests pins it. + /// + /// Rules: whitespace separates tokens; "…" groups with \ escaping the next + /// character; '…' groups with no escapes at all; \ escapes outside + /// quotes; adjacent spans concatenate (a"b c"d → ab cd); "" yields one + /// empty token. There is no expansion of any kind — no $VAR, globbing, ~, + /// comments or operators; && and | are ordinary characters. + /// + /// POSIX-ish rather than Windows CommandLineToArgvW because single quotes are + /// load-bearing here — eval 'obj.name = "x";' and batch --operations '[{…}]' + /// need a form that passes double quotes through untouched, and Windows semantics have no + /// single-quote concept. The usual argument for Windows rules (\ is the path + /// separator) does not apply: every path this API accepts is a forward-slashed Unity asset + /// path. + /// + internal static class CommandLineTokenizer + { + /// + /// Tokenizes . Returns false and sets + /// on an unbalanced quote or a dangling backslash. + /// A null, empty or all-whitespace input succeeds with zero tokens — a lexer has no + /// opinion about needing a command name, so the caller reports that (keeping the message + /// identical to the structured path). + /// + public static bool TryTokenize(string commandLine, out List tokens, out string error) + { + tokens = new List(); + error = null; + + if (string.IsNullOrEmpty(commandLine)) + return true; + + var current = new StringBuilder(); + // Distinguishes `""` (one empty token) from whitespace (no token at all). + var hasToken = false; + var inSingle = false; + var inDouble = false; + + for (var i = 0; i < commandLine.Length; i++) + { + var c = commandLine[i]; + + if (inSingle) + { + if (c == '\'') + inSingle = false; + else + current.Append(c); + continue; + } + + if (inDouble) + { + if (c == '"') + { + inDouble = false; + } + else if (c == '\\') + { + if (i + 1 >= commandLine.Length) + { + error = "Dangling backslash at end of command line"; + return false; + } + current.Append(commandLine[++i]); + } + else + { + current.Append(c); + } + continue; + } + + if (c == '\'') + { + inSingle = true; + hasToken = true; + } + else if (c == '"') + { + inDouble = true; + hasToken = true; + } + else if (c == '\\') + { + if (i + 1 >= commandLine.Length) + { + error = "Dangling backslash at end of command line"; + return false; + } + current.Append(commandLine[++i]); + hasToken = true; + } + else if (c == ' ' || c == '\t' || c == '\n' || c == '\r') + { + if (hasToken) + { + tokens.Add(current.ToString()); + current.Length = 0; + hasToken = false; + } + } + else + { + current.Append(c); + hasToken = true; + } + } + + if (inSingle) + { + error = "Unbalanced single quote in command line"; + return false; + } + + if (inDouble) + { + error = "Unbalanced double quote in command line"; + return false; + } + + if (hasToken) + tokens.Add(current.ToString()); + + return true; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandLineTokenizer.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandLineTokenizer.cs.meta new file mode 100644 index 0000000..97370da --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandLineTokenizer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 04dfc14e12dcc7f4dbd172a1e84380b2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandRegistry.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandRegistry.cs new file mode 100644 index 0000000..3d450f4 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandRegistry.cs @@ -0,0 +1,400 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using UnityEngine; +#if UNITY_6000_3_OR_NEWER +using UnityEngine.Assemblies; +#endif +#if UNITY_6000_5_OR_NEWER +using Unity.Scripting.LifecycleManagement; +#endif + +namespace Unity.Pipeline.Commands +{ + /// + /// Registry for discovering and managing CLI commands via pluggable discovery mechanism. + /// Scans for methods marked with [CliCommand] attribute across all assemblies. + /// Based on unity-tools ToolRegistry patterns adapted for Pipeline requirements. + /// + /// + /// [NoAutoStaticsCleanup] on purpose: m_DiscoveryLock and the injected discovery mechanism are + /// set up once per domain and must not be reset under the running server. The dynamic-command + /// table is the one static here with a shorter useful life, and PlayModeSessionEnded resets the + /// part of it that a Play session owns. + /// +#if UNITY_6000_5_OR_NEWER + [NoAutoStaticsCleanup] +#endif + static class CommandRegistry + { + private static IReadOnlyList m_CachedCommands; + private static IReadOnlyList m_CachedAllCommands; + private static readonly Dictionary m_DynamicCommands = + new Dictionary(StringComparer.Ordinal); + // Names in m_DynamicCommands that predate the Play session currently running; null outside + // one. Lets PlayModeSessionEnded tell a registration made during the session apart from one + // that was already there. See PlayModeSessionStarted. + private static HashSet m_PrePlayModeCommands; + private static ICommandDiscovery m_Discovery; + private static readonly object m_DiscoveryLock = new object(); + + /// + /// Set the command discovery mechanism. + /// Editor assembly provides TypeCache-based discovery, Runtime uses reflection fallback. + /// + /// The discovery mechanism to use. + public static void SetDiscovery(ICommandDiscovery discovery) + { + m_Discovery = discovery; + ClearCache(); // Re-discover with new mechanism + } + + /// + /// Discover every available command: the methods marked with [CliCommand], plus any + /// registered through . + /// Attribute discovery uses the injected mechanism (TypeCache in Editor, reflection in + /// Runtime) and is cached until domain reload; the combined result is re-cached whenever + /// a dynamic command is registered or unregistered. + /// + /// All discovered commands. + public static IEnumerable DiscoverCommands() + { + var cached = m_CachedAllCommands; + if (cached != null) + { + return cached; + } + + lock (m_DiscoveryLock) + { + if (m_CachedCommands == null) + { + m_CachedCommands = DiscoverCommandsInternal().ToList(); + } + + if (m_CachedAllCommands == null) + { + m_CachedAllCommands = m_DynamicCommands.Count == 0 + ? m_CachedCommands + : m_CachedCommands.Concat(m_DynamicCommands.Values).ToList(); + } + } + + return m_CachedAllCommands; + } + + /// + /// Register a command at runtime, without a [CliCommand] attribute. The resulting command + /// is indistinguishable from an attribute-declared one: it is listed by /api/commands + /// and executable through /api/exec under . + /// + /// Parameter metadata is read from the handler's own parameters exactly as it is for an + /// attribute-declared command — a [CliArg] on a parameter supplies its CLI name, + /// description, and required flag; a parameter without one falls back to its declared name + /// and default value. Note that a lambda cannot carry [CliArg], so registering a named + /// method is what yields full metadata. + /// + /// Registrations live until they are unregistered or the domain reloads; they survive + /// and . One made while the Editor is in + /// Play Mode is additionally dropped when Play Mode exits — see + /// . + /// + /// Unique command name for CLI execution. + /// Human-readable description, shown in command listings. + /// + /// Method to invoke. An instance-method delegate keeps its receiver, so the command runs + /// against that instance; a static one runs with no receiver. + /// + /// Whether the command must run on the Unity main thread. + /// Whether the command belongs to the Player command surface only. + /// Optional path-style tags used to group and browse the command. + /// + /// A command called is already registered. Attribute-declared + /// commands can never be replaced; a dynamic one must be unregistered first. + /// + public static void RegisterCommand(string name, string description, Delegate handler, + bool mainThreadRequired = true, bool runtimeOnly = false, string[] tags = null) + { + if (name == null) + throw new ArgumentNullException(nameof(name)); + if (description == null) + throw new ArgumentNullException(nameof(description)); + if (handler == null) + throw new ArgumentNullException(nameof(handler)); + if (string.IsNullOrWhiteSpace(name)) + throw new ArgumentException("Command name must not be empty or whitespace.", nameof(name)); + + var method = handler.Method; + var command = new CommandInfo( + name, + description, + mainThreadRequired, + method, + DiscoverParameters(method).ToList(), + runtimeOnly, + tags, + method.DeclaringType?.Assembly.GetName().Name, + handler.Target); + + lock (m_DiscoveryLock) + { + if (m_DynamicCommands.ContainsKey(name)) + { + throw new InvalidOperationException( + $"A command named '{name}' is already registered dynamically. " + + "Unregister it before registering it again."); + } + + // Anything left matching here is attribute-declared: the dynamic table was just checked. + if (DiscoverCommands().Any(c => c.Name == name)) + { + throw new InvalidOperationException( + $"A command named '{name}' is already declared with a [CliCommand] attribute " + + "and cannot be replaced."); + } + + m_DynamicCommands[name] = command; + m_CachedAllCommands = null; + } + } + + /// + /// Remove a command previously registered with . + /// Attribute-declared commands are part of the code and are never removable. + /// + /// Name the command was registered under. + /// + /// True if a dynamic command was removed; false if no command is registered under that + /// name dynamically, including when the name belongs to an attribute-declared command. + /// + public static bool UnregisterCommand(string name) + { + if (name == null) + throw new ArgumentNullException(nameof(name)); + + lock (m_DiscoveryLock) + { + if (!m_DynamicCommands.Remove(name)) + return false; + + m_CachedAllCommands = null; + return true; + } + } + + /// + /// Note that a Play session is starting, so registrations made from here on can be told + /// apart from the ones that predate it. Called by the Editor on Play Mode entry, before any + /// user code runs. + /// + internal static void PlayModeSessionStarted() + { + lock (m_DiscoveryLock) + { + m_PrePlayModeCommands = new HashSet(m_DynamicCommands.Keys, StringComparer.Ordinal); + } + } + + /// + /// Drop every dynamic registration made during the Play session that just ended, the way a + /// domain reload would have. Registrations that predate the session are left alone: nothing + /// re-runs to restore them (an [InitializeOnLoadMethod] runs once per domain). + /// + /// A script registering from Awake or OnEnable re-registers on every Play Mode entry, so + /// without this the second entry would throw "already registered dynamically" whenever no + /// domain reload happened in between — and any surviving entry would still hold a delegate + /// bound to the previous session's destroyed object. That covers Enter Play Mode with domain + /// reload disabled on any Editor version, and on 6000.5+ the class-wide + /// [NoAutoStaticsCleanup] means AutoStaticsCleanup does not step in either. + /// + internal static void PlayModeSessionEnded() + { + lock (m_DiscoveryLock) + { + // No recorded session start (e.g. a domain reload wiped it on the way in, having + // already cleared the registry): nothing is known to belong to the session, so + // removing anything would be guesswork. + if (m_PrePlayModeCommands == null) + return; + + foreach (var name in m_DynamicCommands.Keys.Where(n => !m_PrePlayModeCommands.Contains(n)).ToList()) + m_DynamicCommands.Remove(name); + + m_PrePlayModeCommands = null; + m_CachedAllCommands = null; + } + } + + /// + /// Clear the discovered-command cache, so the next discovery re-scans for [CliCommand] + /// methods. Called automatically on domain reload, and whenever the discovery mechanism + /// changes. Commands registered through are not affected. + /// + public static void ClearCache() + { + lock (m_DiscoveryLock) + { + m_CachedCommands = null; + m_CachedAllCommands = null; + } + } + + /// + /// Internal implementation of command discovery using injected discovery mechanism. + /// + private static IEnumerable DiscoverCommandsInternal() + { + var commands = new List(); + + try + { + // Use injected discovery mechanism if available, otherwise fallback to reflection + IEnumerable methods; + + if (m_Discovery != null) + { + methods = m_Discovery.GetMethodsWithAttribute(); + } + else + { + // Fallback: Use reflection to scan loaded assemblies + methods = GetMethodsWithAttributeViaReflection(); + } + + foreach (var method in methods) + { + try + { + var commandInfo = CreateCommandInfo(method); + if (commandInfo != null) + { + commands.Add(commandInfo); + } + } + catch (Exception ex) + { + Debug.LogWarning($"Failed to register command from method {method.DeclaringType?.Name}.{method.Name}: {ex.Message}"); + } + } + } + catch (Exception ex) + { + Debug.LogError($"Failed to discover commands: {ex.Message}"); + } + + return commands; + } + + /// + /// Fallback command discovery using reflection when TypeCache is not available. + /// + private static IEnumerable GetMethodsWithAttributeViaReflection() where T : Attribute + { + var methods = new List(); + + try + { + var assemblies = PipelineUtils.GetLoadedAssemblies(); + + foreach (var assembly in assemblies) + { + // Skip system assemblies for performance + if (IsSystemAssembly(assembly)) + continue; + + try + { + foreach (var type in assembly.GetTypes()) + { + foreach (var method in type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)) + { + if (method.GetCustomAttribute() != null) + { + methods.Add(method); + } + } + } + } + catch (ReflectionTypeLoadException) + { + // Skip assemblies that can't be loaded + continue; + } + } + } + catch (Exception ex) + { + Debug.LogWarning($"Reflection-based command discovery failed: {ex.Message}"); + } + + return methods; + } + + /// + /// Check if assembly is a system assembly that should be skipped during discovery. + /// + private static bool IsSystemAssembly(Assembly assembly) + { + var name = assembly.GetName().Name; + return name.StartsWith("System.") || + name.StartsWith("Microsoft.") || + name.StartsWith("mscorlib") || + name.StartsWith("netstandard") || + name.Equals("UnityEngine") || + name.Equals("UnityEditor"); + } + + /// + /// Create CommandInfo from a method with CliCommand attribute. + /// + private static CommandInfo CreateCommandInfo(MethodInfo method) + { + var commandAttr = method.GetCustomAttribute(); + if (commandAttr == null) + return null; + + // Validate method is static (required for CLI commands). + // Any static method may be registered regardless of accessibility + // (public, internal, or private) — invocation goes through MethodInfo.Invoke. + if (!method.IsStatic) + { + Debug.LogWarning($"Command method {method.DeclaringType?.Name}.{method.Name} must be static"); + return null; + } + + // Discover parameters + var parameters = DiscoverParameters(method).ToList(); + + return new CommandInfo( + commandAttr.Name, + commandAttr.Description, + commandAttr.MainThreadRequired, + method, + parameters, + commandAttr.RuntimeOnly, + commandAttr.Tags, + method.DeclaringType?.Assembly.GetName().Name + ); + } + + /// + /// Discover parameter information from method parameters. + /// + private static IEnumerable DiscoverParameters(MethodInfo method) + { + foreach (var param in method.GetParameters()) + { + var argAttr = param.GetCustomAttribute(); + + // Parameters without CliArg attribute get default metadata + var name = argAttr?.Name ?? param.Name; + var description = argAttr?.Description ?? $"Parameter: {param.Name}"; + var required = argAttr?.Required ?? !param.HasDefaultValue; + var defaultValue = param.HasDefaultValue ? param.DefaultValue : argAttr?.DefaultValue; + + yield return new CommandParameterInfo(name, description, required, param.ParameterType, defaultValue); + } + } + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandRegistry.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandRegistry.cs.meta new file mode 100644 index 0000000..607900e --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/CommandRegistry.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c53b0ba553311e14c833aadafdb44999 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/DialogStateTracker.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Common/DialogStateTracker.cs new file mode 100644 index 0000000..6d143f6 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/DialogStateTracker.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Unity.Pipeline +{ + /// Snapshot of one dialog shown/dismissed event, as relayed by EditorDialogEvents. + internal readonly struct DialogInfo + { + public readonly int Id; + public readonly string Source; + public readonly string Title; + public readonly string Message; + public readonly string[] Buttons; + public readonly string Level; + public readonly DateTime OpenedAtUtc; + public readonly DateTime? DismissedAtUtc; + + public DialogInfo(int id, string source, string title, string message, string[] buttons, string level, DateTime openedAtUtc, DateTime? dismissedAtUtc) + { + Id = id; + Source = source; + Title = title; + Message = message; + Buttons = buttons; + Level = level; + OpenedAtUtc = openedAtUtc; + DismissedAtUtc = dismissedAtUtc; + } + + public DialogInfo WithDismissed(DateTime dismissedAtUtc) => + new DialogInfo(Id, Source, Title, Message, Buttons, Level, OpenedAtUtc, dismissedAtUtc); + } + + /// + /// Per-server modal-dialog state (the same one-instance-per- + /// ownership as CliProgressState/Progress, so a test server's dialog state never + /// crosses into the live server's). Unlike progress, dialogs are not scoped to a currently + /// executing command — they can be raised by anything (a human, a background job, an unrelated + /// command) at any time, so there is no owner-id concept here. + /// + internal sealed class DialogStateTracker + { + const int MaxRecentEvents = 50; + + readonly object m_Gate = new object(); + readonly Dictionary m_Open = new Dictionary(); + readonly LinkedList m_Recent = new LinkedList(); + + internal bool IsDialogOpen + { + get { lock (m_Gate) return m_Open.Count > 0; } + } + + /// + /// Ordered oldest-opened-first: callers (the dialog busy-gate, /api/status) treat index 0 + /// as "the first open dialog", and Dictionary<,>'s enumeration order isn't guaranteed + /// to match insertion order once entries have been removed and re-added. + /// + internal List CurrentlyOpen + { + get { lock (m_Gate) return m_Open.Values.OrderBy(e => e.OpenedAtUtc).ToList(); } + } + + internal void OnShown(int id, string source, string title, string message, string[] buttons, string level, DateTime openedAtUtc) + { + var info = new DialogInfo(id, source, title, message, buttons, level, openedAtUtc, null); + lock (m_Gate) + { + m_Open[id] = info; + } + } + + internal void OnDismissed(int id, DateTime dismissedAtUtc) + { + lock (m_Gate) + { + if (!m_Open.TryGetValue(id, out var info)) + return; + + m_Open.Remove(id); + m_Recent.AddLast(info.WithDismissed(dismissedAtUtc)); + while (m_Recent.Count > MaxRecentEvents) + m_Recent.RemoveFirst(); + } + } + + /// + /// Dialogs opened at or after — still-open ones and recently + /// dismissed ones. Used to attach dialogsDuringExecution to a command's exec response. + /// + internal List EventsSince(DateTime utc) + { + lock (m_Gate) + { + var result = m_Open.Values.Where(e => e.OpenedAtUtc >= utc).ToList(); + result.AddRange(m_Recent.Where(e => e.OpenedAtUtc >= utc)); + return result; + } + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/DialogStateTracker.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Common/DialogStateTracker.cs.meta new file mode 100644 index 0000000..8060cbe --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/DialogStateTracker.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 9700dd7e04984bd7a48f4d5f0f82d71c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetVersion: 1 diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/Dispatcher.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Common/Dispatcher.cs new file mode 100644 index 0000000..8c850ab --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/Dispatcher.cs @@ -0,0 +1,299 @@ +using System; +using System.Collections.Concurrent; +using System.Threading; +using System.Threading.Tasks; +using UnityEngine; + +namespace Unity.Pipeline.Threading +{ + /// + /// Dispatches work to Unity's main thread from background threads (required for accessing Unity + /// APIs from HTTP request handlers). + /// + /// Each pipeline server owns its own instance (no global singleton): it is initialized on Start + /// and pumped from the main thread — auto-pumped via EditorApplication.update in the editor, and + /// by RuntimePipelineDriver.Update in a player. + /// + public class Dispatcher + { + private readonly ConcurrentQueue m_WorkQueue = new ConcurrentQueue(); + private volatile bool m_IsInitialized; + private int m_MainThreadId = -1; + + /// True once has run and this dispatcher is pumping its queue. + public bool IsInitialized => m_IsInitialized; + + /// + /// Initialize the dispatcher. Must be called from Unity's main thread. + /// + public void Initialize() + { + if (m_IsInitialized) + return; + + m_MainThreadId = Thread.CurrentThread.ManagedThreadId; + m_IsInitialized = true; + +#if UNITY_EDITOR + UnityEditor.EditorApplication.update += ProcessWorkQueue; +#endif + } + + /// + /// Shutdown the dispatcher and cancel any pending work. + /// + public void Shutdown() + { + if (!m_IsInitialized) + return; + +#if UNITY_EDITOR + UnityEditor.EditorApplication.update -= ProcessWorkQueue; +#endif + + while (m_WorkQueue.TryDequeue(out var item)) + { + try + { + item.SetException(new OperationCanceledException("Dispatcher is shutting down")); + } + catch { } + } + + m_IsInitialized = false; + } + + /// + /// Execute a function on the main thread and return the result (synchronous wait). + /// + /// The function's return type. + /// Function to run on the main thread. + /// Time to wait before throwing . + /// The function's result. + public T Invoke(Func function, int timeoutMs = 60000) + { + if (!m_IsInitialized) + throw new InvalidOperationException("Dispatcher must be initialized first"); + + if (IsMainThread()) + return function(); + + var workItem = new WorkItem(function); + m_WorkQueue.Enqueue(workItem); + + var startTime = DateTime.UtcNow; + var task = workItem.TaskCompletionSource.Task; + + while (!task.IsCompleted) + { + if ((DateTime.UtcNow - startTime).TotalMilliseconds > timeoutMs) + { + // No-op if execution already started on the main thread — only prevents a + // still-queued item from running after we've reported the timeout. + workItem.TryCancel(); + throw new TimeoutException($"Main thread operation timed out after {timeoutMs}ms"); + } + + Thread.Sleep(1); + } + + if (task.IsFaulted) + throw task.Exception?.GetBaseException() ?? new Exception("Unknown error"); + + if (task.IsCanceled) + throw new OperationCanceledException("Main thread operation was cancelled"); + + return task.Result; + } + + /// + /// Execute an action on the main thread. + /// + /// Action to run on the main thread. + /// Time to wait before throwing . + public void Invoke(Action action, int timeoutMs = 60000) + { + Invoke(() => + { + action(); + return null; + }, timeoutMs); + } + + /// + /// Execute a function on the main thread and return the result (async version). + /// + /// The function's return type. + /// Function to run on the main thread. + /// Time to wait before throwing . + /// The function's result. + public async Task InvokeAsync(Func function, int timeoutMs = 60000) + { + return await Task.Run(() => Invoke(function, timeoutMs)); + } + + /// + /// Execute an action on the main thread (async version). + /// + /// Action to run on the main thread. + /// Time to wait before throwing . + /// A task that completes once the action has run on the main thread. + public async Task InvokeAsync(Action action, int timeoutMs = 60000) + { + await Task.Run(() => Invoke(action, timeoutMs)); + } + + /// + /// Queue an action to run on the main thread and return immediately. + /// + /// For work with no caller left to return to — reporting, logging, telemetry, anything + /// whose result nobody reads. is wrong for that: it parks + /// the calling thread until the next pump, and on a request thread that delay is paid by + /// whoever is waiting on the response. InvokeAsync only moves the same wait onto a + /// threadpool thread. + /// + /// The action always runs on a later pump, never inline, even when called from the main + /// thread, so posted work runs in the order it was posted. It has nowhere to report a + /// failure, so an exception is logged and swallowed rather than propagated. Work still + /// queued when the dispatcher shuts down is dropped, and posting to a dispatcher that is + /// not running is a no-op for the same reason — losing a report is always preferable to + /// throwing at a caller that was only trying to record something. + /// + /// Action to run on the main thread on a later pump. + public void Post(Action action) + { + if (action == null) + throw new ArgumentNullException(nameof(action)); + + if (!m_IsInitialized) + return; + + m_WorkQueue.Enqueue(new PostedWorkItem(action)); + } + + /// + /// Check if we're currently on Unity's main thread. + /// + /// True if the calling thread is the main thread captured by . + public bool IsMainThread() + { + return m_MainThreadId != -1 && Thread.CurrentThread.ManagedThreadId == m_MainThreadId; + } + + /// + /// Process queued work items. Called from EditorApplication.update or MonoBehaviour.Update. + /// + /// Max items to process per call, to limit frame-rate impact. + public void ProcessWorkQueue(int maxItemsPerFrame) + { + int processedCount = 0; + + while (processedCount < maxItemsPerFrame && m_WorkQueue.TryDequeue(out var workItem)) + { + try + { + workItem.Execute(); + } + catch (Exception ex) + { + Debug.LogError($"Dispatcher work item failed: {ex.Message}"); + workItem.SetException(ex); + } + + processedCount++; + } + } + + /// Process queued work items, up to a default limit of 10 per call. + public void ProcessWorkQueue() + { + ProcessWorkQueue(10); + } + + private abstract class WorkItem + { + private const int Pending = 0; + private const int Started = 1; + private const int Canceled = 2; + private int m_State; + + /// Marks the item canceled if it hasn't started executing yet. Returns false + /// (no-op) once has already claimed it. + public bool TryCancel() => Interlocked.CompareExchange(ref m_State, Canceled, Pending) == Pending; + + public void Execute() + { + if (Interlocked.CompareExchange(ref m_State, Started, Pending) != Pending) + return; // Canceled before it could start. + + ExecuteCore(); + } + + protected abstract void ExecuteCore(); + public abstract void SetException(Exception exception); + } + + /// + /// A work item. Unlike it carries no + /// TaskCompletionSource: nobody is waiting on the result, so a fault has nowhere to go but + /// the log — and faulting a TCS no one awaits would surface later as an unobserved task + /// exception. A shutdown cancellation simply drops the work. + /// + private class PostedWorkItem : WorkItem + { + private readonly Action m_Action; + + public PostedWorkItem(Action action) + { + m_Action = action; + } + + protected override void ExecuteCore() + { + try + { + m_Action(); + } + catch (Exception ex) + { + Debug.LogWarning($"Dispatcher posted work failed: {ex.Message}"); + } + } + + public override void SetException(Exception exception) + { + // Nobody is waiting on this item, so there is nothing to hand the exception to. + } + } + + private class WorkItem : WorkItem + { + private readonly Func m_Function; + public TaskCompletionSource TaskCompletionSource { get; } + + public WorkItem(Func function) + { + m_Function = function ?? throw new ArgumentNullException(nameof(function)); + TaskCompletionSource = new TaskCompletionSource(); + } + + protected override void ExecuteCore() + { + try + { + var result = m_Function(); + TaskCompletionSource.SetResult(result); + } + catch (Exception ex) + { + TaskCompletionSource.SetException(ex); + } + } + + public override void SetException(Exception exception) + { + TaskCompletionSource.SetException(exception); + } + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/Dispatcher.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Common/Dispatcher.cs.meta new file mode 100644 index 0000000..49e040a --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/Dispatcher.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: df7819f4aeb94b2408fd309361f67243 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/ExecResponseSerializer.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Common/ExecResponseSerializer.cs new file mode 100644 index 0000000..62cb2b9 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/ExecResponseSerializer.cs @@ -0,0 +1,141 @@ +using System.Reflection; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using Unity.Pipeline.Models; + +namespace Unity.Pipeline +{ + /// + /// Single source of truth for how /api/exec replies are serialized (AUTHAPI-21). Centralized + /// here so the server and the envelope byte-size regression test share one contract. + /// + /// Every mode serializes with (compact): agents consume the JSON, and + /// an MCP client can pretty-print for a human if ever needed — the wire form never needs indentation. + /// + /// Two independent request flags select the mode: + /// + /// * verbose — envelope metadata. Off (default): the always-on metadata (executedAt, + /// command, executionTimeMs) is stripped from every -derived object + /// in the graph (the outer envelope AND responses nested as result, e.g. eval's), and + /// the envelope's own null keys (message/error/errorDetails when null, result on failure — all + /// redundant given success) are omitted, so a minimal success is just + /// {"success":true,"result":...}. On: full fidelity for debugging/correlation. + /// * omitNulls — payload null fidelity. Off (default): the command's own result + /// payload keeps explicit nulls — an agent must be able to distinguish "this field is null" + /// from "this field doesn't exist / I got the name wrong". On: null keys are dropped + /// everywhere, for callers that already know the result schema and want the bytes back + /// (e.g. bulk list reads where a null column repeats hundreds of times). + /// + /// One invariant holds in EVERY mode: a successful reply always carries result, even + /// when its value is null — a null result on success is the command's actual value (e.g. a + /// format="value" read of a genuinely-null field), never a droppable envelope null. + /// + /// The two axes are deliberately separate booleans: envelope metadata and payload null fidelity + /// are orthogonal concerns, and each combination is meaningful. + /// + /// The gating lives in a contract resolver scoped to THIS serializer, not in ShouldSerialize* + /// hooks on the models: serializing these types anywhere else (other endpoints, logs, tests) is + /// unaffected, and Serialize never mutates the response object. + /// + internal static class ExecResponseSerializer + { + /// + /// Lean-envelope gating for every -derived object in the graph + /// (nested results included): strips the always-on metadata and omits the envelope's own + /// null keys — WITHOUT touching null handling on non-envelope payload objects, which keep + /// the serializer-level default. One shared instance per settings object: + /// DefaultContractResolver caches resolved contracts per resolver instance (thread-safe), + /// so the reflection cost is paid once per type, not per request. + /// + private class LeanEnvelopeContractResolver : DefaultContractResolver + { + protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) + { + var property = base.CreateProperty(member, memberSerialization); + + // DeclaringType guards against unrelated same-named members (e.g. + // CommandExecutionRequest.Command must keep serializing). + if (member.DeclaringType != null && typeof(BaseResponse).IsAssignableFrom(member.DeclaringType)) + { + switch (member.Name) + { + case nameof(BaseResponse.ExecutedAt): + case nameof(CommandExecutionResponse.Command): + case nameof(CommandExecutionResponse.ExecutionTimeMs): + property.ShouldSerialize = _ => false; + break; + + // The ONLY keys lean mode may null-drop: genuinely redundant given + // `success` (error/errorDetails are null exactly on success, message on + // both paths when there is nothing to say). Everything else declared on + // a BaseResponse-DERIVED type is payload (TestExecutionResponse's + // summary/results/filterApplied, EvalResponse.Output, …) and keeps + // explicit nulls — a dropped payload key is indistinguishable from a + // nonexistent or misspelled one; e.g. an async run_tests poller could + // not tell "not ready yet" from "not a field". Enumerated per key + // instead of type-wide for exactly that reason. + case nameof(BaseResponse.Message): + case nameof(BaseResponse.Error): + case nameof(BaseResponse.ErrorDetails): + property.NullValueHandling = NullValueHandling.Ignore; + break; + + case nameof(CommandExecutionResponse.Result): + // A null result on SUCCESS is not a redundant envelope null — it is + // the command's actual value (e.g. get_serialized_fields + // format="value" reading a genuinely-null field), so a successful + // reply always carries "result", explicitly null when null (Include + // also defeats the omitNulls serializer settings). On failure the + // result is structurally meaningless and stays omitted. + property.NullValueHandling = NullValueHandling.Include; + property.ShouldSerialize = instance => + !(instance is CommandExecutionResponse response) || response.Success; + break; + } + } + + return property; + } + } + + private static readonly JsonSerializerSettings m_LeanSettings = new JsonSerializerSettings + { + Formatting = Formatting.None, + NullValueHandling = NullValueHandling.Include, + ContractResolver = new LeanEnvelopeContractResolver(), + }; + + private static readonly JsonSerializerSettings m_LeanOmitNullsSettings = new JsonSerializerSettings + { + Formatting = Formatting.None, + NullValueHandling = NullValueHandling.Ignore, + ContractResolver = new LeanEnvelopeContractResolver(), + }; + + private static readonly JsonSerializerSettings m_VerboseSettings = new JsonSerializerSettings + { + Formatting = Formatting.None, + NullValueHandling = NullValueHandling.Include, + }; + + private static readonly JsonSerializerSettings m_VerboseOmitNullsSettings = new JsonSerializerSettings + { + Formatting = Formatting.None, + NullValueHandling = NullValueHandling.Ignore, + }; + + /// + /// Serialize an exec response body with the contract selected by the request's flags (see + /// the class doc for the two axes). Pure: the body is never mutated — the mode is carried + /// entirely by the serializer settings, so serializing the same instance repeatedly (in + /// any order) always yields the same JSON per mode. + /// + public static string Serialize(BaseResponse body, bool verbose, bool omitNulls = false) + { + var settings = verbose + ? (omitNulls ? m_VerboseOmitNullsSettings : m_VerboseSettings) + : (omitNulls ? m_LeanOmitNullsSettings : m_LeanSettings); + return JsonConvert.SerializeObject(body, settings); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/ExecResponseSerializer.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Common/ExecResponseSerializer.cs.meta new file mode 100644 index 0000000..92223a3 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/ExecResponseSerializer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 56ce3a87dbdb3c84bac7bccdf5c8c0fb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/FilePermissions.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Common/FilePermissions.cs new file mode 100644 index 0000000..044c06d --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/FilePermissions.cs @@ -0,0 +1,110 @@ +using System; +using System.Diagnostics; +using System.Runtime.InteropServices; +using UnityEngine; +using Debug = UnityEngine.Debug; + +namespace Unity.Pipeline +{ + /// + /// Restricts a file so that only the user who started the process can read or write it. + /// Used to protect the instance descriptor (port file), which carries the auth token. + /// + /// The managed ACL APIs (System.Security.AccessControl) are not part of Unity's runtime + /// profile, so Windows is handled via icacls and Unix via libc chmod. + /// + static class FilePermissions + { + /// + /// Restrict the file at to the current user only. + /// Failures are logged but never thrown, so they cannot block server startup. + /// + /// The file to restrict. + public static void RestrictToCurrentUser(string path) + { + try + { + switch (Application.platform) + { + case RuntimePlatform.WindowsEditor: + case RuntimePlatform.WindowsPlayer: + RestrictWindows(path); + break; + default: + RestrictUnix(path); + break; + } + } + catch (Exception ex) + { + Debug.LogWarning($"Pipeline: Could not restrict permissions on '{path}': {ex.Message}"); + } + } + + private static void RestrictWindows(string path) + { + // Grant by SID rather than account name: AzureAD/Entra-joined accounts (e.g. + // "AzureAD\\user") have no name-to-SID mapping for icacls, but the SID always resolves. + var sid = GetCurrentUserSid(); + if (string.IsNullOrEmpty(sid)) + { + Debug.LogWarning($"Pipeline: Could not resolve current user SID; leaving default permissions on '{path}'."); + return; + } + + // /inheritance:r drops inherited ACEs; /grant:r replaces the DACL with a single + // full-control grant to the current user. + Run("icacls", $"\"{path}\" /inheritance:r /grant:r \"*{sid}:(F)\"", out _); + } + + private static string GetCurrentUserSid() + { + if (!Run("whoami", "/user /fo csv /nh", out var output) || string.IsNullOrEmpty(output)) + return null; + + // Output looks like: "domain\user","S-1-5-21-..." + var idx = output.IndexOf("S-1-", StringComparison.Ordinal); + if (idx < 0) + return null; + + var end = idx; + while (end < output.Length && (char.IsLetterOrDigit(output[end]) || output[end] == '-')) + end++; + + return output.Substring(idx, end - idx); + } + + private static bool Run(string fileName, string arguments, out string stdout) + { + stdout = null; + var psi = new ProcessStartInfo(fileName, arguments) + { + UseShellExecute = false, + CreateNoWindow = true, + RedirectStandardOutput = true, + RedirectStandardError = true, + }; + + using (var process = Process.Start(psi)) + { + if (process == null) + return false; + + // Read before WaitForExit to avoid a full-pipe deadlock. + stdout = process.StandardOutput.ReadToEnd(); + process.WaitForExit(); + return process.ExitCode == 0; + } + } + + [DllImport("libc", SetLastError = true)] + private static extern int chmod(string pathname, uint mode); + + private static void RestrictUnix(string path) + { + // 0600 (octal) == owner read/write only. + const uint ownerReadWrite = 0x180; + chmod(path, ownerReadWrite); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/FilePermissions.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Common/FilePermissions.cs.meta new file mode 100644 index 0000000..211ca38 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/FilePermissions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e310dee2532338d4e914d3c909ea4db0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/ICommandDiscovery.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Common/ICommandDiscovery.cs new file mode 100644 index 0000000..6f1f37a --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/ICommandDiscovery.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using System.Reflection; + +namespace Unity.Pipeline.Commands +{ + /// + /// Interface for command discovery mechanism. + /// Allows Runtime assembly to discover commands without directly using Editor APIs. + /// + interface ICommandDiscovery + { + /// + /// Find all methods marked with CliCommand attribute. + /// Implementation uses TypeCache in Editor or reflection fallback in Runtime. + /// + /// The attribute type to search for. + /// The matching methods. + IEnumerable GetMethodsWithAttribute() where T : System.Attribute; + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/ICommandDiscovery.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Common/ICommandDiscovery.cs.meta new file mode 100644 index 0000000..4110a5b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/ICommandDiscovery.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c6e1392c576ec4d4d9b389d5fc899303 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/IStructuredCommandInput.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Common/IStructuredCommandInput.cs new file mode 100644 index 0000000..fafd213 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/IStructuredCommandInput.cs @@ -0,0 +1,28 @@ +namespace Unity.Pipeline.Commands +{ + /// + /// Marker for a command parameter type that should be advertised to clients as a nested JSON + /// object schema in GET /api/commands, instead of collapsing to string. + /// + /// Convention for command authors: when a command needs a structured (multi-field) argument, + /// declare a small DTO that implements this interface and take it as a single parameter. The + /// reflects over the type's public, writable fields and + /// properties to emit { "type": "object", "properties": { ... } } (recursing into nested + /// members and arrays/lists of them). At runtime the value + /// deserializes automatically via Newtonsoft in + /// BasePipelineServer.ExtractCommandParameters, so no extra wiring is needed. + /// + /// Member metadata: + /// + /// Annotate members with [CliArg(name, description, Required = ...)] to control the + /// property name, description, and whether it appears in the schema's required array + /// (mirrors how command parameters are described). + /// Without a [CliArg], the member name (or its Newtonsoft [JsonProperty] name) + /// is used and the member is optional. + /// [JsonIgnore] members are omitted from the schema. + /// + /// + public interface IStructuredCommandInput + { + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/IStructuredCommandInput.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Common/IStructuredCommandInput.cs.meta new file mode 100644 index 0000000..cc7ec9a --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/IStructuredCommandInput.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 366b2704c3b5c044aa544fe545d462f0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/JsonSchemaGenerator.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Common/JsonSchemaGenerator.cs new file mode 100644 index 0000000..75a5f74 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/JsonSchemaGenerator.cs @@ -0,0 +1,326 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Unity.Pipeline.Commands +{ + /// + /// Generates JSON Schema for CLI commands to enable parameter validation and help generation. + /// Produces standard JSON Schema format that CLI tools can use for validation and auto-completion. + /// + /// Primitive, enum, and array parameters map directly. Parameters whose type implements + /// are emitted as nested object schemas (recursing into + /// structured members and arrays/lists of them) rather than collapsing to string, so + /// agents calling the package — directly or as MCP tools whose schemas come from + /// GET /api/commands — can construct structured arguments reliably. + /// + static class JsonSchemaGenerator + { + /// + /// Generate JSON Schema for a command. + /// Returns standard JSON Schema format for CLI validation. + /// + /// The command to generate a schema for. + /// The generated JSON Schema document. + public static string GenerateCommandSchema(CommandInfo command) + { + if (command == null) + throw new ArgumentNullException(nameof(command)); + + var schema = new JObject + { + ["$schema"] = "http://json-schema.org/draft-07/schema#", + ["type"] = "object", + ["title"] = command.Name, + ["description"] = command.Description, + ["properties"] = GenerateParameterProperties(command.Parameters), + ["required"] = new JArray(command.Parameters.Where(p => p.Required).Select(p => p.Name)), + ["additionalProperties"] = false + }; + + // Add command metadata for CLI tools + schema["x-command-metadata"] = new JObject + { + ["mainThreadRequired"] = command.MainThreadRequired, + ["methodName"] = $"{command.Method.DeclaringType?.FullName}.{command.Method.Name}" + }; + + return schema.ToString(Formatting.Indented); + } + + /// + /// Generate properties section of JSON Schema from command parameters. + /// + private static JObject GenerateParameterProperties(IEnumerable parameters) + { + var properties = new JObject(); + + foreach (var parameter in parameters) + { + properties[parameter.Name] = GenerateParameterSchema(parameter); + } + + return properties; + } + + /// + /// Generate JSON Schema for a single top-level command parameter. + /// + private static JObject GenerateParameterSchema(CommandParameterInfo parameter) + { + var schema = GenerateTypeSchema(parameter.ParameterType, new HashSet()); + schema["description"] = parameter.Description; + + // Add default value if present (skip for objects/arrays whose default is typically null) + if (parameter.DefaultValue != null) + { + try + { + schema["default"] = JToken.FromObject(parameter.DefaultValue); + } + catch + { + // Non-serializable default; omit rather than fail schema generation. + } + } + + return schema; + } + + /// + /// Build the schema fragment for a CLR type: scalar/enum, array/list, or — for + /// types — a nested object schema. + /// tracks structured types currently being expanded so self-referential graphs don't recurse + /// forever. + /// + private static JObject GenerateTypeSchema(Type type, HashSet visited) + { + // Unwrap Nullable so e.g. int? schemas as "integer". + var underlying = Nullable.GetUnderlyingType(type); + if (underlying != null) + type = underlying; + + if (typeof(IStructuredCommandInput).IsAssignableFrom(type) && !type.IsAbstract && !type.IsInterface) + return GenerateObjectSchema(type, visited); + + if (TryGetEnumerableElementType(type, out var elementType)) + { + return new JObject + { + ["type"] = "array", + ["items"] = GenerateTypeSchema(elementType, visited) + }; + } + + var schema = new JObject(); + var (jsonType, format) = MapTypeToJsonSchema(type); + schema["type"] = jsonType; + + if (!string.IsNullOrEmpty(format)) + schema["format"] = format; + + if (type.IsEnum) + schema["enum"] = new JArray(Enum.GetNames(type)); + + return schema; + } + + /// + /// Emit a nested object schema for an type by reflecting + /// its public, writable fields and properties. + /// + private static JObject GenerateObjectSchema(Type type, HashSet visited) + { + var schema = new JObject { ["type"] = "object" }; + + // Cycle guard: if we're already expanding this type higher in the stack, stop recursing + // and emit an open object rather than looping. + if (!visited.Add(type)) + { + schema["additionalProperties"] = true; + return schema; + } + + try + { + var properties = new JObject(); + var required = new JArray(); + + foreach (var member in GetSchemaMembers(type)) + { + var memberSchema = GenerateTypeSchema(member.Type, visited); + if (!string.IsNullOrEmpty(member.Description)) + memberSchema["description"] = member.Description; + + properties[member.Name] = memberSchema; + if (member.Required) + required.Add(member.Name); + } + + schema["properties"] = properties; + if (required.Count > 0) + schema["required"] = required; + schema["additionalProperties"] = false; + } + finally + { + visited.Remove(type); + } + + return schema; + } + + /// + /// Enumerate the schema-bearing members of a structured-input type: public instance fields and + /// read/write properties. Honors [JsonIgnore], and reads name/description/required from + /// [CliArg] (falling back to a Newtonsoft [JsonProperty] name, then the member name). + /// + private static IEnumerable GetSchemaMembers(Type type) + { + const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance; + + foreach (var field in type.GetFields(flags)) + { + if (field.IsInitOnly || field.IsLiteral) + continue; + if (field.GetCustomAttribute() != null) + continue; + + yield return ToSchemaMember(field, field.FieldType); + } + + foreach (var property in type.GetProperties(flags)) + { + if (!property.CanRead || !property.CanWrite) + continue; + if (property.GetIndexParameters().Length > 0) + continue; + if (property.GetCustomAttribute() != null) + continue; + + yield return ToSchemaMember(property, property.PropertyType); + } + } + + private static SchemaMember ToSchemaMember(MemberInfo member, Type memberType) + { + var cliArg = member.GetCustomAttribute(); + var jsonProperty = member.GetCustomAttribute(); + + return new SchemaMember + { + Name = cliArg?.Name ?? jsonProperty?.PropertyName ?? member.Name, + Type = memberType, + Description = cliArg?.Description, + Required = cliArg?.Required ?? false + }; + } + + /// + /// Detect a JSON-array-shaped type (arrays and common generic collections) and yield its + /// element type. string is intentionally excluded (it is + /// of char but maps to a JSON string). + /// + private static bool TryGetEnumerableElementType(Type type, out Type elementType) + { + elementType = null; + + if (type == typeof(string)) + return false; + + if (type.IsArray) + { + elementType = type.GetElementType(); + return elementType != null; + } + + if (type.IsGenericType) + { + var definition = type.GetGenericTypeDefinition(); + if (definition == typeof(List<>) || definition == typeof(IList<>) || + definition == typeof(IEnumerable<>) || definition == typeof(ICollection<>) || + definition == typeof(IReadOnlyList<>) || definition == typeof(IReadOnlyCollection<>)) + { + elementType = type.GetGenericArguments()[0]; + return true; + } + } + + return false; + } + + /// + /// Map a scalar/enum C# type to JSON Schema type and format. Object and array shapes are + /// handled by before this is reached; anything else falls + /// back to string. + /// + private static (string type, string format) MapTypeToJsonSchema(Type csharpType) + { + // Handle nullable types + if (Nullable.GetUnderlyingType(csharpType) != null) + { + csharpType = Nullable.GetUnderlyingType(csharpType); + } + + // String types + if (csharpType == typeof(string) || csharpType == typeof(char)) + { + return ("string", null); + } + + // Integer types + if (csharpType == typeof(int) || csharpType == typeof(long) || + csharpType == typeof(short) || csharpType == typeof(byte) || + csharpType == typeof(uint) || csharpType == typeof(ulong) || + csharpType == typeof(ushort) || csharpType == typeof(sbyte)) + { + return ("integer", null); + } + + // Number types + if (csharpType == typeof(float) || csharpType == typeof(double) || csharpType == typeof(decimal)) + { + return ("number", null); + } + + // Boolean type + if (csharpType == typeof(bool)) + { + return ("boolean", null); + } + + // Enum types - represent as string with enum constraint (added by the caller) + if (csharpType.IsEnum) + { + return ("string", null); + } + + // DateTime types + if (csharpType == typeof(DateTime) || csharpType == typeof(DateTimeOffset)) + { + return ("string", "date-time"); + } + + // Guid type + if (csharpType == typeof(Guid)) + { + return ("string", "uuid"); + } + + // Default to string for unknown types + return ("string", null); + } + + /// A reflected member of a structured-input type, flattened for schema emission. + private struct SchemaMember + { + public string Name; + public Type Type; + public string Description; + public bool Required; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/JsonSchemaGenerator.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Common/JsonSchemaGenerator.cs.meta new file mode 100644 index 0000000..34f6582 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/JsonSchemaGenerator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 779098faca184884f9f588e41c4c0898 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/MaxLengthStream.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Common/MaxLengthStream.cs new file mode 100644 index 0000000..aa41352 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/MaxLengthStream.cs @@ -0,0 +1,97 @@ +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace Unity.Pipeline +{ + /// + /// Read-only stream wrapper that enforces a maximum number of bytes read from an inner stream. + /// Once cumulative reads exceed maxBytes, the next read throws + /// . Used to cap HTTP request bodies even when the + /// Content-Length header is absent or untruthful (e.g. chunked transfer-encoding), so an + /// oversized body cannot be buffered into memory. + /// + internal sealed class MaxLengthStream : Stream + { + private readonly Stream m_Inner; + private readonly long m_MaxBytes; + private readonly bool m_LeaveOpen; + private long m_TotalRead; + + /// + /// When true, disposing this wrapper does not dispose . The server + /// uses this so it can keep reading (draining) the raw request stream after the wrapper is + /// disposed on an over-limit read. + /// + public MaxLengthStream(Stream inner, long maxBytes, bool leaveOpen = false) + { + m_Inner = inner ?? throw new ArgumentNullException(nameof(inner)); + m_MaxBytes = maxBytes; + m_LeaveOpen = leaveOpen; + } + + public override int Read(byte[] buffer, int offset, int count) + { + var read = m_Inner.Read(buffer, offset, count); + Account(read); + return read; + } + + public override async Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) + { + var read = await m_Inner.ReadAsync(buffer, offset, count, cancellationToken); + Account(read); + return read; + } + + // Throw as soon as the running total exceeds the cap. Exactly maxBytes is allowed. + private void Account(int read) + { + if (read <= 0) + return; + + m_TotalRead += read; + if (m_TotalRead > m_MaxBytes) + throw new RequestTooLargeException(m_MaxBytes); + } + + public override bool CanRead => true; + public override bool CanSeek => false; + public override bool CanWrite => false; + public override long Length => throw new NotSupportedException(); + public override long Position + { + get => m_TotalRead; + set => throw new NotSupportedException(); + } + + public override void Flush() { } + public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); + public override void SetLength(long value) => throw new NotSupportedException(); + public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); + + protected override void Dispose(bool disposing) + { + // Own the inner stream's lifetime (matching the previous `using (StreamReader(InputStream))`) + // unless the caller asked to leave it open so it can keep reading from it afterwards. + if (disposing && !m_LeaveOpen) + m_Inner.Dispose(); + base.Dispose(disposing); + } + } + + /// + /// Thrown by when a read would exceed the configured byte cap. + /// + internal sealed class RequestTooLargeException : Exception + { + public long MaxBytes { get; } + + public RequestTooLargeException(long maxBytes) + : base($"Request body exceeds the maximum allowed size of {maxBytes} bytes.") + { + MaxBytes = maxBytes; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/MaxLengthStream.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Common/MaxLengthStream.cs.meta new file mode 100644 index 0000000..1b0dca1 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/MaxLengthStream.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d75fa6089aa06114c9450387a6d816ad +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/ParameterInfo.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Common/ParameterInfo.cs new file mode 100644 index 0000000..a60d255 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/ParameterInfo.cs @@ -0,0 +1,62 @@ +using System; + +namespace Unity.Pipeline.Commands +{ + /// + /// Information about a CLI command parameter. + /// Contains metadata needed for parameter validation and CLI help generation. + /// + public class CommandParameterInfo + { + /// + /// Name of the parameter for CLI arguments. + /// + public string Name { get; } + + /// + /// Human-readable description of the parameter. + /// + public string Description { get; } + + /// + /// Whether this parameter is required for command execution. + /// + public bool Required { get; } + + /// + /// Type of the parameter for validation and conversion. + /// + public Type ParameterType { get; } + + /// + /// Default value for optional parameters. + /// + public object DefaultValue { get; } + + /// + /// Create parameter information from discovery. + /// + /// Name of the parameter for CLI arguments. + /// Human-readable description of the parameter. + /// Whether this parameter is required for command execution. + /// Type of the parameter for validation and conversion. + /// Default value for optional parameters. + public CommandParameterInfo(string name, string description, bool required, + Type parameterType, object defaultValue = null) + { + Name = name ?? throw new ArgumentNullException(nameof(name)); + Description = description ?? throw new ArgumentNullException(nameof(description)); + ParameterType = parameterType ?? throw new ArgumentNullException(nameof(parameterType)); + Required = required; + DefaultValue = defaultValue; + } + + /// A short diagnostic summary of the parameter. + /// The summary string. + public override string ToString() + { + return $"{Name} Required:{Required} Type:{ParameterType}"; + } + + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/ParameterInfo.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Common/ParameterInfo.cs.meta new file mode 100644 index 0000000..445c8ac --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/ParameterInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7127497e92677024f949772c30aaf79b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/PipelineJobs.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Common/PipelineJobs.cs new file mode 100644 index 0000000..8dc0dd9 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/PipelineJobs.cs @@ -0,0 +1,270 @@ +using System; +using System.Collections.Concurrent; +using System.Linq; + +namespace Unity.Pipeline +{ + /// + /// Lifecycle states of a detached command job (CLI-335). + /// Serialized to the wire as lower-case strings (see BasePipelineServer). + /// + internal enum PipelineJobState + { + Queued, + Running, + Completed, + Failed, + Canceled + } + + /// One detached command execution tracked by . + internal sealed class PipelineJobRecord + { + public string Id; + public string Command; + public PipelineJobState State; + public object Result; + public string Error; + public string ErrorDetails; + public DateTime EnqueuedAt; + public DateTime? StartedAt; + public DateTime? CompletedAt; + public volatile bool CancellationRequested; + + /// Guards State/Result/Error/timestamps; reads and writes cross threads. + public readonly object Gate = new object(); + } + + /// + /// Registry of detached command jobs (CLI-335): a client can submit a command as a job + /// (`/api/exec` with `"job": true`), get a job id back immediately, and later poll + /// `/api/job?id=…` to reattach and collect the result — surviving the client's own HTTP + /// timeout. Results are retained (bounded, see below) so a client that timed out or + /// disconnected can still fetch the outcome. + /// + /// Owned one-per- (the same pattern as Dispatcher), so + /// a test server's jobs can never cross-attribute state with the live server's. + /// + /// In-memory by design: a domain reload (script recompilation) discards pending jobs the + /// same way it discards every other C# static. That limitation is inherent to in-Editor + /// state and is tracked separately. + /// + internal sealed class PipelineJobRegistry + { + /// Completed/failed/canceled jobs retained beyond this count are pruned oldest-first. + private const int MaxRetainedTerminalJobs = 100; + + /// + /// Jobs allowed queued or running at once. Jobs execute strictly serially through the + /// exec gate, so a deep backlog beyond this is pure queued work with no throughput + /// benefit — an authorized client loop (or a retrying script) submitting faster than jobs + /// drain would otherwise grow this without bound. + /// + private const int MaxQueuedJobs = 100; + + /// Terminal jobs older than this are pruned regardless of count. + private static readonly TimeSpan m_RetentionTtl = TimeSpan.FromHours(1); + + private readonly ConcurrentDictionary m_Jobs = + new ConcurrentDictionary(); + + /// Guards the queued-job cap check against a concurrent create racing past it. + private readonly object m_CreateGate = new object(); + + /// + /// The record currently executing. At most one job runs at a time (jobs share the + /// server's exec gate), so a single reference suffices; read by + /// from whatever thread the command runs on. + /// + private volatile PipelineJobRecord m_CurrentRunning; + + internal PipelineJobRecord CurrentRunning => m_CurrentRunning; + + /// + /// Create a queued job for , unless + /// queued-or-running jobs already exist (returns false; the caller should reject the + /// submission rather than grow an unbounded backlog). + /// + internal bool TryCreate(string command, out PipelineJobRecord record) + { + Prune(); + + lock (m_CreateGate) + { + var nonTerminal = m_Jobs.Values.Count(job => + { + lock (job.Gate) + { + return job.State == PipelineJobState.Queued || job.State == PipelineJobState.Running; + } + }); + if (nonTerminal >= MaxQueuedJobs) + { + record = null; + return false; + } + + record = new PipelineJobRecord + { + Id = Guid.NewGuid().ToString("N"), + Command = command, + State = PipelineJobState.Queued, + EnqueuedAt = DateTime.UtcNow + }; + m_Jobs[record.Id] = record; + } + return true; + } + + internal bool TryGet(string id, out PipelineJobRecord record) + { + Prune(); + return m_Jobs.TryGetValue(id ?? string.Empty, out record); + } + + internal void MarkRunning(PipelineJobRecord record) + { + lock (record.Gate) + { + record.State = PipelineJobState.Running; + record.StartedAt = DateTime.UtcNow; + } + m_CurrentRunning = record; + } + + internal void MarkCompleted(PipelineJobRecord record, object result) + { + lock (record.Gate) + { + record.State = PipelineJobState.Completed; + record.Result = result; + record.CompletedAt = DateTime.UtcNow; + } + ClearCurrent(record); + } + + internal void MarkFailed(PipelineJobRecord record, string error, string details) + { + lock (record.Gate) + { + record.State = PipelineJobState.Failed; + record.Error = error; + record.ErrorDetails = details; + record.CompletedAt = DateTime.UtcNow; + } + ClearCurrent(record); + } + + internal void MarkCanceled(PipelineJobRecord record) + { + lock (record.Gate) + { + record.State = PipelineJobState.Canceled; + record.CompletedAt = DateTime.UtcNow; + } + ClearCurrent(record); + } + + /// + /// Request cancellation. A queued job is canceled before it ever starts (the runner + /// checks the flag under the exec gate); a running job gets a cooperative flag that + /// command/eval code can observe via — arbitrary + /// synchronous main-thread code cannot be aborted safely, so cancellation of a running + /// job takes effect only when the code cooperates (mirroring how test cancellation + /// requires the runner's cooperation). + /// + internal bool RequestCancel(string id, out PipelineJobRecord record) + { + if (!TryGet(id, out record)) + { + return false; + } + record.CancellationRequested = true; + return true; + } + + private void ClearCurrent(PipelineJobRecord record) + { + if (ReferenceEquals(m_CurrentRunning, record)) + { + m_CurrentRunning = null; + } + } + + private void Prune() + { + var now = DateTime.UtcNow; + var terminal = m_Jobs.Values + .Where(job => + { + lock (job.Gate) + { + return job.State == PipelineJobState.Completed + || job.State == PipelineJobState.Failed + || job.State == PipelineJobState.Canceled; + } + }) + .OrderBy(job => job.CompletedAt ?? job.EnqueuedAt) + .ToList(); + + // Oldest-first: drop everything beyond the retained count, plus anything expired. + var excess = terminal.Count - MaxRetainedTerminalJobs; + for (var i = 0; i < terminal.Count; i++) + { + var job = terminal[i]; + var expired = now - (job.CompletedAt ?? job.EnqueuedAt) > m_RetentionTtl; + if (i < excess || expired) + { + m_Jobs.TryRemove(job.Id, out _); + } + } + } + + /// Test hook: forget every job. + internal void Reset() + { + m_Jobs.Clear(); + m_CurrentRunning = null; + } + } + + /// + /// Cooperative cancellation for detached jobs (CLI-335). Long-running command or + /// eval code checks this periodically; when a client has requested cancellation + /// (POST /api/job/cancel), the code can wind down early: + /// + /// for (int i = 0; i < n; i++) + /// { + /// Unity.Pipeline.PipelineCancellation.ThrowIfCancellationRequested(); + /// // … chunk of work … + /// } + /// + /// Arbitrary synchronous code cannot be aborted safely from outside, so a running job + /// that never checks this flag runs to completion (its state still reports canceled). + /// This is a thin static façade over the executing server's own + /// (resolved via ) + /// so command code — which has no reference to "which server is running me" — can keep + /// calling this the same way regardless of which server dispatched it. + /// + public static class PipelineCancellation + { + /// True when the currently executing job has been asked to cancel. + public static bool IsCancellationRequested + { + get + { + var current = BasePipelineServer.CurrentServer?.JobRegistry.CurrentRunning; + return current != null && current.CancellationRequested; + } + } + + /// Throw when cancellation was requested. + public static void ThrowIfCancellationRequested() + { + if (IsCancellationRequested) + { + throw new OperationCanceledException("Pipeline job cancellation was requested"); + } + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/PipelineJobs.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Common/PipelineJobs.cs.meta new file mode 100644 index 0000000..1225aee --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/PipelineJobs.cs.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 34693b29c0c343d9804a82d9b234ea3f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetVersion: 1 diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/PipelineUtils.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Common/PipelineUtils.cs new file mode 100644 index 0000000..1ae20f5 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/PipelineUtils.cs @@ -0,0 +1,231 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using UnityEngine; +#if UNITY_6000_3_OR_NEWER +using UnityEngine.Assemblies; +#endif + +namespace Unity.Pipeline +{ + /// + /// Version-stable handle to a Unity object id. In 6000.4 Unity replaced the int instance id with + /// (a ulong-backed handle), made Object.GetInstanceID() / + /// EditorUtility.InstanceIDToObject(int) obsolete-as-error, and is removing the + /// EntityId<->int conversions. This struct stores the concrete id type for the + /// running editor — on 6000.4+, int below — and converts implicitly to + /// it so it can be passed straight to Unity APIs. All version branching for object ids is confined + /// here. It (de)serializes as a single JSON integer (the raw ulong on 6000.4+, the int below). + /// + [JsonConverter(typeof(ObjectIdConverter))] + public readonly struct ObjectId : System.IEquatable + { +#if UNITY_6000_4_OR_NEWER + readonly EntityId m_Value; + /// Wrap an . + /// The entity id to wrap. + public ObjectId(EntityId value) { m_Value = value; } + /// Unwrap to the underlying . + /// The id to unwrap. + /// The underlying entity id. + public static implicit operator EntityId(ObjectId id) => id.m_Value; + /// Wrap an . + /// The entity id to wrap. + /// The wrapped id. + public static implicit operator ObjectId(EntityId value) => new ObjectId(value); + /// Raw 64-bit id — the canonical wire / serialization form. + public ulong RawValue => EntityId.ToULong(m_Value); + /// Reconstruct an from its raw wire value. + /// The raw wire value. + /// The reconstructed id. + public static ObjectId FromRaw(ulong raw) => new ObjectId(EntityId.FromULong(raw)); + /// Value-equality on the underlying id. + /// The id to compare against. + /// True if the underlying ids are equal. + public bool Equals(ObjectId other) => m_Value.Equals(other.m_Value); + /// Hash of the underlying id. + /// The hash code. + public override int GetHashCode() => m_Value.GetHashCode(); +#else + readonly int m_Value; + /// Wrap a raw instance id. + /// The instance id to wrap. + public ObjectId(int value) { m_Value = value; } + /// Unwrap to the underlying instance id. + /// The id to unwrap. + /// The underlying instance id. + public static implicit operator int(ObjectId id) => id.m_Value; + /// Wrap a raw instance id. + /// The instance id to wrap. + /// The wrapped id. + public static implicit operator ObjectId(int value) => new ObjectId(value); + /// Raw id — the canonical wire / serialization form. + public long RawValue => m_Value; + /// Reconstruct an from its raw wire value. + /// The raw wire value. + /// The reconstructed id. + public static ObjectId FromRaw(long raw) => new ObjectId((int)raw); + /// Value-equality on the underlying id. + /// The id to compare against. + /// True if the underlying ids are equal. + public bool Equals(ObjectId other) => m_Value == other.m_Value; + /// Hash of the underlying id. + /// The hash code. + public override int GetHashCode() => m_Value; +#endif + /// Value-equality on the underlying id. + /// The object to compare against. + /// True if is an equal . + public override bool Equals(object obj) => obj is ObjectId other && Equals(other); + /// The canonical numeric wire form (see ). + /// The numeric string form. + public override string ToString() => RawValue.ToString(); + + /// Parse the canonical numeric form produced by . + /// The numeric string to parse. + /// The parsed id. + public static ObjectId Parse(string s) + { +#if UNITY_6000_4_OR_NEWER + return FromRaw(ulong.Parse(s)); +#else + return FromRaw(long.Parse(s)); +#endif + } + + /// Try to parse the canonical numeric form produced by . + /// The numeric string to parse. + /// The parsed id, if successful. + /// True if was a valid numeric form. + public static bool TryParse(string s, out ObjectId id) + { +#if UNITY_6000_4_OR_NEWER + if (ulong.TryParse(s, out var raw)) { id = FromRaw(raw); return true; } +#else + if (long.TryParse(s, out var raw)) { id = FromRaw(raw); return true; } +#endif + id = default; + return false; + } + } + + /// JSON converter: an is a single integer on the wire. + sealed class ObjectIdConverter : JsonConverter + { + /// Write an as its raw numeric wire value. + /// The JSON writer. + /// The id to write. + /// The active serializer. + public override void WriteJson(JsonWriter writer, ObjectId value, JsonSerializer serializer) + { + writer.WriteValue(value.RawValue); + } + + /// Read an from either its numeric or string wire form. + /// The JSON reader. + /// The declared property type. + /// The existing value, if any. + /// Whether is valid. + /// The active serializer. + /// The parsed id, or default for an unrecognized token type. + public override ObjectId ReadJson(JsonReader reader, System.Type objectType, ObjectId existingValue, + bool hasExistingValue, JsonSerializer serializer) + { + var token = JToken.Load(reader); + switch (token.Type) + { + case JTokenType.Integer: +#if UNITY_6000_4_OR_NEWER + return ObjectId.FromRaw(token.Value()); +#else + return ObjectId.FromRaw(token.Value()); +#endif + case JTokenType.String: + return ObjectId.Parse((string)token); + default: + return default; + } + } + } + + /// Small cross-Unity-version compatibility shims used across the package. + public static class PipelineUtils + { + /// The on-disk path Unity loaded an assembly from. + /// The assembly to query. + /// The assembly's loaded path. + public static string GetLoadedAssemblyPath(System.Reflection.Assembly a) + { +#if UNITY_6000_5_OR_NEWER + return a.GetLoadedAssemblyPath(); +#else + return a.Location; +#endif + } + + /// Load a compiled assembly from raw bytes (used by the code-reload/eval compilers). + /// The assembly image. + /// The matching portable PDB, if any. + /// The loaded assembly. + public static System.Reflection.Assembly LoadFromBytes(byte[] bytes, byte[] pdb = null) + { +#if UNITY_6000_5_OR_NEWER + return UnityEngine.Assemblies.CurrentAssemblies.LoadFromBytes(bytes, pdb); +#else + return System.Reflection.Assembly.Load(bytes, pdb); +#endif + } + + /// Find every loaded object of type , including inactive ones. + /// The object type to search for. + /// All matching objects. + public static T[] FindObjectsByType() where T : Object + { +#if UNITY_6000_4_OR_NEWER + return GameObject.FindObjectsByType(); +#else + return GameObject.FindObjectsByType(FindObjectsSortMode.None) ; +#endif + } + + /// All assemblies currently loaded in the domain. + /// The loaded assemblies. + public static IReadOnlyList GetLoadedAssemblies() + { +#if UNITY_6000_5_OR_NEWER + return CurrentAssemblies.GetLoadedAssemblies(); +#else + return System.AppDomain.CurrentDomain.GetAssemblies(); +#endif + } + + /// The object's id as a version-stable (EntityId on 6000.4+, int below). + /// The object to get an id for. + /// The object's version-stable id. + public static ObjectId GetObjectId(Object obj) + { +#if UNITY_6000_4_OR_NEWER + return new ObjectId(obj.GetEntityId()); +#else + return new ObjectId(obj.GetInstanceID()); +#endif + } + +#if UNITY_EDITOR + /// Resolve a loaded/scene object from its , or null if not found. + public static Object IdToObject(ObjectId id) + { +#if UNITY_6000_4_OR_NEWER + return UnityEditor.EditorUtility.EntityIdToObject(id); +#elif UNITY_6000_3_OR_NEWER + // EntityIdToObject is the non-obsolete resolver from 6000.3, but the ulong-backed ObjectId + // (GetRawData/FromULong) doesn't exist until 6000.4 — so ObjectId is still int-backed here and + // we route the int through the (non-obsolete on 6.3) int->EntityId conversion. + return UnityEditor.EditorUtility.EntityIdToObject((int)id); +#else + return UnityEditor.EditorUtility.InstanceIDToObject((int)id); +#endif + } +#endif + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/PipelineUtils.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Common/PipelineUtils.cs.meta new file mode 100644 index 0000000..436cb52 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/PipelineUtils.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e6c6a6cac05ac41438850c53ea3178b1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/RotatingFileBackup.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Common/RotatingFileBackup.cs new file mode 100644 index 0000000..ad47f7b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/RotatingFileBackup.cs @@ -0,0 +1,31 @@ +using System.IO; + +namespace Unity.Pipeline +{ + /// + /// The one piece of "rotate a log file" that PipelineTransactionLog (a whole-file JSON + /// array, rotated once per Unity session) and EvalUsageTelemetry (true JSONL, rotated on + /// a byte-size cap) actually share verbatim: swapping the active file for a backup. Everything + /// else — the append shape, the lock, and what triggers a rotation — differs enough between the + /// two that forcing them into one bigger "rotating append log" abstraction would cost more + /// clarity than the duplication it removes, so only this file-swap step is factored out. + /// + static class RotatingFileBackup + { + /// + /// Move to , replacing any prior + /// backup, so the active path is free for a fresh file. No-op when there is no active file. + /// Callers are responsible for their own locking around this — it performs no synchronization + /// itself. + /// + public static void RotateToBackup(string activePath, string backupPath) + { + if (!File.Exists(activePath)) + return; + + if (File.Exists(backupPath)) + File.Delete(backupPath); + File.Move(activePath, backupPath); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Common/RotatingFileBackup.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Common/RotatingFileBackup.cs.meta new file mode 100644 index 0000000..d50f94f --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Common/RotatingFileBackup.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 24f2295b1c6944c89c0615c9be0ed96a diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Compilation.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Compilation.meta new file mode 100644 index 0000000..ded6006 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Compilation.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 257ad47737473da48b7569484405904e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/CodeReloadCompiler.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/CodeReloadCompiler.cs new file mode 100644 index 0000000..b01c52a --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/CodeReloadCompiler.cs @@ -0,0 +1,578 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using Unity.Pipeline.CodeReload; +using Unity.Pipeline.Models; +using Unity.Pipeline.Threading; +using UnityEngine; + +namespace Unity.Pipeline.Compilation +{ + /// + /// Compiles transformed code reload source using the shared RoslynCompilationService. + /// Creates versioned DLLs and manages code reload assembly lifecycle. + /// + static class CodeReloadCompiler + { + /// + /// Interpreter-targeted overrides (in-editor backend and push-to-player) carry an embedded + /// PDB and #line mapping, so runtime errors report the user's source file and line instead + /// of an IL offset. Costs a few KB per pushed override and compiles it unoptimized + /// (irrelevant to interpreted execution). Always on; this knob exists only so tests can + /// exercise the no-line-info error path — nothing in production writes it, and a domain + /// reload resets it to true. + /// + internal static bool EmitSourceLineInfo = true; + +#if UNITY_EDITOR || (UNITY_STANDALONE && DEBUG) + + private static readonly Dictionary _versionTracker = new(); + private const string CodeReloadTempDir = "Temp/CodeReload"; + + /// + /// Compile source code on main thread synchronously to avoid deadlocks. + /// + /// Code reload source code to compile. + /// Base filename for versioned assembly naming. + /// Optional directory to save compiled assembly to disk. + /// Emit a portable PDB and load symbols so breakpoints can bind. + /// Source document path recorded in the PDB (the original .cs file). + /// When set, the compiled bytes register with the interpreter backend instead of Assembly.Load. + /// The compilation result. + internal static CodeReloadCompileResult CompileSourceCodeOnMainThread(string sourceCode, string baseFileName, string assemblyDir = null, bool emitPdb = false, string documentPath = null, InterpreterOverrideSet interpreterMethods = null) + { + var stopwatch = System.Diagnostics.Stopwatch.StartNew(); + var useInterpreter = interpreterMethods != null; + + try + { + Debug.Log($"CodeReload: Starting synchronous source code compilation for {baseFileName}"); + + if (string.IsNullOrWhiteSpace(sourceCode)) + { + return CodeReloadCompileResult.Failure( + "Empty Source Code", + "Source code cannot be empty", + stopwatch.ElapsedMilliseconds); + } + + // Generate versioned assembly name + var nextVersion = GetNextVersion(baseFileName); + var assemblyName = $"{baseFileName}_{nextVersion:D3}"; + + // Ensure temp directory exists + Directory.CreateDirectory(CodeReloadTempDir); + + // The interpreter path needs only the bytes (no Assembly.Load), with the PDB embedded + // in them: the interpreter reads sequence points only from an embedded PDB and uses + // them for source lines in runtime error messages. + var compilationResult = CompileCodeReloadAssembly(sourceCode, assemblyName, + emitPdb: emitPdb && !useInterpreter, documentPath, loadAssembly: !useInterpreter, + embedPdb: useInterpreter && EmitSourceLineInfo); + + if (!compilationResult.Success) + { + var dumpPath = DumpFailedSource(assemblyName, sourceCode); + return CodeReloadCompileResult.Failure( + "Compilation Failed", + "Code reload source code compilation failed" + + (dumpPath != null ? $" (generated source: {dumpPath})" : ""), + stopwatch.ElapsedMilliseconds, + compilationResult.Diagnostics.Select(FormatDiagnostic).ToList()); + } + + List registeredMethods; + List skippedOverrides; + if (useInterpreter) + { + registeredMethods = InterpreterCodeReloadExecutor.Register( + compilationResult.AssemblyBytes, interpreterMethods.TypeName, interpreterMethods.MethodNames, + out skippedOverrides, out var bindingWarnings); + // The reload response carries one flat Diagnostics list; append binding warnings + // (unbound host members that throw only if reached) so the client sees the gap + // in the same reply that reports the reload as applied. + skippedOverrides.AddRange(bindingWarnings); + } + else + { + registeredMethods = RegisterCodeReloadMethods(compilationResult.Assembly, assemblyName, out skippedOverrides); + } + + // Save assembly to disk if assemblyDir is specified + string actualAssemblyPath = null; + if (!string.IsNullOrWhiteSpace(assemblyDir)) + { + Directory.CreateDirectory(assemblyDir); + actualAssemblyPath = Path.Combine(assemblyDir, $"{assemblyName}.dll"); + File.WriteAllBytes(actualAssemblyPath, compilationResult.AssemblyBytes); + Debug.Log($"CodeReload: Assembly saved to disk: {actualAssemblyPath}"); + + // Symbols are loaded in-memory; also write the .pdb next to the .dll for convenience. + if (compilationResult.PdbBytes != null) + { + var pdbPath = Path.Combine(assemblyDir, $"{assemblyName}.pdb"); + File.WriteAllBytes(pdbPath, compilationResult.PdbBytes); + Debug.Log($"CodeReload: Symbols saved to disk: {pdbPath}"); + } + } + else + { + actualAssemblyPath = Path.Combine(CodeReloadTempDir, $"{assemblyName}.dll"); // For compatibility (in-memory) + } + + stopwatch.Stop(); + + Debug.Log($"CodeReload: Successfully compiled source code -> {assemblyName}.dll with {registeredMethods.Count} methods in {stopwatch.ElapsedMilliseconds}ms"); + + var sourceCompileResult = CodeReloadCompileResult.Success( + assemblyName, + actualAssemblyPath, + registeredMethods, + stopwatch.ElapsedMilliseconds); + sourceCompileResult.Diagnostics = skippedOverrides; + return sourceCompileResult; + } + catch (Exception ex) + { + stopwatch.Stop(); + Debug.LogError($"CodeReload: Synchronous source code compilation failed for {baseFileName}: {ex.Message}"); + return CodeReloadCompileResult.Failure( + "Exception", + ex.ToString(), + stopwatch.ElapsedMilliseconds); + } + } + + /// + /// Clean up old code reload DLL versions, keeping only the latest for each base filename. + /// + /// Directory containing code-reload assemblies, or null for the default temp directory. + /// Which files were deleted, and whether cleanup succeeded. + public static CodeReloadCleanupResult CleanupCodeReloadDlls(string assemblyDir = null) + { + var stopwatch = System.Diagnostics.Stopwatch.StartNew(); + var deletedFiles = new List(); + + try + { + // Use specified assemblyDir or default to CodeReloadTempDir + var targetDir = !string.IsNullOrWhiteSpace(assemblyDir) ? assemblyDir : CodeReloadTempDir; + + if (!Directory.Exists(targetDir)) + { + return new CodeReloadCleanupResult + { + Success = true, + DeletedFiles = deletedFiles, + Message = $"No code reload directory found: {targetDir}", + ExecutionTimeMs = stopwatch.ElapsedMilliseconds + }; + } + + var dllFiles = Directory.GetFiles(targetDir, "*.dll"); + var groupedFiles = dllFiles + .Select(f => new + { + FilePath = f, + FileName = Path.GetFileNameWithoutExtension(f), + BaseFilename = ExtractBaseFilename(Path.GetFileNameWithoutExtension(f)), + Version = ExtractVersion(Path.GetFileNameWithoutExtension(f)) + }) + .Where(f => f.Version > 0) // Only versioned code reload DLLs + .GroupBy(f => f.BaseFilename) + .ToList(); + + foreach (var group in groupedFiles) + { + var sortedFiles = group.OrderByDescending(f => f.Version).ToList(); + + // Keep the latest version, delete older ones + for (int i = 1; i < sortedFiles.Count; i++) + { + var fileToDelete = sortedFiles[i]; + File.Delete(fileToDelete.FilePath); + deletedFiles.Add(fileToDelete.FileName + ".dll"); + Debug.Log($"CodeReload: Deleted old version {fileToDelete.FileName}.dll"); + } + } + + // Clear registry and reset version tracker + CodeReloadRegistry.ClearAllOverrides(); + _versionTracker.Clear(); + + stopwatch.Stop(); + + Debug.Log($"CodeReload: Cleanup completed - deleted {deletedFiles.Count} files in {stopwatch.ElapsedMilliseconds}ms"); + + return new CodeReloadCleanupResult + { + Success = true, + DeletedFiles = deletedFiles, + Message = $"Deleted {deletedFiles.Count} old DLL versions", + ExecutionTimeMs = stopwatch.ElapsedMilliseconds + }; + } + catch (Exception ex) + { + stopwatch.Stop(); + Debug.LogError($"CodeReload: Cleanup failed: {ex.Message}"); + + return new CodeReloadCleanupResult + { + Success = false, + DeletedFiles = deletedFiles, + Message = $"Cleanup failed: {ex.Message}", + ExecutionTimeMs = stopwatch.ElapsedMilliseconds + }; + } + } + + /// + /// Get the next version number for a base filename. + /// + private static int GetNextVersion(string baseFilename) + { + if (!_versionTracker.ContainsKey(baseFilename)) + { + _versionTracker[baseFilename] = 0; + } + + return ++_versionTracker[baseFilename]; + } + + /// + /// Compile transformed override source to raw assembly bytes without loading or registering + /// anything, for the push-to-player path (the device runs the bytes through the interpreter). + /// The PDB is embedded so the interpreter can report source lines instead of IL offsets; + /// is recorded for source outside the transform's #line + /// directives. + /// + internal static bool TryCompileOverrideBytes(string transformedCode, string baseFileName, out byte[] ilBytes, out List diagnostics, string documentPath = null, string[] preprocessorSymbols = null) + { + ilBytes = null; + diagnostics = new List(); + + var assemblyName = $"{baseFileName}_{GetNextVersion(baseFileName):D3}"; + var result = CompileCodeReloadAssembly(transformedCode, assemblyName, emitPdb: false, documentPath: documentPath, loadAssembly: false, embedPdb: EmitSourceLineInfo, preprocessorSymbols: preprocessorSymbols); + if (!result.Success) + { + diagnostics = result.Diagnostics.Select(FormatDiagnostic).ToList(); + var dumpPath = DumpFailedSource(assemblyName, transformedCode); + if (dumpPath != null) + diagnostics.Add($"Generated source written to {dumpPath}"); + return false; + } + + ilBytes = result.AssemblyBytes; + return ilBytes != null && ilBytes.Length > 0; + } + + /// + /// One diagnostic as the user should read it: the line of THEIR file it maps to (via the + /// transform's #line directives), the compiler message, and the generated line that + /// actually failed. The generated source differs from what the user wrote (bodies are + /// lifted into a static class, members re-qualified), so a bare compiler message such as + /// "the type name 'var' does not exist in the type 'Foo'" is not debuggable on its own. + /// + internal static string FormatDiagnostic(DiagnosticInfo d) + { + var where = d.File != null + ? $"{Path.GetFileName(d.File)}({d.FileLine})" + : $"generated line {d.Line + 1}"; + var text = $"{where}: {d.Severity} {d.Id}: {d.Message}"; + if (!string.IsNullOrEmpty(d.Source)) + text += $"\n generated line {d.Line + 1}: {d.Source}"; + return text; + } + + /// + /// Write the generated override source next to the versioned DLLs so a failed compile can + /// be inspected whole. Returns the path, or null when the write failed (never fatal). + /// + private static string DumpFailedSource(string assemblyName, string sourceCode) + { + try + { + Directory.CreateDirectory(CodeReloadTempDir); + var path = Path.Combine(CodeReloadTempDir, $"{assemblyName}.failed.cs"); + File.WriteAllText(path, sourceCode); + return path; + } + catch (Exception) + { + return null; + } + } + + /// + /// Compile code reload source code using shared RoslynCompilationService. + /// Synchronous compilation for main thread use. + /// + private static CompilationResult CompileCodeReloadAssembly(string sourceCode, string assemblyName, bool emitPdb = false, string documentPath = null, bool loadAssembly = true, bool embedPdb = false, string[] preprocessorSymbols = null) + { + var request = new CompilationRequest + { + // Null = the project's define set; the push path passes the player's defines. + PreprocessorSymbols = preprocessorSymbols, + SourceCode = sourceCode, + AssemblyName = assemblyName, + // Ensure Unity.Pipeline assemblies are included (contains CodeReloadOverrideMethodAttribute) + // Also include test assemblies for testing scenarios + AdditionalAssemblyPrefixes = new[] { "Unity.Pipeline", "Unity.Pipeline.Tests" }, + EmitDebugInformation = emitPdb, + EmbedDebugInformation = embedPdb, + DocumentPath = documentPath, + // The interpreter path runs the bytes directly; skip Assembly.Load (IL2CPP-unsafe). + SkipLoad = !loadAssembly, + // Interpreter-bound bytes only: the interpreter reaches non-public members via + // reflection. Loaded assemblies keep standard access checks — Mono JIT-enforces + // accessibility on Assembly.Load'd IL, so relaxing them would only trade a compile + // error for a throw at first dispatch (see AccessibilityValidator). + AllowNonPublicMemberAccess = !loadAssembly + }; + + return RoslynCompilationService.Compile(request); + } + + /// + /// Register the [CodeReloadOverrideMethod] methods of a compiled assembly with the registry. + /// Only overrides that actually bind are returned; overrides that were skipped (e.g. the + /// target is not a registered [CodeReload] method, or a signature mismatch) are reported via + /// with a user-facing reason. + /// + private static List RegisterCodeReloadMethods(Assembly assembly, string assemblyId, out List skipped) + { + var registeredMethods = new List(); + skipped = new List(); + + try + { + // Register assembly types for discovery + foreach (var type in assembly.GetTypes()) + { + CodeReloadRegistry.RegisterCodeReloadType(type, assemblyId); + + // Find methods with [CodeReloadOverrideMethod] attribute for overrides + var staticMethods = type.GetMethods(BindingFlags.Public | BindingFlags.Static); + + foreach (var method in staticMethods) + { + // Try multiple ways to find the attribute + var codeReloadAttr = method.GetCustomAttribute(); + if (codeReloadAttr == null) + { + // Try by name in case of type loading issues + var attrByName = method.GetCustomAttributes(true) + .FirstOrDefault(a => a.GetType().Name == "CodeReloadOverrideMethodAttribute"); + if (attrByName != null) + { + // Cast to the attribute type + codeReloadAttr = attrByName as CodeReloadOverrideMethodAttribute; + } + } + + if (codeReloadAttr != null) + { + if (CodeReloadRegistry.RegisterMethodOverride(method, codeReloadAttr, type, out var skipReason)) + { + registeredMethods.Add(codeReloadAttr.TargetMethodId); + } + else + { + skipped.Add($"{method.Name} -> {codeReloadAttr.TargetMethodId}: {skipReason}"); + } + } + } + } + + Debug.Log($"CodeReload: Registered {registeredMethods.Count} override methods: {string.Join(", ", registeredMethods)}"); + } + catch (Exception ex) + { + Debug.LogError($"CodeReload: Error registering methods from assembly {assemblyId}: {ex.Message}"); + Debug.LogError($"CodeReload: Stack trace: {ex.StackTrace}"); + } + + return registeredMethods; + } + + /// + /// Extract base filename from versioned filename (e.g., "PlayerMovement_001" -> "PlayerMovement"). + /// + private static string ExtractBaseFilename(string versionedFilename) + { + var lastUnderscoreIndex = versionedFilename.LastIndexOf('_'); + if (lastUnderscoreIndex > 0) + { + var potentialVersion = versionedFilename.Substring(lastUnderscoreIndex + 1); + if (int.TryParse(potentialVersion, out _)) + { + return versionedFilename.Substring(0, lastUnderscoreIndex); + } + } + return versionedFilename; + } + + /// + /// Extract version number from versioned filename (e.g., "PlayerMovement_001" -> 1). + /// + private static int ExtractVersion(string versionedFilename) + { + var lastUnderscoreIndex = versionedFilename.LastIndexOf('_'); + if (lastUnderscoreIndex > 0) + { + var potentialVersion = versionedFilename.Substring(lastUnderscoreIndex + 1); + if (int.TryParse(potentialVersion, out var version)) + { + return version; + } + } + return 0; + } + +#else + // Code reload requires Roslyn compilation, which is only available in the Editor and in + // Desktop development builds. In all other builds the methods below are compiled instead, + // matching the surface used by callers (CodeReloadCommands, InPlaceReloadProcessor) + // so the project still builds, and returning a clear "not supported" failure at runtime. + const string NotSupportedMessage = + "Code reload compilation is only supported on Desktop development builds (Windows/Mac/Linux)."; + + /// + /// Code reload source compilation (in-place editing) not supported on this build. + /// + /// Unused on this build. + /// Unused on this build. + /// Unused on this build. + /// Unused on this build. + /// Unused on this build. + /// Unused on this build. + /// A "Platform Not Supported" failure. + internal static CodeReloadCompileResult CompileSourceCodeOnMainThread(string sourceCode, string baseFileName, string assemblyDir = null, bool emitPdb = false, string documentPath = null, InterpreterOverrideSet interpreterMethods = null) + { + return CodeReloadCompileResult.Failure("Platform Not Supported", NotSupportedMessage); + } + + /// + /// Override compilation to bytes (push path) not supported on this build (no Roslyn). + /// + /// Unused on this build. + /// Unused on this build. + /// Always null on this build. + /// Always contains the "not supported" message on this build. + /// Unused on this build. + /// Unused on this build. + /// Always false on this build. + internal static bool TryCompileOverrideBytes(string transformedCode, string baseFileName, out byte[] ilBytes, out List diagnostics, string documentPath = null, string[] preprocessorSymbols = null) + { + ilBytes = null; + diagnostics = new List { NotSupportedMessage }; + return false; + } + + /// + /// Code reload cleanup not supported on this build. + /// + /// Unused on this build. + /// A failure result explaining code reload isn't supported on this build. + public static CodeReloadCleanupResult CleanupCodeReloadDlls(string assemblyDir = null) + { + return new CodeReloadCleanupResult + { + Success = false, + Message = NotSupportedMessage, + ExecutionTimeMs = 0 + }; + } +#endif + } + + /// + /// The override set an interpreter-backed compile registers instead of Assembly.Load: the + /// reloaded type plus its surviving method names. Passing one to + /// selects the interpreter path. + /// + internal class InterpreterOverrideSet + { + public string TypeName { get; set; } + public List MethodNames { get; set; } + } + + /// + /// Result from code reload compilation operation. + /// + class CodeReloadCompileResult + { + /// Whether compilation succeeded. + public bool IsSuccess { get; set; } + /// Name of the compiled code-reload assembly. + public string AssemblyName { get; set; } + /// Path the assembly was written to, if saved to disk. + public string OutputPath { get; set; } + /// Method ids registered as overrides. + public List RegisteredMethods { get; set; } = new List(); + /// How long compilation took, in milliseconds. + public long ExecutionTimeMs { get; set; } + /// Error message, if compilation failed. + public string Error { get; set; } + /// Additional error details for debugging. + public string ErrorDetails { get; set; } + /// Compiler diagnostics (errors/warnings), if any. + public List Diagnostics { get; set; } = new List(); + + /// Create a successful compile result. + /// Name of the compiled assembly. + /// Path the assembly was written to, if saved to disk. + /// Method ids registered as overrides. + /// How long compilation took, in milliseconds. + /// A successful result. + public static CodeReloadCompileResult Success(string assemblyName, string outputPath, List registeredMethods, long executionTimeMs) + { + return new CodeReloadCompileResult + { + IsSuccess = true, + AssemblyName = assemblyName, + OutputPath = outputPath, + RegisteredMethods = registeredMethods, + ExecutionTimeMs = executionTimeMs + }; + } + + /// Create a failed compile result. + /// Error message. + /// Additional error details for debugging. + /// How long compilation took, in milliseconds. + /// Compiler diagnostics (errors/warnings), if any. + /// A failed result. + public static CodeReloadCompileResult Failure(string error, string errorDetails, long executionTimeMs = 0, List diagnostics = null) + { + return new CodeReloadCompileResult + { + IsSuccess = false, + Error = error, + ErrorDetails = errorDetails, + ExecutionTimeMs = executionTimeMs, + Diagnostics = diagnostics ?? new List() + }; + } + } + + /// + /// Result from code reload cleanup operation. + /// + class CodeReloadCleanupResult + { + /// Whether cleanup succeeded. + public bool Success { get; set; } + /// Paths of the deleted files. + public List DeletedFiles { get; set; } = new List(); + /// Human-readable summary or error message. + public string Message { get; set; } + /// How long cleanup took, in milliseconds. + public long ExecutionTimeMs { get; set; } + } + +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/CodeReloadCompiler.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/CodeReloadCompiler.cs.meta new file mode 100644 index 0000000..5c30a10 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/CodeReloadCompiler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 29ede4b57fcc6c64b84e5f6ee75df373 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/EvalCodeCompiler.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/EvalCodeCompiler.cs new file mode 100644 index 0000000..ffb1094 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/EvalCodeCompiler.cs @@ -0,0 +1,335 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using Unity.Pipeline.Models; +using UnityEngine; + +namespace Unity.Pipeline.Compilation +{ + /// + /// C# code evaluation service using shared Roslyn compilation infrastructure. + /// Wraps user code in Execute() method, compiles, and executes with result serialization. + /// Supports both Editor and Runtime compilation for desktop development builds. + /// + static class EvalCodeCompiler + { +#if UNITY_EDITOR || (UNITY_STANDALONE && DEBUG) + + // Fixed lines in the generated source before user code begins + private const int BaseCodeLineOffset = 11; + + /// + /// Compile and execute code on Unity's main thread using Roslyn. + /// Eval is a MainThreadRequired command, so the server marshals the caller to the main + /// thread before invoking this; compilation + execution run synchronously here. + /// + /// The C# expression/statement(s) to evaluate. + /// Timeout for compilation, in milliseconds. + /// Running stopwatch used to report execution time in the response. + /// The evaluation result. + public static EvalResponse CompileAndExecuteOnMainThread(string code, int timeoutMs, System.Diagnostics.Stopwatch stopwatch) + { + if (stopwatch == null) + { + stopwatch = System.Diagnostics.Stopwatch.StartNew(); + } + + try + { + // Compile on current thread + var compilationResult = CompileCodeToAssembly(code, timeoutMs, stopwatch); + + if (!compilationResult.Success) + { + stopwatch.Stop(); + return EvalResponse.EvalFailure( + "Compilation Failed", + "Code compilation failed", + stopwatch.ElapsedMilliseconds, + compilationResult.Diagnostics); + } + + // Execute on current thread + var executionResult = ExecuteCompiledAssembly(compilationResult.Assembly); + + stopwatch.Stop(); + + if (executionResult.Success) + { + return EvalResponse.EvalSuccess( + executionResult.ReturnValue, + executionResult.Output, + stopwatch.ElapsedMilliseconds); + } + else + { + return EvalResponse.EvalFailure( + executionResult.Error, + executionResult.ErrorDetails, + stopwatch.ElapsedMilliseconds); + } + } + catch (Exception ex) + { + stopwatch.Stop(); + return EvalResponse.EvalFailure( + "Execution Failed", + ex.ToString(), + stopwatch.ElapsedMilliseconds); + } + } + + /// + /// Compile C# code to assembly using shared RoslynCompilationService. + /// Thread-safe and can run on background thread. + /// + private static CompilationResult CompileCodeToAssembly(string userCode, int timeoutMs, System.Diagnostics.Stopwatch stopwatch) + { + var id = Guid.NewGuid().ToString("N").Substring(0, 8); + + // Generate wrapper code + var sourceCode = BuildSourceCode(id, userCode, Application.isEditor); + + // Use shared compilation service + var request = new CompilationRequest + { + SourceCode = sourceCode, + AssemblyName = $"PipelineEval_{id}", + LineNumberOffset = BaseCodeLineOffset // Adjust diagnostics for wrapper code + }; + + var result = RoslynCompilationService.Compile(request); + + if (result.Success) + { + // Add execution context for eval-specific needs + return new CompilationResult + { + Success = true, + Assembly = result.Assembly, + ExecutionContext = new ExecutionContext + { + AssemblyId = id, + TypeName = $"PipelineEvaluation.PipelineEval_{id}", + MethodName = "Execute" + }, + Diagnostics = result.Diagnostics + }; + } + else + { + return new CompilationResult + { + Success = false, + Diagnostics = result.Diagnostics + }; + } + } + + /// + /// Generate C# source code wrapper for user code with conditional editor support. + /// + private static string BuildSourceCode(string id, string userCode, bool isEditorContext) + { + var editorUsing = isEditorContext ? "using UnityEditor;" : ""; + + return $@"using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +{editorUsing} + +namespace PipelineEvaluation +{{ + public static class PipelineEval_{id} + {{ + public static object Execute() + {{ + {userCode} + return null; + }} + }} +}}"; + } + + + /// + /// Execute compiled assembly and return result. + /// Must run on Unity's main thread for safe Unity API access. + /// + private static ExecutionResult ExecuteCompiledAssembly(Assembly assembly) + { + try + { + var executionContext = GetExecutionContextFromAssembly(assembly); + + var type = assembly.GetType(executionContext.TypeName); + var method = type?.GetMethod(executionContext.MethodName, BindingFlags.Public | BindingFlags.Static); + + if (type == null) + { + return new ExecutionResult + { + Success = false, + Error = "Assembly Load Error", + ErrorDetails = $"Could not find type {executionContext.TypeName} in compiled assembly" + }; + } + + if (method == null) + { + return new ExecutionResult + { + Success = false, + Error = "Method Not Found", + ErrorDetails = $"Could not find method {executionContext.MethodName} in compiled type" + }; + } + + var result = method.Invoke(null, null); + + return new ExecutionResult + { + Success = true, + ReturnValue = SerializeResult(result) + }; + } + catch (TargetInvocationException tie) when (tie.InnerException != null) + { + return new ExecutionResult + { + Success = false, + Error = "Runtime Error", + ErrorDetails = tie.InnerException.Message, + StackTrace = tie.InnerException.StackTrace + }; + } + catch (Exception ex) + { + return new ExecutionResult + { + Success = false, + Error = "Execution Error", + ErrorDetails = ex.Message, + StackTrace = ex.StackTrace + }; + } + } + + /// + /// Get execution context from compiled assembly. + /// + private static ExecutionContext GetExecutionContextFromAssembly(Assembly assembly) + { + // Find PipelineEvaluation types + var evalTypes = assembly.GetTypes() + .Where(t => t.Namespace == "PipelineEvaluation" && t.Name.StartsWith("PipelineEval_")) + .ToList(); + + if (evalTypes.Any()) + { + var evalType = evalTypes.First(); + return new ExecutionContext + { + TypeName = evalType.FullName, + MethodName = "Execute" + }; + } + + // Fallback + return new ExecutionContext + { + TypeName = "PipelineEvaluation.PipelineEval_Unknown", + MethodName = "Execute" + }; + } + + /// + /// Serialize result for JSON response. + /// + private static object SerializeResult(object value) + { + if (value == null) return null; + + // Handle primitive types directly + if (value is string || value is bool || value is int || value is long || value is float || value is double) + return value; + + // Handle Unity objects + if (value is UnityEngine.Object unityObj) + { + try + { + return Newtonsoft.Json.JsonConvert.DeserializeObject(UnityEngine.JsonUtility.ToJson(unityObj)); + } + catch + { + return value.ToString(); + } + } + + // Handle other objects via JSON serialization + try + { + return Newtonsoft.Json.JsonConvert.DeserializeObject( + Newtonsoft.Json.JsonConvert.SerializeObject(value)); + } + catch + { + return value.ToString(); + } + } + + /// + /// Result from compilation process. + /// + private class CompilationResult + { + public bool Success { get; set; } + public Assembly Assembly { get; set; } + public ExecutionContext ExecutionContext { get; set; } + public List Diagnostics { get; set; } = new List(); + } + + /// + /// Result from code execution. + /// + private class ExecutionResult + { + public bool Success { get; set; } + public object ReturnValue { get; set; } + public string Output { get; set; } + public string Error { get; set; } + public string ErrorDetails { get; set; } + public string StackTrace { get; set; } + } + + /// + /// Execution context for compiled assembly. + /// + private class ExecutionContext + { + public string AssemblyId { get; set; } + public string TypeName { get; set; } + public string MethodName { get; set; } + } + +#else + /// + /// Runtime compilation not supported on this platform. + /// Desktop development builds only (Windows/Mac/Linux). + /// + /// Unused on this build. + /// Unused on this build. + /// Unused on this build. + /// A failure result explaining runtime compilation isn't supported on this build. + public static EvalResponse CompileAndExecuteOnMainThread(string code, int timeoutMs, System.Diagnostics.Stopwatch stopwatch) + { + return EvalResponse.EvalFailure( + "Platform Not Supported", + "Runtime code compilation only supported on Desktop development builds"); + } +#endif + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/EvalCodeCompiler.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/EvalCodeCompiler.cs.meta new file mode 100644 index 0000000..09eebd0 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/EvalCodeCompiler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1ea6a44edd711194a968a40f1eb16f59 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/IlInterpreterHostBindings.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/IlInterpreterHostBindings.cs new file mode 100644 index 0000000..82e99c7 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/IlInterpreterHostBindings.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using UnityEngine; + +namespace Unity.Pipeline.Compilation +{ + /// + /// Shared IlInterpreter surface used by the + /// interpreter-backed code-reload path. Mirrors IlInterpreter's + /// UnityHostBinding.Prototyping() minus the Input System block, Audio, and physics — + /// anything outside UnityEngine's core module binds on demand via , + /// so the package forces no engine-module dependency. Reference types use AllowType<T>() + /// and blittable structs AllowTypeStruct<T>() for AOT/IL2CPP safety; static classes + /// and enums use AllowType(typeof(...)). + /// + static class IlInterpreterHostBindings + { +// Used by the interpreter-backed code-reload sink; available in dev players (incl. IL2CPP). +#if UNITY_EDITOR || DEVELOPMENT_BUILD || ENABLE_RUNTIME_PIPELINE + /// + /// Single source of truth for the interpreter's host surface: BCL + the standard UnityEngine + /// types + Debug. Every consumer — eval binding, code-reload binding, and the build-time + /// link.xml preservation set — is a projection of this one builder, so they cannot + /// drift. Callers overlay only what is site-specific: eval overlays capturing Debug.Log + /// variants; code reload overlays AllowType(targetType); link.xml reads + /// off the result. + /// + public static IlInterpreter.Interpreter.HostBinding CreateStandard() + { + // Route IlInterpreter registration warnings to the Unity console (the default sink is + // stderr, which Unity players never surface). + IlInterpreter.Interpreter.HostBinding.Warn = msg => Debug.LogWarning(msg); + + var binding = AddStandardUnity(new IlInterpreter.Interpreter.HostBinding().AllowBcl()) + .AllowType(typeof(Debug)); // logging from eval/reloaded bodies (eval overlays capture on top) + // Demand-time auto-bind: the interpreter resolves every TypeRef a loaded script carries + // through this policy, so engine/game types outside the curated surface bind on first use + // instead of throwing "not registered". The curated list above stays the fast-path core + // (typed delegates, flat structs) and the link.xml baseline — a floor, not a ceiling. + // Types the policy declines (see ResolveAutoBindType) are not bindable — the + // project-extension seam that could promote them was deferred to a future release. + binding.AutoBindResolver = ResolveAutoBindType; + return binding; + } + + /// + /// Auto-bind policy for : resolve a CLR full name from the loaded + /// assemblies, skipping (a) the BCL — the hand-rolled AllowBcl shims collapse doubles + /// into the script's float number space and must stay authoritative — and (b) this package's + /// own assemblies. On IL2CPP dev players this self-limits to types the stripper kept (see the + /// dev-build link.xml widening in CodeReloadLinkXmlGenerator). + /// + static Type ResolveAutoBindType(string fullName) + { + foreach (var asm in PipelineUtils.GetLoadedAssemblies()) + { + if (IsAutoBindSkippedAssembly(asm.GetName().Name ?? string.Empty)) continue; + Type t = null; + try { t = asm.GetType(fullName, throwOnError: false); } catch { } + if (t != null) return t; + } + return null; + } + + // Internal for tests: the classification itself is the contract (a misclassified game + // assembly silently loses auto-bind), and no test can load a real assembly by these names. + internal static bool IsAutoBindSkippedAssembly(string name) => + name == "System" || + name.StartsWith("System.", StringComparison.Ordinal) || + name.StartsWith("Microsoft.", StringComparison.Ordinal) || + name.StartsWith("Mono.", StringComparison.Ordinal) || + name == "mscorlib" || + name == "netstandard" || + name.StartsWith("nunit.", StringComparison.Ordinal) || + name.StartsWith("Unity.Pipeline", StringComparison.Ordinal); + + /// + /// Register the standard UnityEngine type surface onto (fluent). + /// Private: is the only supported way to build the surface, + /// closing the compose-it-yourself seam where per-site drift used to enter. + /// + static IlInterpreter.Interpreter.HostBinding AddStandardUnity(IlInterpreter.Interpreter.HostBinding binding) + { + return binding + .AllowType(typeof(Resources)) + .AllowType(typeof(PrimitiveType)) + // The base Object surface carries the fake-null operators (op_Equality, + // op_Implicit -> bool) every `target == null` / `if (component)` guard compiles + // against, plus Destroy/Instantiate/name. Explicit, not auto-bound: the guards + // must work on IL2CPP without relying on the on-demand resolver. + .AllowType() + .AllowType() + .AllowType() + .AllowType() + .AllowType() + .AllowType() + .AllowType() + .AllowType() + .AllowType() + .AllowType() + .AllowType() + .AllowType() + .AllowType(typeof(Shader)) // Shader.Find for material creation + .AllowType(typeof(CameraClearFlags)) // cam.clearFlags + .AllowType(typeof(TextAnchor)) // TextMesh.anchor + .AllowType(typeof(TextAlignment)) // TextMesh.alignment + .AllowType() + .AllowTypeStruct() + .AllowType() + .AllowType() + .AllowType(typeof(Mathf)) + .AllowType(typeof(Time)) + // 3D physics (Rigidbody, Collider, Physics, ForceMode, RaycastHit, ...) is NOT + // registered here: those types live in UnityEngine.PhysicsModule, and a compile-time + // reference would force a physics module dependency on every consumer. They bind on + // demand through AutoBindResolver instead — reflection-tier, and present in a player + // only when the game's own code kept the module alive. + .AllowType(typeof(Space)) + .AllowType() + .AllowType(typeof(LayerMask)) + .AllowType(typeof(Cursor)) + .AllowType(typeof(CursorLockMode)) + .AllowType(typeof(Screen)) + .AllowType(typeof(Rect)) + .AllowType(typeof(ScreenOrientation)) + .AllowType(typeof(Application)) + .AllowType(typeof(PlayerPrefs)) + .AllowType(typeof(Color32)) + .AllowType(typeof(System.Collections.IEnumerator)) + .AllowType(typeof(UnityEngine.Random)) + // UITK value-changed callbacks read evt.newValue/previousValue on ChangeEvent. + // Those are members on an OPEN generic type, which auto-bind can't resolve at Load + // (there's no closed instantiation to invoke against) — so reflect on the receiver's + // concrete type at call time. Covers Slider/Toggle/TextField/DropdownField/... the + // whole RegisterValueChangedCallback surface, without a compile-time UITK dependency. + .Allow("ChangeEvent`1", "get_newValue", + (recv, _) => recv?.GetType().GetProperty("newValue")?.GetValue(recv), 0) + .Allow("ChangeEvent`1", "get_previousValue", + (recv, _) => recv?.GetType().GetProperty("previousValue")?.GetValue(recv), 0) + // AllowType registers a type's methods/fields/props but not its constructors, so the + // common ctors are wired explicitly (Vector3's comes from AllowTypeStruct above). + .AllowConstructor("Vector2", + (_, args) => (object)new Vector2(Convert.ToSingle(args[0]), Convert.ToSingle(args[1])), 2) + .AllowConstructor("Color", + (_, args) => (object)new Color(Convert.ToSingle(args[0]), Convert.ToSingle(args[1]), Convert.ToSingle(args[2]), Convert.ToSingle(args[3])), 4) + .AllowConstructor("GameObject", (_, args) => (object)new GameObject(), 0) + .AllowConstructor("GameObject", (_, args) => (object)new GameObject((string)args[0]), 1) + .AllowConstructor("Material", (_, args) => (object)new Material((Shader)args[0]), 1); + } +#endif + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/IlInterpreterHostBindings.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/IlInterpreterHostBindings.cs.meta new file mode 100644 index 0000000..afb53b9 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/IlInterpreterHostBindings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fb251aef26c42704ca3d81d67fd13fc5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/InterpolationToFormatRewriter.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/InterpolationToFormatRewriter.cs new file mode 100644 index 0000000..af0f340 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/InterpolationToFormatRewriter.cs @@ -0,0 +1,84 @@ +using System.Collections.Generic; +using System.Text; +// The package bundles Roslyn renamed with a "UnityPipeline." prefix (Runtime/Plugins/CodeAnalysis); +// the dotnet test projects reference the same DLLs (IlInterpreter/BundledRoslyn.props). +using UnityPipeline.Microsoft.CodeAnalysis; +using UnityPipeline.Microsoft.CodeAnalysis.CSharp; +using UnityPipeline.Microsoft.CodeAnalysis.CSharp.Syntax; + +namespace Unity.Pipeline.Compilation +{ + /// + /// Rewrites C# string interpolation ($"...") into string.Format(fmt, args…) at the + /// source level: the interpreter can't run the compiler's normal interpolation lowering + /// (DefaultInterpolatedStringHandler, a ref struct), but it can call String.Format + /// (bound in ). Applied by + /// before an in-place reload body is compiled. + /// + /// Purely syntactic — no semantic model. Format specifiers, alignment, escaped braces, verbatim + /// strings and nested interpolation are handled. The one unserved case is an interpolation whose + /// target type is FormattableString/IFormattable: rewriting yields a string, + /// so that rare usage becomes a compile error rather than a silent wrong result. + /// + sealed class InterpolationToFormatRewriter : CSharpSyntaxRewriter + { + public override SyntaxNode VisitInterpolatedStringExpression(InterpolatedStringExpressionSyntax node) + { + var fmt = new StringBuilder(); + var args = new List(); + int index = 0; + + foreach (var content in node.Contents) + { + switch (content) + { + case InterpolatedStringTextSyntax text: + // ValueText decodes escapes (\t etc.) but leaves literal braces doubled + // ({{ / }}) — exactly the escaping a Format string wants, so append as-is. + fmt.Append(text.TextToken.ValueText); + break; + + case InterpolationSyntax interp: + fmt.Append('{').Append(index++); + if (interp.AlignmentClause != null) + fmt.Append(',').Append(interp.AlignmentClause.Value.ToString().Trim()); + if (interp.FormatClause != null) + fmt.Append(':').Append(interp.FormatClause.FormatStringToken.ValueText); + fmt.Append('}'); + // Visit the hole so nested interpolations rewrite bottom-up and later + // member-qualification passes see it. + args.Add(SyntaxFactory.Argument((ExpressionSyntax)Visit(interp.Expression))); + break; + } + } + + // No holes: emit a plain string literal (no Format, no brace doubling), matching how + // Roslyn treats a hole-less interpolated string. + if (index == 0) + { + var raw = new StringBuilder(); + foreach (var content in node.Contents) + if (content is InterpolatedStringTextSyntax t) + // A plain literal wants single braces, so undo the {{ / }} escaping ValueText keeps. + raw.Append(t.TextToken.ValueText.Replace("{{", "{").Replace("}}", "}")); + return SyntaxFactory.LiteralExpression( + SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(raw.ToString())) + .WithTriviaFrom(node); + } + + var allArgs = new List(args.Count + 1) + { + SyntaxFactory.Argument(SyntaxFactory.LiteralExpression( + SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(fmt.ToString()))), + }; + allArgs.AddRange(args); + + // Passing holes as loose args lets Roslyn pick the Format overload: fixed arity for ≤3, + // params object[] for ≥4 — both are bound on the interpreter side. + return SyntaxFactory.InvocationExpression( + SyntaxFactory.ParseExpression("string.Format"), + SyntaxFactory.ArgumentList(SyntaxFactory.SeparatedList(allArgs))) + .WithTriviaFrom(node); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/InterpolationToFormatRewriter.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/InterpolationToFormatRewriter.cs.meta new file mode 100644 index 0000000..5ac457d --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/InterpolationToFormatRewriter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d10aa4b9388057a4f96c43b0c41c35d1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/InterpreterCodeReloadExecutor.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/InterpreterCodeReloadExecutor.cs new file mode 100644 index 0000000..d9dce1b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/InterpreterCodeReloadExecutor.cs @@ -0,0 +1,314 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using Unity.Pipeline.CodeReload; +using IlInterpreter.Interpreter; + +namespace Unity.Pipeline.Compilation +{ + /// + /// IL2CPP-safe in-place code reload backend: instead of Assembly.Load + reflection, the + /// transformed override assembly bytes run in the IlInterpreter interpreter, and each override is + /// registered as an interpreter dispatch in . + /// + /// Override methods are static {ret} {Method}({TargetType} instance, ...), dispatched as + /// interpreter.Invoke("{Method}", instance, ...args). The host binding is the shared + /// standard surface plus the target type — public and non-public members (the override is + /// compiled with access checks disabled). Other referenced types bind on demand during Load via + /// the binding's AutoBindResolver. + /// + /// Inherits the interpreter's limits: constructs IlInterpreter doesn't lower yet throw at dispatch + /// time, and falls back to the original + /// compiled body for that call. Member refs unbound at Load are reported through the + /// warnings out param so the reload response shows the gap before play-mode execution hits it. + /// + static class InterpreterCodeReloadExecutor + { +// Editor and any development player (incl. IL2CPP on device): the interpreter runs pushed IL +// bytes without Assembly.Load or Roslyn. +#if UNITY_EDITOR || DEVELOPMENT_BUILD || ENABLE_RUNTIME_PIPELINE + + /// + /// Load into an interpreter and register an interpreter-backed + /// override for each entry on . + /// A name with no woven dispatch target (the method — or its whole type — was added since + /// the running build was compiled) cannot be dispatched from compiled code and is reported + /// through ; it still loads into the interpreter, so other + /// reloaded bodies in the same file can call it. + /// Returns the method ids that bound; carries + /// reasons for any that didn't; carries non-fatal load-time + /// diagnostics (host members that resolved to throwing stubs — the reload still applies, and + /// a stub only throws if its call site is reached). + /// + public static List Register( + byte[] assemblyBytes, string typeName, IEnumerable methodNames, + out List skipped, out List warnings) + { + var registered = new List(); + skipped = new List(); + warnings = new List(); + + var names = new List(methodNames ?? Array.Empty()); + if (assemblyBytes == null || names.Count == 0) + return registered; + + // All methods in one in-place file share the target type, but not every NAME resolves: + // a [CodeReload] method added since the last compile has no woven prologue to dispatch + // from, so its id is not in the registry. Resolve the type from the first name that is; + // the rest load but only intra-file calls reach them (reported below). A file whose type + // was never compiled resolves nothing — targetType stays null and the binding runs + // without the target-type overlay. + Type targetType = null; + var resolvable = new List(); + var unwovenNames = new List(); + foreach (var m in names) + { + if (CodeReloadRegistry.TryGetReloadableDeclaringType($"{typeName}.{m}", out var t)) + { + targetType = targetType ?? t; + resolvable.Add(m); + } + else + { + unwovenNames.Add(m); + } + } + + IlInterpreter.Interpreter.ScriptInterpreter interpreter; + try + { + // Standard shared surface plus the target type so the rewritten body can touch its + // own members, public and non-public. Every other type the override references is + // bound on demand by the Load pass via the binding's AutoBindResolver. + var binding = IlInterpreterHostBindings.CreateStandard(); + if (targetType != null) + binding = binding.AllowType(targetType) + .AllowNonPublicInstanceMembers(targetType); + + interpreter = new IlInterpreter.Interpreter.ScriptInterpreter( + binding, msg => Debug.Log(msg)); + // Lenient: a method that can't be lowered becomes a skipped stub (reported per method + // in the registration loop below) instead of failing the whole file's reload — so one + // bad method (e.g. SetupUI referencing a member missing on the running build) doesn't + // drop the other reloaded methods (UIUpdate) in the same file. + interpreter.Load(new OverrideScript(assemblyBytes), lenient: true); + } + catch (Exception ex) + { + // Lenient load no longer throws for per-method lowering failures, so this is a + // whole-assembly failure (parse error, cctor, a genuine crash). Anything but a + // ScriptValidationException carries an unactionable message ("Index was outside the + // bounds of the array") — name the type and put the full stack in the log. + var detail = ex is IlInterpreter.ScriptValidationException + ? ex.Message + : $"{ex.GetType().Name}: {ex.Message} (full stack in the editor log)"; + Debug.LogError($"CodeReload: interpreter load failed for '{typeName}': {ex}"); + foreach (var m in names) + skipped.Add($"{m}: interpreter load failed: {detail}"); + return registered; + } + + // These member refs resolved to throwing stubs. The reload still applies (a stub only + // throws if reached), but report the gap in the reload response rather than as a mid-play + // ScriptRuntimeException on whichever frame first hits it. + if (interpreter.UnboundHostMembers.Count > 0) + warnings.Add( + $"warning: {interpreter.UnboundHostMembers.Count} host member(s) referenced by the " + + $"reloaded code are not in the binding and will throw if reached: " + + $"{string.Join(", ", interpreter.UnboundHostMembers)}. Types outside the standard " + + "surface and demand-time auto-bind are not callable from interpreted code; " + + "BCL types beyond the shims are intentionally not auto-bound."); + + foreach (var methodName in resolvable) + { + var targetMethodId = $"{typeName}.{methodName}"; + var name = methodName; // capture per iteration + + // Skipped under lenient load — its body couldn't be lowered. Report the reason and + // move on rather than register a dispatcher that throws on first call. The most + // common cause across the editor→player boundary is a reference the running build + // lacks, so make that actionable. + if (interpreter.TryGetLoweringSkip(methodName, out var lowerSkip)) + { + if (lowerSkip.Contains("did not resolve to a host or script method")) + lowerSkip += " — the referenced member is neither an interpreted " + + "(reloaded/[CodeReload]) method nor a bound host member. If it was added " + + "since the running build was made, rebuild/redeploy the player to sync, " + + "or mark it [CodeReload]."; + skipped.Add($"{methodName}: interpreter load skipped this method: {lowerSkip}"); + continue; + } + + object Dispatch(object instance, object[] parameters) + { + // Override signature: static M(TargetType instance, ...originalArgs). Use typed + // Invoke overloads for the common arities to avoid a per-call object[] (args are + // already boxed by the woven prologue). Returns the interpreter's (boxed) result, + // which the woven prologue of a value-returning method unboxes; void methods + // return null, which that prologue ignores. + int n = parameters?.Length ?? 0; + switch (n) + { + case 0: return interpreter.Invoke(name, instance); + case 1: return interpreter.Invoke(name, instance, parameters[0]); + case 2: return interpreter.Invoke(name, instance, parameters[0], parameters[1]); + default: + var args = new object[1 + n]; + args[0] = instance; + Array.Copy(parameters, 0, args, 1, n); + return interpreter.Invoke(name, args); + } + } + + if (CodeReloadRegistry.RegisterInterpreterMethodOverride(targetMethodId, Dispatch, out var skipReason)) + registered.Add(targetMethodId); + else + skipped.Add($"{methodName} -> {targetMethodId}: {skipReason}"); + } + + // A method with no woven target has no compiled caller to dispatch from. It is still + // part of the loaded assembly, so other reloaded bodies in this file call it fine — + // report it so the reload response says why it isn't independently dispatchable. + foreach (var methodName in unwovenNames) + { + if (interpreter.TryGetLoweringSkip(methodName, out var lowerSkip)) + { + skipped.Add($"{methodName}: interpreter load skipped this method: {lowerSkip}"); + continue; + } + // An empty registry means discovery never ran (nothing entered Play Mode / no + // driver booted), not that this one method is new — say so instead of blaming the + // build. + if (!CodeReloadRegistry.HasReloadableMethods) + { + skipped.Add($"{methodName}: no [CodeReload] targets are registered in this session, so " + + "there is nothing to dispatch to. Targets are discovered when Play Mode starts " + + "(or a Player boots); enter Play Mode and save again."); + continue; + } + skipped.Add($"{methodName}: no woven dispatch target — the method (or its type) was " + + "added after the running build was compiled. Other reloaded [CodeReload] bodies in " + + "this file can call it; dispatching it on its own requires a rebuild."); + } + + return registered; + } + + /// + /// Push-time host-surface check: load the compiled override bytes into a throwaway + /// interpreter against the same binding a player builds on receipt, and return the member + /// refs that resolved to throwing stubs. Running the device's load pass in the editor turns + /// a mid-play ScriptRuntimeException into a synchronous diagnostic in the + /// reload_file_player_interpreter response (the device ack is async and carries only a warning + /// count). + /// + /// The editor's surface is a superset of a device player's (no IL2CPP stripping, and + /// editor-only assemblies resolve), so a clean result here is no guarantee — the player's + /// own load pass stays the backstop. The converse holds strictly: every member reported + /// here is a throwing stub on the player too. + /// + /// Non-fatal context when the check was degraded: the target type + /// could not be resolved (its non-public members may be reported as unbound), or the + /// interpreter load itself threw (the player's load will likely fail the same way). + public static List ValidateBindingSurface( + byte[] assemblyBytes, string typeName, IReadOnlyList methodNames, out string note) + { + note = null; + var unbound = new List(); + if (assemblyBytes == null || assemblyBytes.Length == 0) + return unbound; + + try + { + var binding = IlInterpreterHostBindings.CreateStandard(); + var targetType = ResolveTargetType(typeName, methodNames); + if (targetType != null) + binding.AllowType(targetType).AllowNonPublicInstanceMembers(targetType); + else + note = $"target type '{typeName}' not resolved in the editor — its own " + + "non-public members may show up as unbound"; + + using var interpreter = new IlInterpreter.Interpreter.ScriptInterpreter(binding, _ => { }); + // Lenient like the player's Register: a method that can't lower is skipped, not + // thrown, so the pre-check still reports the unbound members of the methods that DID + // lower instead of failing the whole validation on the first bad method. + interpreter.Load(new OverrideScript(assemblyBytes), lenient: true); + unbound.AddRange(interpreter.UnboundHostMembers); + } + catch (Exception ex) + { + note = $"interpreter load failed during validation: {ex.Message} — the player's " + + "load pass will likely fail the same way"; + } + return unbound; + } + + /// + /// Resolve the override's target type the way does (the code-reload + /// registry, only populated in play mode), falling back to a scan of the loaded user + /// assemblies for a unique short-name match (override extraction records short names). + /// Returns null when unknown or ambiguous; validation then runs without the target-type overlay. + /// + static Type ResolveTargetType(string typeName, IReadOnlyList methodNames) + { + if (methodNames != null && methodNames.Count > 0 && + CodeReloadRegistry.TryGetReloadableDeclaringType($"{typeName}.{methodNames[0]}", out var fromRegistry)) + return fromRegistry; + + // Skip engine/BCL assemblies ([CodeReload] target types live in user code); mirrors + // IlInterpreterHostBindings.IsAutoBindSkippedAssembly's classification intent. + Type unique = null; + foreach (var asm in PipelineUtils.GetLoadedAssemblies()) + { + var name = asm.GetName().Name ?? string.Empty; + if (name.StartsWith("Unity", StringComparison.Ordinal) || + name.StartsWith("System", StringComparison.Ordinal) || + name.StartsWith("Microsoft.", StringComparison.Ordinal) || + name.StartsWith("Mono.", StringComparison.Ordinal) || + name.StartsWith("mscorlib", StringComparison.Ordinal) || + name.StartsWith("netstandard", StringComparison.Ordinal) || + name.StartsWith("nunit.", StringComparison.Ordinal)) + continue; + + Type[] types; + try { types = asm.GetTypes(); } + catch (System.Reflection.ReflectionTypeLoadException ex) { types = ex.Types; } + catch { continue; } + + foreach (var t in types) + { + if (t == null || t.Name != typeName) continue; + if (unique != null && unique != t) return null; // ambiguous — skip the overlay + unique = t; + } + } + return unique; + } + + /// Minimal over the Roslyn-emitted override PE bytes. + private sealed class OverrideScript : IlInterpreter.IScript + { + public OverrideScript(byte[] bytes) { Il = bytes; } + public string Name => "PipelineCodeReload"; + public ReadOnlyMemory Il { get; } + } + +#else + public static List Register( + byte[] assemblyBytes, string typeName, IEnumerable methodNames, + out List skipped, out List warnings) + { + skipped = new List { "Interpreter code reload only supported on Desktop development builds" }; + warnings = new List(); + return new List(); + } + + public static List ValidateBindingSurface( + byte[] assemblyBytes, string typeName, IReadOnlyList methodNames, out string note) + { + note = "Binding validation only supported in the editor and Desktop development builds"; + return new List(); + } +#endif + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/InterpreterCodeReloadExecutor.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/InterpreterCodeReloadExecutor.cs.meta new file mode 100644 index 0000000..ad826bd --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/InterpreterCodeReloadExecutor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6cf557e8738ed1441a08144565d882d9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/RoslynCompilationService.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/RoslynCompilationService.cs new file mode 100644 index 0000000..7c806c6 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/RoslynCompilationService.cs @@ -0,0 +1,534 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using UnityPipeline.Microsoft.CodeAnalysis; +using UnityPipeline.Microsoft.CodeAnalysis.CSharp; +using UnityPipeline.Microsoft.CodeAnalysis.Emit; +using UnityPipeline.Microsoft.CodeAnalysis.Text; +using Unity.Pipeline.Models; +using UnityEngine; + +namespace Unity.Pipeline.Compilation +{ + /// + /// Shared Roslyn compilation service for both code evaluation and code reload systems. + /// Eliminates code duplication by providing common compilation infrastructure. + /// Thread-safe and can be called from any thread. + /// + static class RoslynCompilationService + { +#if UNITY_EDITOR || (UNITY_STANDALONE && DEBUG) + + /// + /// Compile source code to assembly with customizable options. + /// Thread-safe compilation that can run on any thread. + /// + /// The source and compilation options. + /// The compilation result. + public static CompilationResult Compile(CompilationRequest request) + { + try + { + // Parse syntax tree. When emitting debug info, the tree needs a document path and + // UTF-8 encoding so the portable PDB can reference a source document. Explicit + // symbols (e.g. run_script's `defines`) win; otherwise the project's define set + // applies so the source's #if regions match the running assemblies. + var emitDebug = request.EmitDebugInformation || request.EmbedDebugInformation; + var parseOptions = ProjectParseOptions(request.PreprocessorSymbols); + var syntaxTree = emitDebug + ? CSharpSyntaxTree.ParseText( + SourceText.From(request.SourceCode, Encoding.UTF8), + parseOptions, + path: request.DocumentPath ?? request.AssemblyName + ".cs") + : CSharpSyntaxTree.ParseText(request.SourceCode, parseOptions); + + // Get metadata references with optional additional prefixes + var references = GetMetadataReferences(request.AdditionalAssemblyPrefixes); + + // Create compilation. Disable optimizations when emitting debug info so the JIT + // keeps full sequence points (otherwise breakpoints can't bind). + var options = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary); + if (emitDebug) + options = options.WithOptimizationLevel(OptimizationLevel.Debug); + // Non-public member access needs two pieces: MetadataImportOptions.All (the default, + // Public, doesn't import non-public members of referenced assemblies at all — CS1061) + // and BinderFlags.IgnoreAccessibility (the compiler does not honor + // [assembly: IgnoresAccessChecksTo] — CS0122 otherwise). Interpreter-bound compiles + // only (see the property doc): the interpreter executes the result by reflection, + // which reaches non-public members. Unity's Mono JIT-enforces accessibility on + // Assembly.Load'd IL and ignores IgnoresAccessChecksTo too (verified on Mono 6.13) — + // see CodeReloadInPlaceTests.ReloadFileInPlace_PrivateFieldAccess_FailsValidationUpFront. + if (request.AllowNonPublicMemberAccess) + options = WithIgnoreAccessibility(options.WithMetadataImportOptions(MetadataImportOptions.All)); + + var compilation = CSharpCompilation.Create( + request.AssemblyName, + new[] { syntaxTree }, + references, + options); + + // Get diagnostics + var diagnostics = compilation.GetDiagnostics(); + var diagnosticInfos = ConvertDiagnostics(diagnostics, request.LineNumberOffset); + + // Check for compilation errors + var errors = diagnostics.Where(d => d.Severity == DiagnosticSeverity.Error).ToList(); + if (errors.Any()) + { + return new CompilationResult + { + Success = false, + Diagnostics = diagnosticInfos + }; + } + + // Compile to memory + using (var peStream = new MemoryStream()) + { + byte[] pdbBytes = null; + EmitResult emitResult; + + if (request.EmbedDebugInformation) + { + // Embed the portable PDB in the PE debug directory so the single byte[] + // pushed to a player carries its own sequence points; the IlInterpreter + // interpreter reads line info only from an embedded PDB. + emitResult = compilation.Emit( + peStream, + options: new EmitOptions(debugInformationFormat: DebugInformationFormat.Embedded)); + } + else if (request.EmitDebugInformation) + { + using (var pdbStream = new MemoryStream()) + { + emitResult = compilation.Emit( + peStream, + pdbStream, + options: new EmitOptions(debugInformationFormat: DebugInformationFormat.PortablePdb)); + + if (emitResult.Success) + pdbBytes = pdbStream.ToArray(); + } + } + else + { + emitResult = compilation.Emit(peStream); + } + + if (!emitResult.Success) + { + var emitDiagnostics = ConvertDiagnostics(emitResult.Diagnostics, request.LineNumberOffset); + return new CompilationResult + { + Success = false, + Diagnostics = diagnosticInfos.Concat(emitDiagnostics).ToList() + }; + } + + // Load assembly from memory. When symbols are present, load them alongside the + // assembly so an attached debugger can bind breakpoints into the emitted code. + // SkipLoad = emit-only (run_script's dry_run, and the interpreter path — see + // the property doc). + var assemblyBytes = peStream.ToArray(); + Assembly assembly = null; + if (!request.SkipLoad) + { + assembly = pdbBytes != null + ? PipelineUtils.LoadFromBytes(assemblyBytes, pdbBytes) + : PipelineUtils.LoadFromBytes(assemblyBytes); + } + + return new CompilationResult + { + Success = true, + Assembly = assembly, + AssemblyBytes = assemblyBytes, + PdbBytes = pdbBytes, + Diagnostics = diagnosticInfos + }; + } + } + catch (Exception ex) + { + return new CompilationResult + { + Success = false, + Diagnostics = new List + { + new DiagnosticInfo + { + Severity = "error", + Message = $"Compilation exception: {ex.Message}", + Line = 0, + Column = 0, + Id = "ROSLYN001" + } + } + }; + } + } + + /// + /// Async wrapper for compilation that runs on background thread. + /// Use when you need to avoid blocking the calling thread. + /// + /// The source and compilation options. + /// The compilation result. + public static Task CompileAsync(CompilationRequest request) + { + return Task.Run(() => Compile(request)); + } + + // MetadataReference cache keyed by assembly path. Reusing the same instances, both within one + // reload and across successive reloads, lets Roslyn cache each assembly's parsed metadata + // instead of re-reading all ~190 DLLs per compilation (~830 ms each). Static: cleared by + // domain reload, which is when the loaded-assembly set can change. + static readonly System.Collections.Concurrent.ConcurrentDictionary s_ReferenceCache = + new System.Collections.Concurrent.ConcurrentDictionary(); + + static MetadataReference GetCachedReference(string path) => + s_ReferenceCache.GetOrAdd(path, p => MetadataReference.CreateFromFile(p)); + + // The internal BinderFlags.IgnoreAccessibility is the only way to disable Roslyn's + // compile-time access checks (no public API; [IgnoresAccessChecksTo] is ignored, see Compile). + // Resolve the internal CSharpCompilationOptions.WithTopLevelBinderFlags(BinderFlags) once. + static bool s_BinderFlagResolved; + static MethodInfo s_WithTopLevelBinderFlags; + static object s_IgnoreAccessibilityFlag; + + static CSharpCompilationOptions WithIgnoreAccessibility(CSharpCompilationOptions options) + { + if (!s_BinderFlagResolved) + { + s_BinderFlagResolved = true; + try + { + var binderFlags = typeof(CSharpCompilationOptions).Assembly + .GetType(typeof(CSharpCompilationOptions).Namespace + ".BinderFlags"); + if (binderFlags != null) + { + s_IgnoreAccessibilityFlag = Enum.Parse(binderFlags, "IgnoreAccessibility"); + s_WithTopLevelBinderFlags = typeof(CSharpCompilationOptions).GetMethod( + "WithTopLevelBinderFlags", BindingFlags.NonPublic | BindingFlags.Instance); + } + } + catch (Exception ex) + { + Debug.LogWarning($"Pipeline: could not resolve IgnoreAccessibility binder flag; code-reload " + + $"overrides touching non-public members may fail to compile. {ex.Message}"); + } + } + + if (s_WithTopLevelBinderFlags != null && s_IgnoreAccessibilityFlag != null) + return (CSharpCompilationOptions)s_WithTopLevelBinderFlags.Invoke(options, new[] { s_IgnoreAccessibilityFlag }); + return options; + } + + /// + /// Get metadata references for compilation with optional additional assembly prefixes. + /// Handles both Editor and Runtime scenarios with appropriate filtering. Reference instances + /// are cached by path (see ) so repeated compilations are cheap. + /// + /// Extra assembly name prefixes to include as references. + /// The metadata references to compile against. + public static List GetMetadataReferences(string[] additionalPrefixes = null) + { + var references = new List(); + var assemblies = PipelineUtils.GetLoadedAssemblies() + .Where(a => !a.IsDynamic && !string.IsNullOrEmpty(PipelineUtils.GetLoadedAssemblyPath(a))); + + if (Application.isEditor) + { + // Editor: Include all loaded assemblies for maximum compatibility + foreach (var assembly in assemblies) + { + try + { + references.Add(GetCachedReference(PipelineUtils.GetLoadedAssemblyPath(assembly))); + } + catch + { + // Skip problematic assemblies + } + } + } + else + { + // Runtime: Use curated filtering for Unity + user assemblies + var allowedPrefixes = new List + { + "UnityEngine", + "Assembly-CSharp", + "netstandard", + "mscorlib", + "System.", + "Unity.Pipeline" + }; + + // Add any additional prefixes (e.g., for code reload: "UnityPipeline.Microsoft.CodeAnalysis") + if (additionalPrefixes != null) + { + allowedPrefixes.AddRange(additionalPrefixes); + } + + foreach (var assembly in assemblies) + { + try + { + var assemblyName = assembly.GetName().Name; + if (allowedPrefixes.Any(prefix => assemblyName.StartsWith(prefix))) + { + references.Add(GetCachedReference(PipelineUtils.GetLoadedAssemblyPath(assembly))); + } + } + catch + { + // Skip problematic assemblies + } + } + } + + return references; + } + + /// + /// Convert Roslyn diagnostics to DiagnosticInfo list with optional line number adjustment. + /// Handles line number offset for wrapped code scenarios. + /// + private static List ConvertDiagnostics(IEnumerable diagnostics, int lineOffset = 0) + { + var result = new List(); + + foreach (var diagnostic in diagnostics.Where(d => d.Severity >= DiagnosticSeverity.Warning)) + { + var location = diagnostic.Location.GetLineSpan(); + var line = Math.Max(0, location.StartLinePosition.Line - lineOffset); + var column = location.StartLinePosition.Character; + + var info = new DiagnosticInfo + { + Severity = diagnostic.Severity.ToString().ToLower(), + Message = diagnostic.GetMessage(), + Line = line, + Column = column, + Id = diagnostic.Id + }; + + // #line directives (code reload maps rewritten bodies back to the user's file) give + // the user a location they can open; the raw line text shows what was compiled. + var mapped = diagnostic.Location.GetMappedLineSpan(); + if (mapped.HasMappedPath) + { + info.File = mapped.Path; + info.FileLine = mapped.StartLinePosition.Line + 1; + } + var text = diagnostic.Location.SourceTree?.GetText(); + var rawLine = location.StartLinePosition.Line; + if (text != null && rawLine >= 0 && rawLine < text.Lines.Count) + info.Source = text.Lines[rawLine].ToString().Trim(); + + result.Add(info); + } + + return result; + } + +#else + /// + /// Runtime compilation not supported on this platform. + /// Desktop development builds only (Windows/Mac/Linux). + /// + /// Unused on this build. + /// A failure result explaining runtime compilation isn't supported on this build. + public static CompilationResult Compile(CompilationRequest request) + { + return new CompilationResult + { + Success = false, + Diagnostics = new List + { + new DiagnosticInfo + { + Severity = "error", + Message = "Runtime code compilation only supported on Desktop development builds", + Line = 0, + Column = 0, + Id = "PLATFORM001" + } + } + }; + } + + /// + /// Runtime compilation not supported on this platform. + /// + /// Unused on this build. + /// A completed task carrying a failure result. + public static Task CompileAsync(CompilationRequest request) + { + return Task.FromResult(Compile(request)); + } + + /// + /// Runtime compilation not supported on this platform. + /// + /// Unused on this build. + /// An empty list. + public static List GetMetadataReferences(string[] additionalPrefixes = null) + { + return new List(); + } +#endif + + // Preprocessor symbols the surrounding project was compiled with. Reload/eval sources must + // parse under the same defines as the assemblies they patch, or every #if UNITY_EDITOR / + // ENABLE_INPUT_SYSTEM / UNITY_STANDALONE region resolves to the wrong branch. The editor + // snapshots its live define set; a Mono dev player has no runtime API for it, so callers + // that care (the editor-side push path) pass explicit symbols. + // + // Kept outside the desktop-dev #if region: the parse sites that consume this + // (InPlaceReloadProcessor, SourceCodeTransformer) also compile on + // release standalone, where the region above is compiled out. + static string[] s_LastProjectDefines = Array.Empty(); + + static string[] ProjectDefines() + { +#if UNITY_EDITOR + // Editor API — main thread only. Off-thread callers reuse the last snapshot. + try { s_LastProjectDefines = UnityEditor.EditorUserBuildSettings.activeScriptCompilationDefines; } + catch { } +#endif + return s_LastProjectDefines; + } + + /// + /// Seed the define snapshot from the main thread. Called at editor load + /// (PipelineServerStartup's [InitializeOnLoad] ctor) so a background compile that runs + /// before any main-thread parse doesn't see an EMPTY define set — its #if UNITY_EDITOR / + /// UNITY_STANDALONE regions would resolve to the wrong branch. + /// + internal static void SnapshotProjectDefines() => ProjectDefines(); + + /// Parse options carrying , or the project's + /// define set (see ) when null. Every parse of user source in the + /// reload/eval pipeline should use this so #if regions match the running assemblies. + internal static CSharpParseOptions ProjectParseOptions(string[] preprocessorSymbols = null) + => CSharpParseOptions.Default.WithPreprocessorSymbols(preprocessorSymbols ?? ProjectDefines()); + } + + /// + /// Request for Roslyn compilation with customizable options. + /// + public class CompilationRequest + { + /// + /// Source code to compile. + /// + public string SourceCode { get; set; } + + /// + /// Name for the generated assembly (should be unique). + /// + public string AssemblyName { get; set; } + + /// + /// Additional assembly prefixes to include in metadata references. + /// Useful for code reload scenarios that need "UnityPipeline.Microsoft.CodeAnalysis" etc. + /// + public string[] AdditionalAssemblyPrefixes { get; set; } + + /// + /// Preprocessor symbols to parse with. Null = the project's define set + /// (), so #if regions in the source + /// resolve the same way they did when the running assemblies were compiled. The push-to-player + /// path passes the target player's defines explicitly, and run_script's + /// defines parameter arrives here too. + /// + internal string[] PreprocessorSymbols { get; set; } + + /// + /// Line number offset to subtract from diagnostic line numbers. + /// Used when source code has wrapper code that should be hidden from diagnostics. + /// + public int LineNumberOffset { get; set; } + + /// + /// When true, emit a portable PDB and load the assembly with its symbols so an attached + /// managed debugger can bind breakpoints. Compiles unoptimized. Default false (no symbols). + /// + public bool EmitDebugInformation { get; set; } + + /// + /// When true, emit the portable PDB inside the assembly itself (PE debug directory) instead + /// of as separate . Compiles unoptimized, like + /// . Use for the interpreter push path, which ships a single + /// byte[] to the player — the IlInterpreter interpreter resolves error line numbers only from an + /// embedded PDB. + /// + internal bool EmbedDebugInformation { get; set; } + + /// + /// Document path recorded in the syntax tree when or + /// is set. + /// Source that is not covered by explicit #line directives maps to this path. + /// + public string DocumentPath { get; set; } + + /// + /// When true, compile and collect diagnostics but do NOT load the emitted assembly into + /// the domain: stays null; + /// is still returned. Two callers need this: + /// compile-only paths such as run_script's dry_run (in-memory assemblies are + /// not unloadable under Mono, so loading would leak one per compile), and the IL2CPP-safe + /// interpreter path, which runs the raw bytes directly — Assembly.Load is + /// unavailable under IL2CPP. Default false — existing callers keep the load behavior. + /// + public bool SkipLoad { get; set; } + + /// + /// When true, referenced assemblies' non-public members are imported and access checks against them + /// are relaxed (). Interpreter-backend compiles only: the + /// interpreter executes the emitted IL via reflection, which reaches non-public members. Never set + /// this for IL that will be Assembly.Load'd — Mono JIT-enforces accessibility on loaded IL, + /// so the access would compile and then throw at first dispatch. Off by default. + /// + internal bool AllowNonPublicMemberAccess { get; set; } + } + + /// + /// Result from Roslyn compilation. + /// + public class CompilationResult + { + /// + /// Whether compilation was successful. + /// + public bool Success { get; set; } + + /// + /// Compiled assembly (only available if Success = true and + /// was not set). + /// + public Assembly Assembly { get; set; } + + /// + /// Raw assembly bytes (for potential disk saving or caching). + /// + public byte[] AssemblyBytes { get; set; } + + /// + /// Portable PDB bytes when was set; + /// null otherwise. + /// + public byte[] PdbBytes { get; set; } + + /// + /// Compilation diagnostics (errors, warnings, info). + /// + public List Diagnostics { get; set; } = new List(); + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/RoslynCompilationService.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/RoslynCompilationService.cs.meta new file mode 100644 index 0000000..b2ec11a --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Compilation/RoslynCompilationService.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 957feb25e68236e45b15cd5e9f095c31 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Console.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Console.meta new file mode 100644 index 0000000..7742891 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Console.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7c1f4a9e2b6d4c8f9a0e3d5b7c1a2f48 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Console/ConsoleLogBuffer.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Console/ConsoleLogBuffer.cs new file mode 100644 index 0000000..3c7b460 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Console/ConsoleLogBuffer.cs @@ -0,0 +1,427 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Newtonsoft.Json; +using Unity.Pipeline.Models; +using UnityEngine; + +namespace Unity.Pipeline.Console +{ + /// + /// Bounded, thread-safe ring buffer of captured Unity console entries that backs the + /// console command. + /// + /// Why thread-safe: entries arrive via , + /// which can fire from background threads, while the command reads the buffer from an HTTP + /// request thread. All access is guarded by a single lock. + /// + /// Each entry gets a monotonic that never repeats and only + /// increases — including across domain reloads, because the buffer (and the seq counter) is + /// persisted via /. The seq is the cursor a "--follow" + /// client uses to fetch only newer entries. + /// + class ConsoleLogBuffer + { + /// Maximum number of entries retained. Older entries are evicted first. + public const int Capacity = 2000; + + // Severity levels, ordered so a "minimum severity" filter is a simple >= comparison. + public const int SeverityLog = 0; + public const int SeverityWarn = 1; + public const int SeverityError = 2; + + public const string LevelLog = "log"; + public const string LevelWarn = "warn"; + public const string LevelError = "error"; + + readonly object m_Lock = new object(); + readonly Queue m_Entries = new Queue(); + long m_LastSeq; + string m_Session = Guid.NewGuid().ToString("N"); + + struct StoredEntry + { + public int Severity; + public ConsoleLogEntry Entry; + } + + /// + /// Identifies the capture session that values belong to. + /// Sequence numbers restart from zero with the process, so a cursor only names the same + /// entries within one session. In the Editor this is adopted from SessionState, which has + /// exactly the lifetime of one editor launch; in a player the constructor's value stands. + /// + public string Session + { + get { lock (m_Lock) { return m_Session; } } + } + + /// Adopt an externally owned session identifier. See the Editor bootstrap. + /// The identifier to report as . + public void SetSession(string session) + { + if (string.IsNullOrEmpty(session)) + return; + + lock (m_Lock) + m_Session = session; + } + + /// + /// Capture a console entry. Assigns the next sequence number and evicts the oldest entry if + /// the buffer is full. Safe to call from any thread. + /// + /// Unity log type; mapped to a severity via . + /// The log message. + /// The stack trace, if any. + /// UTC time the entry was captured. + /// + /// True when the entry was read from the Editor console's own store rather than captured + /// live, which makes the read time. + /// + public void Add(LogType type, string message, string stackTrace, DateTime timestampUtc, bool seeded = false) + { + var severity = SeverityFromLogType(type); + lock (m_Lock) + { + m_LastSeq++; + if (m_Entries.Count >= Capacity) + m_Entries.Dequeue(); + + m_Entries.Enqueue(new StoredEntry + { + Severity = severity, + Entry = new ConsoleLogEntry + { + Seq = m_LastSeq, + TimestampUtc = timestampUtc, + Level = LevelName(severity), + LogType = type.ToString(), + Message = message ?? string.Empty, + StackTrace = stackTrace ?? string.Empty, + Seeded = seeded + } + }); + } + } + + /// + /// Query the buffer for the console command. + /// + /// + /// Cursor: return only entries with Seq > since. Pass a negative value (e.g. -1) + /// for a snapshot of the most recent entries with no cursor filtering. + /// + /// + /// Maximum number of entries to return (the most recent matches). Values <= 0 mean "no + /// limit" (up to ). + /// + /// Minimum severity to include (see the Severity* constants). + /// + /// The that issued . When it names a different + /// session the cursor is refused; omit it and the cursor is taken at face value. + /// + /// The matching entries plus cursor/drop metadata for the console command. + public ConsoleLogResponse Query(long since, int tail, int minSeverity, string sinceSession = null) + { + lock (m_Lock) + { + // A cursor issued in another session, or one past the counter, cannot be honored: + // sequence numbers restart from zero with the process, so such a cursor filters out + // every entry held and reads as "nothing new". Ignore it, return the tail, and say so. + var reset = since > m_LastSeq + || (!string.IsNullOrEmpty(sinceSession) && sinceSession != m_Session); + if (reset) + since = -1; + + var counts = new ConsoleLevelCounts(); + var matches = new List(); + foreach (var stored in m_Entries) + { + // Counted before the level filter and the tail trim, so the counts describe + // what the buffer holds rather than what this call returned. + Tally(counts, stored.Severity); + + if (stored.Severity < minSeverity) + continue; + if (since >= 0 && stored.Entry.Seq <= since) + continue; + matches.Add(stored.Entry); + } + + // Keep only the most recent `tail` matches. + if (tail > 0 && matches.Count > tail) + matches.RemoveRange(0, matches.Count - tail); + + return new ConsoleLogResponse + { + Entries = matches.ToArray(), + Cursor = m_LastSeq, + Session = m_Session, + Returned = matches.Count, + Dropped = reset || ComputeDropped(since), + Reset = reset, + Counts = counts + }; + } + } + + /// + /// The buffer's counters without its entries: retained counts per severity, the cursor, and + /// the session that issued it. Backs console_status, which clients poll in a loop, so + /// it deliberately avoids materializing the entry list. + /// + /// A response with an empty . + public ConsoleLogResponse Stats() + { + lock (m_Lock) + { + var counts = new ConsoleLevelCounts(); + foreach (var stored in m_Entries) + Tally(counts, stored.Severity); + + return new ConsoleLogResponse + { + Entries = Array.Empty(), + Cursor = m_LastSeq, + Session = m_Session, + Counts = counts + }; + } + } + + /// + /// True when refers to entries that have already been evicted, so + /// the caller missed some output. Caller must hold . + /// + bool ComputeDropped(long since) + { + if (since < 0) + return false; + if (since >= m_LastSeq) + return false; + + // Everything after `since` was evicted (or never retained): buffer empty but seq moved on. + if (m_Entries.Count == 0) + return m_LastSeq > since; + + // The next entry the caller expects is since+1; if the oldest entry we still hold is + // newer than that, the gap in between was evicted. + var oldestSeq = m_Entries.Peek().Entry.Seq; + return oldestSeq > since + 1; + } + + /// Remove all entries. Does NOT reset the sequence counter (cursors stay monotonic). + public void Clear() + { + lock (m_Lock) + { + m_Entries.Clear(); + } + } + + /// Current number of retained entries. For diagnostics/tests. + public int Count + { + get { lock (m_Lock) { return m_Entries.Count; } } + } + + /// The highest sequence number assigned so far (the live cursor). + public long LastSeq + { + get { lock (m_Lock) { return m_LastSeq; } } + } + + /// + /// Raise the sequence counter to if it is behind. Never lowers it, so + /// a cursor already handed to a client can never be issued again for different entries. + /// + /// The floor the counter must be at or above. + public void RaiseLastSeq(long seq) + { + lock (m_Lock) + { + if (seq > m_LastSeq) + m_LastSeq = seq; + } + } + + #region Persistence + + [Serializable] + class Snapshot + { + [JsonProperty("lastSeq")] public long LastSeq; + [JsonProperty("entries")] public ConsoleLogEntry[] Entries; + } + + /// + /// Persist the buffer (entries + sequence counter) to so it survives + /// a domain reload. Failures are swallowed (logging is best-effort, never fatal). + /// + /// File to write the snapshot to. + public void Save(string path) + { + try + { + Snapshot snapshot; + lock (m_Lock) + { + var entries = new ConsoleLogEntry[m_Entries.Count]; + var i = 0; + foreach (var stored in m_Entries) + entries[i++] = stored.Entry; + snapshot = new Snapshot { LastSeq = m_LastSeq, Entries = entries }; + } + + var dir = Path.GetDirectoryName(path); + if (!string.IsNullOrEmpty(dir)) + Directory.CreateDirectory(dir); + File.WriteAllText(path, JsonConvert.SerializeObject(snapshot)); + } + catch (Exception ex) + { + Debug.LogWarning($"[Pipeline] Failed to persist console log buffer: {ex.Message}"); + } + } + + /// + /// Merge a buffer previously written by into this one. Missing or + /// unreadable files leave the buffer untouched. Returns true if a snapshot was loaded. + /// + /// File previously written by . + /// True if a snapshot was found and loaded. + public bool Load(string path) + { + try + { + if (!File.Exists(path)) + return false; + + var snapshot = JsonConvert.DeserializeObject(File.ReadAllText(path)); + if (snapshot == null) + return false; + + lock (m_Lock) + { + // Merge rather than replace. Where [NoAutoStaticsCleanup] keeps this buffer alive + // across a domain reload, entries logged since the snapshot are already here, and + // a snapshot entry whose seq the counter has already issued is one of those. + // Anything with a higher seq was never seen in memory, so it is newer than + // everything held and appends in order. + if (snapshot.Entries != null) + { + foreach (var entry in snapshot.Entries) + { + if (entry == null || entry.Seq <= m_LastSeq) + continue; + if (m_Entries.Count >= Capacity) + m_Entries.Dequeue(); + + m_Entries.Enqueue(new StoredEntry + { + Severity = SeverityFromLevelName(entry.Level), + Entry = entry + }); + m_LastSeq = entry.Seq; + } + } + + // Keep the counter ahead of the snapshot even when it held no entries, and never + // lower it: a cursor already handed out must not be issued a second time. + if (snapshot.LastSeq > m_LastSeq) + m_LastSeq = snapshot.LastSeq; + } + + return true; + } + catch (Exception ex) + { + Debug.LogWarning($"[Pipeline] Failed to restore console log buffer: {ex.Message}"); + return false; + } + } + + #endregion + + #region Severity mapping + + /// Map a Unity to an ordered severity. + /// The Unity log type. + /// One of the Severity* constants. + public static int SeverityFromLogType(LogType type) + { + switch (type) + { + case LogType.Warning: + return SeverityWarn; + case LogType.Error: + case LogType.Exception: + case LogType.Assert: + return SeverityError; + default: + return SeverityLog; + } + } + + /// + /// Parse a "--level" value ("log"/"warn"/"error", plus common aliases) into a minimum + /// severity. Unknown values fall back to (everything), matching the + /// lenient behavior of the existing log command. + /// + /// Level name to parse (case-insensitive). + /// One of the Severity* constants. + public static int SeverityFromLevelName(string level) + { + switch ((level ?? string.Empty).Trim().ToLowerInvariant()) + { + case "error": + case "err": + case "exception": + return SeverityError; + case "warn": + case "warning": + return SeverityWarn; + default: + return SeverityLog; + } + } + + /// Add one entry of to . + /// The tally to add to. + /// One of the Severity* constants. + static void Tally(ConsoleLevelCounts counts, int severity) + { + switch (severity) + { + case SeverityError: + counts.Error++; + break; + case SeverityWarn: + counts.Warn++; + break; + default: + counts.Log++; + break; + } + } + + /// The canonical level name for a severity. + /// One of the Severity* constants. + /// The matching Level* constant. + public static string LevelName(int severity) + { + switch (severity) + { + case SeverityError: + return LevelError; + case SeverityWarn: + return LevelWarn; + default: + return LevelLog; + } + } + + #endregion + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Console/ConsoleLogBuffer.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Console/ConsoleLogBuffer.cs.meta new file mode 100644 index 0000000..1a81c69 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Console/ConsoleLogBuffer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 1e014974635df5fe6a6787c4ba983f80 diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Console/ConsoleLogCapture.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Console/ConsoleLogCapture.cs new file mode 100644 index 0000000..5518f61 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Console/ConsoleLogCapture.cs @@ -0,0 +1,89 @@ +using System; +using System.Threading; +using Unity.Pipeline.Models; +using UnityEngine; +#if UNITY_6000_5_OR_NEWER +using Unity.Scripting.LifecycleManagement; +#endif + +namespace Unity.Pipeline.Console +{ + /// + /// Captures Unity console output into a process-wide so the + /// console command can serve it to CLI clients. This type lives in the runtime + /// assembly, so it ships in player builds as well as the Editor. + /// + /// Lifecycle: + /// - In a Player, the [RuntimeInitializeOnLoadMethod] hook starts capture as the app boots. + /// - In the Editor, the editor-only EditorConsoleCaptureBootstrap starts capture on every + /// domain reload and layers on persistence so entries survive reloads (e.g. after a recompile), + /// and re-arms on every play-mode transition (Unity clears + /// 's subscribers on play-mode exit even + /// though exiting play mode does not reload the domain — undocumented behavior, UUM-148802; + /// re-verify before retiring this). Both paths funnel through + /// , which is safe to call repeatedly: it always removes any + /// existing subscription before adding, so repeat calls (e.g. the runtime hook firing again + /// when Play mode is entered in the Editor) can never double-subscribe. + /// - is used (not the non-threaded variant) + /// so logs emitted from background threads are captured too. The buffer is thread-safe. + /// + /// Capture starts when this type first initializes. Console entries produced before that — or + /// before the package's first import — are not retroactively captured; this reads from the public + /// log callback, not Unity's internal console store. + /// +#if UNITY_6000_5_OR_NEWER + [NoAutoStaticsCleanup] +#endif + public static class ConsoleLogCapture + { + static readonly ConsoleLogBuffer s_Buffer = new ConsoleLogBuffer(); + static readonly object s_SubscriptionLock = new object(); + static ConsoleGroundTruth s_GroundTruth; + + /// The shared buffer holding captured console entries. + internal static ConsoleLogBuffer Buffer => s_Buffer; + + /// + /// The last Editor ground-truth sample, or null outside the Editor and before the first + /// sample. Written on the main thread by the Editor sampler and read from request threads, + /// so the console command can report it while staying off the main thread — which is the + /// point, since clients poll it while the Editor is busy compiling or importing. The + /// snapshot is immutable once published, so a reference swap is all the synchronization a + /// reader needs. + /// + internal static ConsoleGroundTruth GroundTruth + { + get => Volatile.Read(ref s_GroundTruth); + set => Volatile.Write(ref s_GroundTruth, value); + } + + /// + /// Player entry point. Runs as the application boots so console output is captured from the + /// start. In the Editor this also fires when entering Play mode, but + /// is idempotent so it does not double-subscribe. + /// + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] + static void RuntimeBootstrap() + { + EnsureCapturing(); + } + + /// + /// Subscribe to Unity's log callback, removing any existing subscription first. Safe to call + /// repeatedly and from either the runtime bootstrap or the Editor bootstrap. + /// + public static void EnsureCapturing() + { + lock (s_SubscriptionLock) + { + Application.logMessageReceivedThreaded -= OnLogMessage; + Application.logMessageReceivedThreaded += OnLogMessage; + } + } + + static void OnLogMessage(string condition, string stackTrace, LogType type) + { + s_Buffer.Add(type, condition, stackTrace, DateTime.UtcNow); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Console/ConsoleLogCapture.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Console/ConsoleLogCapture.cs.meta new file mode 100644 index 0000000..88136c4 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Console/ConsoleLogCapture.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 3d9b6e1a4f2c40a78c5e0b1d2a6f9c84 diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter.meta b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter.meta new file mode 100644 index 0000000..8f5c97d --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 128b6cd5b150eb54e940418250b3ebf1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/AssemblyInfo.cs b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/AssemblyInfo.cs new file mode 100644 index 0000000..b10f6de --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/AssemblyInfo.cs @@ -0,0 +1,17 @@ +using System.Runtime.CompilerServices; + +// The IlInterpreter VM is an implementation detail of eval/code reload, not a public scripting API: +// only the Script* exceptions are public (user code catches them from eval/reload failures). +// Everything else is internal, visible to the package +// assemblies that drive the VM and to the Unity test assemblies. The standalone dotnet suites +// (IlInterpreter/tests/IlInterpreter.*) compile these sources directly into their own assembly, so they need no +// grant here. +[assembly: InternalsVisibleTo("Unity.Pipeline")] +[assembly: InternalsVisibleTo("Unity.Pipeline.Editor")] +[assembly: InternalsVisibleTo("Unity.Pipeline.Tests.Editor")] +[assembly: InternalsVisibleTo("Unity.Pipeline.Tests.Runtime")] +// IlInterpreter/tests/IlInterpreter/IlInterpreter.csproj compiles these same sources (this file included) into a +// standalone IlInterpreter.dll so the fuzzer can instrument the VM in isolation; the fuzz and bench +// executables consume that DLL cross-assembly. +[assembly: InternalsVisibleTo("IlInterpreter.Fuzz")] +[assembly: InternalsVisibleTo("IlInterpreter.Bench")] diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/AssemblyInfo.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/AssemblyInfo.cs.meta new file mode 100644 index 0000000..cf67ea0 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/AssemblyInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 56c0e5c2691d76d46a9000322eec91dd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/HostBinding.cs b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/HostBinding.cs new file mode 100644 index 0000000..fbd8420 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/HostBinding.cs @@ -0,0 +1,3220 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; +// The package bundles System.Runtime.CompilerServices.Unsafe renamed with a "UnityPipeline." prefix (Runtime/Plugins/CodeAnalysis); +// the dotnet test projects reference the same DLLs (IlInterpreter/BundledRoslyn.props). +using Unsafe = UnityPipeline.System.Runtime.CompilerServices.Unsafe; + +namespace IlInterpreter.Interpreter +{ + +// Pre-built delegate invoked when a script calls a host method. +// receiver: the `this` object for instance methods, null for static. +// args: explicit parameters (not including receiver). +// return: return value, or null for void methods. +internal delegate object? HostCallDelegate(object? receiver, object?[] args); + +// Fast-path delegate: reads args directly from the IR dual frame, bypassing +// ArgBuf allocation and Entry.Invoke coercion. Populated by BuildTypedDelegates. +// recv: host receiver (null for static). +// num: the Vm's unmanaged numeric stack base; slot S is at (bp+S)*4. +// ref_: refStack (object?[]) — the shared call stack; slot S is at bp+S. +// ir: the uint[] instruction stream. +// argBase: index in ir where arg slot indices start. +// dstSlot: frame-relative slot to write result into (-1 for void returns). +// bp: base pointer — offset into num/ref_ for the current frame. +internal unsafe delegate void FastCallDelegate(object? recv, byte* num, object?[] ref_, SType[] slotT, uint[] ir, int argBase, int dstSlot, int bp); + +// Open-instance delegate shapes for VALUE-TYPE receivers: the CLR requires the first +// parameter of an open-instance delegate over a struct method to be `ref T`. These power +// the FastVtRecv closures (computed struct members like Vector3.magnitude/normalized). +internal delegate TR RefRecvFn(ref TRecv self); +internal delegate TR RefRecvFn1F(ref TRecv self, float a); +internal delegate TR RefRecvFn1I(ref TRecv self, int a); +internal delegate void RefRecvAct(ref TRecv self); +internal delegate void RefRecvAct1F(ref TRecv self, float a); +internal delegate void RefRecvAct1I(ref TRecv self, int a); +internal delegate void RefRecvAct2F(ref TRecv self, float a, float b); +internal delegate void RefRecvAct3F(ref TRecv self, float a, float b, float c); + +// Holds all registered host method, constructor, and field delegates. +// Use the fluent Allow*() API to register; acts as both binding and builder. +internal sealed unsafe class HostBinding +{ + // Diagnostic warning sink. IlInterpreter has no UnityEngine dependency (these sources also compile in + // the standalone dotnet test/fuzz builds), so warnings default to stderr; IlInterpreterHostBindings + // redirects this to Debug.LogWarning on the Unity side. + internal static Action Warn = msg => Console.Error.WriteLine(msg); + + internal sealed class Entry + { + // Always set by the Allow*/Register* construction sites; `= null!` marks that invariant. + public HostCallDelegate Delegate = null!; + public int ParamCount; // number of explicit params (not this) + public bool HasThis; + public ParameterInfo[]? Params; // set by AllowType; enables int→bool coercion for Mono + // Optional fast path built by BuildTypedDelegates; null = use Delegate path. + // When non-null, FastIsFlat tells the executor whether the closure writes its result + // to numFrame (true) or to refFrame (false). + public FastCallDelegate? Fast; + public bool FastIsFlat; + // When true, Fast handles a FLAT (Vt) receiver itself: it reads the receiver slot + // index from ir[argBase - 3] and takes the struct bytes in place from the numeric + // frame (mutations land directly — no box, no write-back). Without it the executor + // must drop to the boxing slow path for Vt receivers. + public bool FastVtRecv; + // Optional return-type override consulted by the lowerer when allocating the call_host dst slot. + // Default O = "unset, use Method.ReturnType (or O if Method is null too)". Set to R4 or I4 when + // the C# signature doesn't reflect the script-visible return type — e.g. AllowBcl's Math.Sqrt + // is C# (double)→double but the closure narrows to float, so AttachFlatFloat sets this to R4 + // so the lowerer picks an R4 slot and the closure can write flat bytes into it. + public SType FlatReturnSType; + // The Fast closure reads/writes WIDE (I8/R8) slots itself — the executor's wide-slot + // fast-path guard lets it through. Set by AttachFlatDouble. + public bool FastWideOk; + // Optional method/ctor info — used by the IR loader to resolve struct param/return types + // for the flat-struct (Vt) lowering path. Set by RegisterMethods / AllowConstructor when + // the underlying MethodBase is available; null for hand-rolled Allow* delegates. + public MethodBase? Method; + public Type? DeclaringType; + // S4 operator inlining: set by InspectAndMarkOperators when the operator's IL + // is verified as pure arithmetic. The lowerer synthesizes IR instead of call_host. + public bool IsInlineableOp; + // Verified trivial struct accessor: the getter/setter IL is exactly a single backing-field + // load/store (`ldarg.0; ldfld f; ret` / `ldarg.0; ldarg.1; stfld f; ret`). On a FLAT (Vt) + // receiver the lowerer emits ldfld_vt_*/stfld_vt_* at this byte offset instead of a host call. + // -1 = not a trivial accessor. Set by MarkTrivialAccessors for flat-registered structs. + public int AccessorOffset = -1; + public SType AccessorSt; + // Layout of the backing field's type when the accessor is STRUCT-typed (Bounds.center → + // Vector3): AccessorSt is Vt and the lowerer sizes the copy from this layout. + public StructLayout? AccessorVtLayout; + + public object? Invoke(object? receiver, object?[] args) + { + if (Params != null) CoerceArgs(args, Params); + var result = Delegate(receiver, args); + // Enum and sub-int32/unsigned returns box as their real type, which fails the `is int` + // checks in WrObj/RdI4 and reads 0 even though the lowerer types those slots I4 — + // normalize the whole integer family to a boxed int. These returns always take this + // slow path (Fast delegates are only built for exact int/float/bool shapes). + return result is Enum ? unchecked((int)Convert.ToInt64(result)) : NormalizeIntegralReturn(result); + } + } + + // Coerce VM-boxed args to the parameter types reflection requires: every I4-slot value + // (int, bool, byte, enum, …) arrives as a boxed int, but MethodBase.Invoke needs the real + // type. Shared by Entry.Invoke (single-overload entries, driven by Entry.Params) and the + // same-arity ctor dispatcher (which must coerce AFTER picking its overload). + internal static void CoerceArgs(object?[] args, ParameterInfo[] ps) + { + for (int i = 0; i < args.Length && i < ps.Length; i++) + { + var pt = ps[i].ParameterType; + if (pt == typeof(bool) && args[i] is int ib) args[i] = ib != 0; + else if (pt == typeof(char) && args[i] is int ic) args[i] = (char)ic; + else if (pt == typeof(byte) && args[i] is int i8) args[i] = (byte)i8; + else if (pt == typeof(sbyte) && args[i] is int si8) args[i] = (sbyte)si8; + else if (pt == typeof(short) && args[i] is int i16) args[i] = (short)i16; + else if (pt == typeof(ushort) && args[i] is int u16) args[i] = (ushort)u16; + else if (pt == typeof(uint) && args[i] is int u32) args[i] = unchecked((uint)u32); + // Native int (ELEMENT_TYPE_I) rides a numeric slot and arrives boxed as + // int/long; reflection Invoke has no implicit widening to IntPtr. + else if (pt == typeof(IntPtr)) + { + if (args[i] is long pl) args[i] = new IntPtr(pl); + else if (args[i] is int pi) args[i] = new IntPtr(pi); + } + else if (pt == typeof(UIntPtr)) + { + if (args[i] is long ul) args[i] = new UIntPtr(unchecked((ulong)ul)); + else if (args[i] is int ui) args[i] = new UIntPtr(unchecked((uint)ui)); + } + else if (pt.IsEnum && args[i] is int ie) args[i] = Enum.ToObject(pt, ie); + // Script-created reference-element arrays are object?[]-backed regardless of + // their IL element type, but reflection Invoke needs the runtime array type + // assignable to the declared parameter type (arrays only widen, string[] → + // object[]). Rebuild as the declared array type; SetValue casts/unboxes per + // element, so a genuinely wrong element still throws like C# would. + else if (pt.IsArray && pt != typeof(object[]) && args[i] is object?[] oa + && args[i]!.GetType() == typeof(object[])) + { + var typed = Array.CreateInstance(pt.GetElementType()!, oa.Length); + for (int j = 0; j < oa.Length; j++) typed.SetValue(oa[j], j); + args[i] = typed; + } + } + } + + // Box a sub-int32/unsigned integer value as a plain int (the lowerer types those slots I4), so + // RdI4/WrObj/ldfld_i4's `is int` checks see the value instead of reading 0. Leaves int, long, + // float, char, and reference types untouched. uint wraps like C# `(int)uintValue`. + internal static object? NormalizeIntegralReturn(object? v) => v switch + { + byte b => (int)b, + sbyte sb => (int)sb, + short s => (int)s, + ushort us => (int)us, + uint u => unchecked((int)u), + _ => v, + }; + + // Convert a VM I4-slot value (boxed int) back to a host field's real integer type for reflective + // SetValue — a raw boxed int throws when assigned to a byte/short/uint field. Unchecked, matching C#. + internal static object ToFieldIntegral(object? val, Type ft) + { + int iv = val is int i ? i : Convert.ToInt32(val); + if (ft == typeof(byte)) return (byte)iv; + if (ft == typeof(sbyte)) return (sbyte)iv; + if (ft == typeof(short)) return (short)iv; + if (ft == typeof(ushort)) return (ushort)iv; + if (ft == typeof(uint)) return unchecked((uint)iv); + return iv; + } + + internal sealed class FieldEntry + { + // Both delegates are always set at registration; `= null!` marks that invariant. + public Func Get = null!; + public Action Set = null!; + // "Type.field", for runtime error messages (null-target reads/writes). + public string? Name; + // When the declaring type is a flat-layout struct (registered via AllowTypeStruct), + // these record the field's byte offset and primitive SType (I4/R4/O) so the IR lowerer + // can emit direct ldfld_vt_* / stfld_vt_* ops bypassing the boxed Get/Set delegates. + // DeclaringStruct == null for non-flat-struct fields. + public StructLayout? DeclaringStruct; + public int ByteOffset; + public SType PrimitiveSt; + // Storage kind for I4-classified flat fields: 0 = full 4-byte cell, 1 = u1, 2 = i1, + // 3 = u2, 4 = i2. Sub-4 fields need widening loads / truncating stores in the VM. + public byte PrimitiveKind; + // Script-visible SType of the field, from its declared CLR type (enum → I4). The interpreter's + // field-token classifier prefers this over its signature-byte guess (which can't tell an enum + // 0x11 VALUETYPE from a struct, and so mis-typed enum fields as O — boxed — breaking `switch` + // and comparisons on them). Default O ("unclassified") falls back to the signature guess. + public SType FieldSt; + // Simple name of the field's declared CLR type. Lets the lowerer resolve the layout of a + // NESTED flat struct field (Pose.P where P is a Vec2) at lowering time — registration + // order-independent, unlike capturing the layout here. + public string? FieldTypeName; + } + + // Layout descriptor for a host value type registered via AllowTypeStruct(). + // Built lazily from reflection at registration time. + internal sealed class StructLayout + { + // All fields are set by AllowTypeStruct's registration path; `= null!` marks that invariant. + public Type Type = null!; + public int Size; // total byte size (Marshal.SizeOf) + public string TypeName = null!; // type's simple name, used by parser + // Per-field offsets, indexed by field name. Built from Marshal.OffsetOf. + public Dictionary Fields = null!; + // Storage kind for I4-classified sub-4-byte fields (absent = full 4-byte cell): + // 1 = u1, 2 = i1, 3 = u2, 4 = i2. Loads must widen and stores must truncate. + public Dictionary? FieldKinds; + // Boundary marshalling straight off the unmanaged frame — no managed staging buffer. + // Generic registrations implement these with Unsafe.ReadUnaligned/WriteUnaligned; + // the non-generic (Type-only) path uses a pinned-box memcpy (AOT-safe, no + // MakeGenericMethod). BoxFromPtr's box is the ONLY allocation on the boundary. + public BoxFromPtrDelegate BoxFromPtr = null!; + public CopyToPtrDelegate CopyToPtr = null!; + } + + // Allocates a boxed T and copies Size bytes from src into its payload. + internal unsafe delegate object BoxFromPtrDelegate(byte* src); + // Reads the payload bytes of a boxed T (must be of layout's type) into dst. + internal unsafe delegate void CopyToPtrDelegate(byte* dst, object boxed); + + readonly Dictionary _structLayouts = new(); + readonly Dictionary _structLayoutsByType = new(); + + readonly Dictionary _entries = new(); + readonly Dictionary _fields = new(); + readonly HashSet _registeredTypes = new(); + readonly HashSet _collisions = new(); + readonly Dictionary _byHandle = new(); + readonly Dictionary<(string, string), Type> _genericTypes = new(); + + // Demand-time auto-bind policy. Consulted by ScriptInterpreter.Load for every TypeRef the + // script carries: maps a CLR full name ("UnityEngine.AI.NavMeshPath"; nested types use '+', + // matching Assembly.GetType) to the Type to register, or null to decline — unknown name, or + // policy says skip (e.g. the BCL, whose hand-rolled AllowBcl shims collapse doubles into the + // script's float number space and must stay authoritative). Null resolver = strict allowlist: + // only explicitly Allow*'d members are callable. With a resolver installed the curated surface + // becomes the fast-path core rather than a capability boundary. + internal Func? AutoBindResolver { get; set; } + // Resolver results per full name, INCLUDING negative ones, so repeated Loads against the same + // binding don't rescan the AppDomain for every TypeRef of every reloaded script. + readonly Dictionary _autoBindCache = new(); + + // Open generic method defs (e.g. GameObject.AddComponent) captured at AllowType time. + // The loader instantiates these lazily when it sees a MethodSpec token. + // A (type, name, arity) key can hold several overloads (Object.Instantiate(T,Transform,bool) + // vs (T,Vector3,Quaternion)); the loader picks by matching the MemberRef signature. + readonly Dictionary<(string, string, int), List> _openGenericMethods = new(); + // Cache of closed-method instantiations so repeated reloads don't re-MakeGenericMethod. + readonly Dictionary<(IntPtr, string), MethodInfo> _closedCache = new(); + + // Frame base (bp) of the call currently invoking a Fast delegate. The interpreter sets this + // immediately before each Fast call so the arg readers below can translate an absolute stack + // slot (bp + relativeSlot, used to index numStack/refStack) back to the method-relative index + // that slotT (= LoweredMethod.SlotTypes, length FrameSize) uses. A Fast call reads all its args + // before invoking the host method (and doesn't re-enter the interpreter before doing so), so a + // thread-static is safe. Defaults to 0, which is correct for top-level (bp == 0) calls. + [ThreadStatic] internal static int FastFrameBase; + + // Register an instance method: "TypeName.MethodName/N" + public HostBinding Allow(string typeName, string methodName, + HostCallDelegate del, int paramCount, + ParameterInfo[]? ps = null, MethodBase? mi = null) + { + var entry = new Entry + { + Delegate = del, + ParamCount = paramCount, + HasThis = true, + Params = ps, + Method = mi, + DeclaringType = mi?.DeclaringType, + }; + var key = $"{typeName}.{methodName}/{paramCount}"; + if (_entries.ContainsKey(key)) _collisions.Add(key); + _entries[key] = entry; + if (mi != null) _byHandle[mi.MethodHandle.Value] = entry; + return this; + } + + public HostBinding AllowStatic(string typeName, string methodName, + HostCallDelegate del, int paramCount, + ParameterInfo[]? ps = null, MethodBase? mi = null) + { + var entry = new Entry + { + Delegate = del, + ParamCount = paramCount, + HasThis = false, + Params = ps, + Method = mi, + DeclaringType = mi?.DeclaringType, + }; + var key = $"{typeName}.{methodName}/{paramCount}"; + if (_entries.ContainsKey(key)) _collisions.Add(key); + _entries[key] = entry; + if (mi != null) _byHandle[mi.MethodHandle.Value] = entry; + return this; + } + + // Register a constructor (called via newobj). The delegate receives null as + // receiver and the constructor arguments; it must return the new instance. + public HostBinding AllowConstructor(string typeName, + HostCallDelegate del, int paramCount, + ParameterInfo[]? ps = null, + ConstructorInfo? ci = null) + { + _entries[$"{typeName}..ctor/{paramCount}"] = new Entry + { + Delegate = del, + ParamCount = paramCount, + HasThis = false, + Params = ps, + Method = ci, + DeclaringType = ci?.DeclaringType, + }; + return this; + } + + // Register a host FIELD from reflection, classifying its script SType from the CLR type and + // marshalling at the boundary so the interpreter sees a primitive, not a box: an enum reads/writes + // as its underlying int (a boxed enum in an O slot makes `switch`/`==` on it silently never match); + // a bool reads boxed (the VM's ldfld_i4 coerces bool→1/0) and writes from int→bool. + // `obj` is the instance (null for static). + void RegisterField(string typeName, FieldInfo fi) + => _fields[$"{typeName}.{fi.Name}"] = BuildFieldEntry(fi); + + // The marshalling core of RegisterField, reusable for fields the parser resolves lazily + // through a TypeSpec parent (e.g. ValueTuple`2.Item1) — those are token-keyed per closed + // instantiation and never enter _fields. + internal static FieldEntry BuildFieldEntry(FieldInfo fi) + { + var ft = fi.FieldType; + SType st = ft.IsEnum ? SType.I4 + : ft == typeof(float) ? SType.R4 + : (ft == typeof(int) || ft == typeof(uint) || ft == typeof(bool) + || ft == typeof(byte) || ft == typeof(sbyte) || ft == typeof(short) || ft == typeof(ushort)) + ? SType.I4 + : SType.O; + + Func get; + Action set; + if (ft.IsEnum) + { + // Read through the 64-bit underlying value and truncate (unchecked) to the I4 slot — matching + // C#'s `(int)someEnum`. `Convert.ToInt32` throws OverflowException for an enum whose value + // exceeds Int32 range (a `: long`/`: uint` enum), aborting the whole reload; truncation does not. + get = obj => unchecked((int)Convert.ToInt64(fi.GetValue(obj))); + set = (obj, val) => fi.SetValue(obj, Enum.ToObject(ft, val is int iv ? iv : Convert.ToInt32(val))); + } + else if (ft == typeof(bool)) + { + get = obj => fi.GetValue(obj); + set = (obj, val) => fi.SetValue(obj, val is int iv ? iv != 0 : val); + } + else if (st == SType.I4 && ft != typeof(int)) + { + // Sub-int32/unsigned field (byte/sbyte/short/ushort/uint): present it to the VM as a boxed int + // (reflection boxes it as its real type, which reads 0), and convert back on write (a boxed int + // can't be SetValue'd directly into a byte/short/uint field). + get = obj => NormalizeIntegralReturn(fi.GetValue(obj)); + set = (obj, val) => fi.SetValue(obj, ToFieldIntegral(val, ft)); + } + else + { + get = obj => fi.GetValue(obj); + set = (obj, val) => fi.SetValue(obj, val); + } + return new FieldEntry + { Get = get, Set = set, FieldSt = st, FieldTypeName = ft.Name, Name = $"{fi.DeclaringType?.Name}.{fi.Name}" }; + } + + // Register a minimal set of BCL methods that Roslyn emits calls to. + public HostBinding AllowBcl() + { + // Type — GetTypeFromHandle is an identity: ldtoken already pushed the Type directly + AllowStatic("Type", "GetTypeFromHandle", (_, args) => args[0], 1); + Allow("Type", "get_Name", (recv, _) => ((Type)recv!).Name, 0); + // `t1 == t2` on System.Type operands compiles to Type.op_Equality (Roslyn resolves the + // user-defined operator, not ceq), e.g. `a.GetType() == b.GetType()` in gameplay code. + AllowStatic("Type", "op_Equality", (_, a) => (a[0] as Type) == (a[1] as Type) ? 1 : 0, 2); + AllowStatic("Type", "op_Inequality", (_, a) => (a[0] as Type) != (a[1] as Type) ? 1 : 0, 2); + // `.Name` on a Type receiver usually resolves to the declaring property MemberInfo.Name, + // so Roslyn emits the MemberRef against MemberInfo, not Type — both keys are needed. + Allow("MemberInfo", "get_Name", (recv, _) => ((System.Reflection.MemberInfo)recv!).Name, 0); + + Allow("Object", "ToString", (recv, _) => recv?.ToString() ?? "", 0); + Allow("Object", "GetHashCode", (recv, _) => recv?.GetHashCode() ?? 0, 0); + + // IDisposable — Roslyn emits `constrained.; callvirt IDisposable.Dispose` in the finally of + // every foreach over a struct-enumerator collection (List, Dictionary, …). + Allow("IDisposable", "Dispose", (recv, _) => { (recv as IDisposable)?.Dispose(); return null; }, 0); + + // List — the workhorse gameplay collection. Its members arrive as MemberRefs on a + // TypeSpec parent, keyed by the open type's short name ("List`1"), and dispatch through + // the NON-generic collection interfaces so one shim serves every instantiation with no + // MakeGenericType (AOT/IL2CPP-safe). Element values stay boxed, matching the O-slot + // representation. `new List()` inside a reloaded body is NOT covered — a ctor shim + // can't know T; only members on existing instances are. + // Element values COERCE to the list's T: an enum (or char/byte/short/float-from-int) + // element arrives boxed as int off its I4 slot, and the boxed-int probe would silently + // miss every Contains/IndexOf/Remove on a List — same identity erasure as + // enum dictionary keys. + static object? ListElem(object recv, object? val) + { + var t = recv.GetType(); + if (t.IsGenericType && val is int iv) + { + var e = t.GetGenericArguments()[0]; + if (e.IsEnum) return Enum.ToObject(e, iv); + if (e == typeof(float)) return (float)iv; + if (e == typeof(char)) return (char)iv; + if (e == typeof(byte)) return (byte)iv; + if (e == typeof(short)) return (short)iv; + if (e == typeof(long)) return (long)iv; + } + return val; + } + Allow("List`1", "get_Item", (recv, a) => ((System.Collections.IList)recv!)[Convert.ToInt32(a[0])], 1); + Allow("List`1", "set_Item", (recv, a) => { ((System.Collections.IList)recv!)[Convert.ToInt32(a[0])] = ListElem(recv!, a[1]); return null; }, 2); + Allow("List`1", "get_Count", (recv, _) => ((System.Collections.ICollection)recv!).Count, 0); + Allow("List`1", "Add", (recv, a) => { ((System.Collections.IList)recv!).Add(ListElem(recv!, a[0])); return null; }, 1); + Allow("List`1", "Insert", (recv, a) => { ((System.Collections.IList)recv!).Insert(Convert.ToInt32(a[0]), ListElem(recv!, a[1])); return null; }, 2); + Allow("List`1", "RemoveAt", (recv, a) => { ((System.Collections.IList)recv!).RemoveAt(Convert.ToInt32(a[0])); return null; }, 1); + Allow("List`1", "Clear", (recv, _) => { ((System.Collections.IList)recv!).Clear(); return null; }, 0); + Allow("List`1", "Contains", (recv, a) => ((System.Collections.IList)recv!).Contains(ListElem(recv!, a[0])) ? 1 : 0, 1); + Allow("List`1", "IndexOf", (recv, a) => ((System.Collections.IList)recv!).IndexOf(ListElem(recv!, a[0])), 1); + Allow("List`1", "Remove", (recv, a) => + { + var l = (System.Collections.IList)recv!; + var v = ListElem(recv!, a[0]); + if (!l.Contains(v)) return 0; + l.Remove(v); + return 1; + }, 1); + // HashSet — the visited-set staple. No non-generic interface carries Contains/Add, + // so reflection dispatch on the closed type, with the same element coercion. + Allow("HashSet`1", "Contains", (recv, a) => (bool)recv!.GetType().GetMethod("Contains")!.Invoke(recv, new[] { ListElem(recv!, a[0]) })! ? 1 : 0, 1); + Allow("HashSet`1", "Add", (recv, a) => (bool)recv!.GetType().GetMethod("Add")!.Invoke(recv, new[] { ListElem(recv!, a[0]) })! ? 1 : 0, 1); + Allow("HashSet`1", "Remove", (recv, a) => (bool)recv!.GetType().GetMethod("Remove", new[] { recv.GetType().GetGenericArguments()[0] })!.Invoke(recv, new[] { ListElem(recv!, a[0]) })! ? 1 : 0, 1); + Allow("HashSet`1", "Clear", (recv, _) => { recv!.GetType().GetMethod("Clear")!.Invoke(recv, null); return null; }, 0); + Allow("HashSet`1", "UnionWith", (recv, a) => { recv!.GetType().GetMethod("UnionWith")!.Invoke(recv, new[] { a[0] }); return null; }, 1); + Allow("HashSet`1", "ExceptWith", (recv, a) => { recv!.GetType().GetMethod("ExceptWith")!.Invoke(recv, new[] { a[0] }); return null; }, 1); + Allow("HashSet`1", "IntersectWith", (recv, a) => { recv!.GetType().GetMethod("IntersectWith")!.Invoke(recv, new[] { a[0] }); return null; }, 1); + Allow("HashSet`1", "get_Count", (recv, _) => recv!.GetType().GetProperty("Count")!.GetValue(recv), 0); + Allow("HashSet`1", "GetEnumerator", (recv, _) => ((System.Collections.IEnumerable)recv!).GetEnumerator(), 0); + // foreach support: IEnumerable.GetEnumerator boxes List.Enumerator (a struct), and the + // loop's MoveNext/get_Current calls — MemberRefs on the nested "Enumerator" TypeSpec — + // dispatch on that box via IEnumerator, mutating it in place. Dispose is normally reached + // through the constrained IDisposable shim above; registered here too for direct calls. + // The "Enumerator" key is shared by every BCL struct enumerator (Dictionary, HashSet, …), + // and the IEnumerator dispatch is correct for all of them. + Allow("List`1", "GetEnumerator", (recv, _) => ((System.Collections.IEnumerable)recv!).GetEnumerator(), 0); + Allow("Enumerator", "MoveNext", (recv, _) => ((System.Collections.IEnumerator)recv!).MoveNext() ? 1 : 0, 0); + Allow("Enumerator", "get_Current", (recv, _) => ((System.Collections.IEnumerator)recv!).Current, 0); + Allow("Enumerator", "Dispose", (recv, _) => { (recv as IDisposable)?.Dispose(); return null; }, 0); + // foreach over a value typed as the INTERFACE IEnumerable (not the concrete List etc.) + // — or explicit IEnumerator use in a reloaded coroutine — dispatches through the generic + // interface members, which are distinct TypeSpec MemberRefs from the "Enumerator" struct + // above and from the non-generic IEnumerator. get_Current returns T via the non-generic + // IEnumerator.Current; the same boxed-object dispatch is correct for every instantiation. + Allow("IEnumerable`1", "GetEnumerator", (recv, _) => ((System.Collections.IEnumerable)recv!).GetEnumerator(), 0); + Allow("IEnumerator`1", "MoveNext", (recv, _) => ((System.Collections.IEnumerator)recv!).MoveNext() ? 1 : 0, 0); + Allow("IEnumerator`1", "get_Current", (recv, _) => ((System.Collections.IEnumerator)recv!).Current, 0); + Allow("IEnumerator`1", "Dispose", (recv, _) => { (recv as IDisposable)?.Dispose(); return null; }, 0); + + // Dictionary — the other workhorse (inventories, lookups, pools). Same non-generic + // dispatch strategy as List`1: one shim per member serves every instantiation, AOT-safe, + // values stay boxed. `new Dictionary()` in a reloaded body is NOT covered (no T at + // shim time) — instances come from the host. Keys are COERCED to the dictionary's TKey: + // an enum key arrives boxed as int (the I4 slot erased its identity), and the boxed-int + // probe would silently miss every entry of a Dictionary (found by probing — + // reads returned zero while writes coerced through the IDictionary cast). + static object DictKey(object recv, object? key) + { + var t = recv.GetType(); + if (t.IsGenericType && key is int ik) + { + var k = t.GetGenericArguments()[0]; + if (k.IsEnum) return Enum.ToObject(k, ik); + if (k == typeof(char)) return (char)ik; + if (k == typeof(byte)) return (byte)ik; + if (k == typeof(short)) return (short)ik; + if (k == typeof(long)) return (long)ik; + } + return key!; + } + Allow("Dictionary`2", "get_Item", (recv, a) => + { + var d = (System.Collections.IDictionary)recv!; + var key = DictKey(recv!, a[0]); + // The non-generic indexer returns null on a miss; C# throws. Fault parity matters — + // a silent null reads as 0 through an I4 slot. + if (!d.Contains(key)) throw new KeyNotFoundException($"The given key '{key}' was not present in the dictionary."); + return d[key]; + }, 1); + Allow("Dictionary`2", "set_Item", (recv, a) => { ((System.Collections.IDictionary)recv!)[DictKey(recv!, a[0])] = a[1]; return null; }, 2); + Allow("Dictionary`2", "get_Count", (recv, _) => ((System.Collections.ICollection)recv!).Count, 0); + Allow("Dictionary`2", "Add", (recv, a) => { ((System.Collections.IDictionary)recv!).Add(DictKey(recv!, a[0]), a[1]); return null; }, 2); + Allow("Dictionary`2", "ContainsKey", (recv, a) => ((System.Collections.IDictionary)recv!).Contains(DictKey(recv!, a[0])) ? 1 : 0, 1); + Allow("Dictionary`2", "Remove", (recv, a) => + { + var d = (System.Collections.IDictionary)recv!; + var key = DictKey(recv!, a[0]); + if (!d.Contains(key)) return 0; + d.Remove(key); + return 1; + }, 1); + // TryGetValue writes the out slot through the byref write-back path (the shim mutates + // a[1] in place, exactly like reflection does for a MethodInfo out param). The lowerer + // detects byref from Entry.Params, which hand shims don't have — borrow the parameter + // shape from a marker method so the call site takes the write-back path. + Allow("Dictionary`2", "TryGetValue", (recv, a) => + { + var d = (System.Collections.IDictionary)recv!; + var key = DictKey(recv!, a[0]); + if (d.Contains(key)) { a[1] = d[key]; return 1; } + a[1] = null; // value-typed outs read the null as their zero (CoerceBoxed*) + return 0; + }, 2, typeof(HostBinding).GetMethod(nameof(TryGetValueShape), + BindingFlags.NonPublic | BindingFlags.Static)!.GetParameters()); + // foreach: boxed struct enumerator via IEnumerable (yields boxed KeyValuePair); + // MoveNext/Current ride the shared "Enumerator" shims above. Key/Value dispatch by + // reflection over the closed instantiation — cheap relative to a loop body. + Allow("Dictionary`2", "GetEnumerator", (recv, _) => ((System.Collections.IEnumerable)recv!).GetEnumerator(), 0); + Allow("KeyValuePair`2", "get_Key", (recv, _) => recv!.GetType().GetProperty("Key")!.GetValue(recv), 0); + Allow("KeyValuePair`2", "get_Value", (recv, _) => recv!.GetType().GetProperty("Value")!.GetValue(recv), 0); + // foreach (var (k, v) in dict) — Roslyn calls KeyValuePair.Deconstruct(out, out). + Allow("KeyValuePair`2", "Deconstruct", (recv, a) => + { + var t = recv!.GetType(); + a[0] = t.GetProperty("Key")!.GetValue(recv); + a[1] = t.GetProperty("Value")!.GetValue(recv); + return null; + }, 2, typeof(HostBinding).GetMethod(nameof(DeconstructShape), + BindingFlags.NonPublic | BindingFlags.Static)!.GetParameters()); + // foreach over dict.Keys / dict.Values: the collections come back by reflection (real + // KeyCollection/ValueCollection instances) and their struct enumerators ride the shared + // "Enumerator" shims; GetEnumerator dispatches via IEnumerable like every other one. + Allow("Dictionary`2", "get_Keys", (recv, _) => recv!.GetType().GetProperty("Keys")!.GetValue(recv), 0); + Allow("Dictionary`2", "get_Values", (recv, _) => recv!.GetType().GetProperty("Values")!.GetValue(recv), 0); + Allow("KeyCollection", "GetEnumerator", (recv, _) => ((System.Collections.IEnumerable)recv!).GetEnumerator(), 0); + Allow("ValueCollection", "GetEnumerator", (recv, _) => ((System.Collections.IEnumerable)recv!).GetEnumerator(), 0); + Allow("KeyCollection", "get_Count", (recv, _) => ((System.Collections.ICollection)recv!).Count, 0); + Allow("ValueCollection", "get_Count", (recv, _) => ((System.Collections.ICollection)recv!).Count, 0); + + // Delegate invocation — System.Action/Func fields fire from gameplay code (event-style + // callbacks like `CurrentSegementChanged.Invoke(seg)`). They're BCL TypeSpec MemberRefs the + // auto-bind policy skips, so shim per arity via DynamicInvoke; bool results follow the + // 1/0-int convention. User-declared delegate types resolve via their own auto-bound type. + static object? CoerceDelegateResult(object? r) => r is bool b ? (b ? 1 : 0) : r; + // Coerce against the delegate's OWN Invoke signature before DynamicInvoke: a char/bool + // argument arrives boxed as int (it rides an I4 slot), and DynamicInvoke's binder refuses + // Int32 → Char. Direct host calls get the same treatment from Entry.Params; these + // string-keyed shims have no static ParameterInfo, so resolve it from the instance. + static object? InvokeDelegate(object? recv, object?[] a) + { + var d = (Delegate)recv!; + if (a.Length > 0) + CoerceArgs(a, d.GetType().GetMethod("Invoke")!.GetParameters()); + return d.DynamicInvoke(a); + } + Allow("Action", "Invoke", (recv, _) => ((Delegate)recv!).DynamicInvoke(), 0); + Allow("Action`1", "Invoke", (recv, a) => InvokeDelegate(recv, a), 1); + Allow("Action`2", "Invoke", (recv, a) => InvokeDelegate(recv, a), 2); + Allow("Action`3", "Invoke", (recv, a) => InvokeDelegate(recv, a), 3); + Allow("Action`4", "Invoke", (recv, a) => InvokeDelegate(recv, a), 4); + Allow("Func`1", "Invoke", (recv, _) => CoerceDelegateResult(((Delegate)recv!).DynamicInvoke()), 0); + Allow("Func`2", "Invoke", (recv, a) => CoerceDelegateResult(InvokeDelegate(recv, a)), 1); + Allow("Func`3", "Invoke", (recv, a) => CoerceDelegateResult(InvokeDelegate(recv, a)), 2); + Allow("Func`4", "Invoke", (recv, a) => CoerceDelegateResult(InvokeDelegate(recv, a)), 3); + // 4 args — the ScriptDelegateAdapter's arity ceiling; the invoke surface matches it. + Allow("Func`5", "Invoke", (recv, a) => CoerceDelegateResult(InvokeDelegate(recv, a)), 4); + // Combining delegate VALUES (`a += b` on an Action local/field) compiles to + // Delegate.Combine/Remove + castclass. Null-tolerant like the BCL originals. + AllowStatic("Delegate", "Combine", (_, a) => Delegate.Combine((Delegate?)a[0], (Delegate?)a[1]), 2); + AllowStatic("Delegate", "Remove", (_, a) => Delegate.Remove((Delegate?)a[0], (Delegate?)a[1]), 2); + // `a == b` on delegates binds op_Equality — on MulticastDelegate for Action/Func, on + // Delegate for the base type. Value equality (same target + method), like the BCL. + AllowStatic("Delegate", "op_Equality", (_, a) => Equals(a[0], a[1]) ? 1 : 0, 2); + AllowStatic("Delegate", "op_Inequality", (_, a) => Equals(a[0], a[1]) ? 0 : 1, 2); + AllowStatic("MulticastDelegate", "op_Equality", (_, a) => Equals(a[0], a[1]) ? 1 : 0, 2); + AllowStatic("MulticastDelegate", "op_Inequality", (_, a) => Equals(a[0], a[1]) ? 0 : 1, 2); + AllowStatic("Object", "Equals", (_, a) => Equals(a[0], a[1]) ? 1 : 0, 2); + + // 5+ string concatenations: Roslyn lowers `a + b + c + d + e` to String.Concat(new object[] {...}). + AllowStatic("String", "Concat", (_, a) => + { + if (a[0] is object?[] objs) return string.Concat(objs); + if (a[0] is string[] strs) return string.Concat(strs); + return a[0]?.ToString() ?? ""; + }, 1); + AllowStatic("String", "Concat", (_, a) => string.Concat(a[0]?.ToString(), a[1]?.ToString()), 2); + AllowStatic("String", "Concat", (_, a) => string.Concat(a[0]?.ToString(), a[1]?.ToString(), a[2]?.ToString()), 3); + AllowStatic("String", "Concat", (_, a) => string.Concat(a[0]?.ToString(), a[1]?.ToString(), a[2]?.ToString(), a[3]?.ToString()), 4); + // String.Format — the target of the interpolation rewrite (InterpolationToFormatRewriter). + // Arity 2 serves BOTH Format(string, object) [1 hole] and Format(string, params object[]) [4+ + // holes, Roslyn passes a constructed object[]] — they share the same 2-arg dispatch key, so the + // delegate branches on whether the second arg is an object[]. Culture is default (CurrentCulture), + // matching C# interpolation. + AllowStatic("String", "Format", (_, a) => + a[1] is object?[] fargs ? string.Format((string)a[0]!, fargs) : string.Format((string)a[0]!, a[1]), 2); + AllowStatic("String", "Format", (_, a) => string.Format((string)a[0]!, a[1], a[2]), 3); + AllowStatic("String", "Format", (_, a) => string.Format((string)a[0]!, a[1], a[2], a[3]), 4); + AllowStatic("String", "op_Equality", (_, a) => string.Equals(a[0] as string, a[1] as string) ? 1 : 0, 2); + AllowStatic("String", "op_Inequality", (_, a) => !string.Equals(a[0] as string, a[1] as string) ? 1 : 0, 2); + Allow("String", "get_Length", (recv, _) => ((string)recv!).Length, 0); + // String indexing `s[i]` lowers to get_Chars. The analyzer permits it (it bans constructs, + // not member calls) and get_Length's sibling was missing, so `s[i]` compiled + passed the + // analyzer but threw "not registered" at runtime. Returns char -> I4; a bad index throws the + // real IndexOutOfRangeException (fault parity). (found by fuzzing char/string indexing.) + Allow("String", "get_Chars", (recv, a) => ((string)recv!)[(int)a[0]!], 1); + + // Primitives — ToString (Roslyn emits Int32.ToString(), not Object.ToString()) + Allow("Int32", "ToString", (recv, _) => recv?.ToString() ?? "", 0); + Allow("Int64", "ToString", (recv, _) => recv?.ToString() ?? "", 0); + // (Single.ToString/0 registers below with the Convert.ToSingle receiver coercion — + // registering it here too would be shadowed: entries key by name+arity, last wins.) + Allow("Double", "ToString", (recv, _) => recv?.ToString() ?? "", 0); + Allow("Boolean", "ToString", (recv, _) => recv?.ToString() ?? "", 0); + Allow("Char", "ToString", (recv, _) => recv?.ToString() ?? "", 0); + // Sub-int integrals: reachable e.g. via Math.Max(char,char) -> ushort. Their decimal + // rendering is identical to the (int-boxed) receiver value, so no ReceiverBox is needed. + Allow("Byte", "ToString", (recv, _) => recv?.ToString() ?? "", 0); + Allow("SByte", "ToString", (recv, _) => recv?.ToString() ?? "", 0); + Allow("Int16", "ToString", (recv, _) => recv?.ToString() ?? "", 0); + Allow("UInt16", "ToString", (recv, _) => recv?.ToString() ?? "", 0); + + // Int32.Parse — let FormatException propagate as ScriptRuntimeException + AllowStatic("Int32", "Parse", (_, a) => int.Parse((string)a[0]!), 1); + + AllowStatic("String", "IsNullOrEmpty", (_, a) => string.IsNullOrEmpty(a[0] as string) ? 1 : 0, 1); + AllowStatic("String", "IsNullOrWhiteSpace", (_, a) => string.IsNullOrWhiteSpace(a[0] as string) ? 1 : 0, 1); + AllowStatic("String", "Join", (_, a) => + { + if (a[1] is string[] sj) return string.Join((string?)a[0], sj); + var src = (object?[])a[1]!; + var parts = new string?[src.Length]; + for (int i = 0; i < src.Length; i++) parts[i] = src[i]?.ToString(); + return string.Join((string?)a[0], parts); + }, 2); + // The everyday instance surface HUD/parsing code leans on. Auto-bind deliberately skips + // the BCL, so anything not shimmed here throws at runtime in a reloaded body. char args + // arrive boxed as int (I4 slots) — coerce like CoerceArgs would. + static char AsChar(object? v) => v is char c ? c : (char)Convert.ToInt32(v); + Allow("String", "ToUpper", (recv, _) => ((string)recv!).ToUpper(), 0); + Allow("String", "ToLower", (recv, _) => ((string)recv!).ToLower(), 0); + Allow("String", "ToUpperInvariant", (recv, _) => ((string)recv!).ToUpperInvariant(), 0); + Allow("String", "ToLowerInvariant", (recv, _) => ((string)recv!).ToLowerInvariant(), 0); + Allow("String", "Trim", (recv, _) => ((string)recv!).Trim(), 0); + Allow("String", "TrimStart", (recv, _) => ((string)recv!).TrimStart(), 0); + Allow("String", "TrimEnd", (recv, _) => ((string)recv!).TrimEnd(), 0); + Allow("String", "Substring", (recv, a) => ((string)recv!).Substring(Convert.ToInt32(a[0])), 1); + Allow("String", "Substring", (recv, a) => ((string)recv!).Substring(Convert.ToInt32(a[0]), Convert.ToInt32(a[1])), 2); + Allow("String", "IndexOf", (recv, a) => a[0] is string ixs ? ((string)recv!).IndexOf(ixs) : ((string)recv!).IndexOf(AsChar(a[0])), 1); + Allow("String", "LastIndexOf",(recv, a) => a[0] is string lxs ? ((string)recv!).LastIndexOf(lxs) : ((string)recv!).LastIndexOf(AsChar(a[0])), 1); + Allow("String", "Contains", (recv, a) => (a[0] is string cs ? ((string)recv!).Contains(cs) : ((string)recv!).Contains(AsChar(a[0]))) ? 1 : 0, 1); + Allow("String", "Replace", (recv, a) => a[0] is string rs ? ((string)recv!).Replace(rs, (string?)a[1]) : ((string)recv!).Replace(AsChar(a[0]), AsChar(a[1])), 2); + Allow("String", "StartsWith", (recv, a) => ((string)recv!).StartsWith((string)a[0]!) ? 1 : 0, 1); + Allow("String", "EndsWith", (recv, a) => ((string)recv!).EndsWith((string)a[0]!) ? 1 : 0, 1); + Allow("String", "Trim", (recv, a) => a[0] is char[] tcs ? ((string)recv!).Trim(tcs) : ((string)recv!).Trim(AsChar(a[0])), 1); + // Comparison-mode overloads — the StringComparison enum arrives boxed from an I4 slot. + // Instance comparison-mode only: the entry key is name+arity, and the lowering counts + // stack args from HasThis, so STATIC string.Equals(a, b) can't share this slot — it + // stays loud-unbound (write `a == b`); the 3-arg static form below has its own arity. + Allow("String", "Equals", (recv, a) => ((string)recv!).Equals(a[0] as string, (StringComparison)Convert.ToInt32(a[1])) ? 1 : 0, 2); + Allow("String", "StartsWith", (recv, a) => ((string)recv!).StartsWith((string)a[0]!, (StringComparison)Convert.ToInt32(a[1])) ? 1 : 0, 2); + Allow("String", "EndsWith", (recv, a) => ((string)recv!).EndsWith((string)a[0]!, (StringComparison)Convert.ToInt32(a[1])) ? 1 : 0, 2); + Allow("String", "IndexOf", (recv, a) => a[1] is string || a[1] == null + ? ((string)recv!).IndexOf((string)a[0]!, StringComparison.Ordinal) + : ((string)recv!).IndexOf((string)a[0]!, (StringComparison)Convert.ToInt32(a[1])), 2); + Allow("String", "Contains", (recv, a) => ((string)recv!).Contains((string)a[0]!, (StringComparison)Convert.ToInt32(a[1])) ? 1 : 0, 2); + AllowStatic("String", "Equals", (_, a) => string.Equals(a[0] as string, a[1] as string, (StringComparison)Convert.ToInt32(a[2])) ? 1 : 0, 3); + Allow("String", "Remove", (recv, a) => ((string)recv!).Remove(Convert.ToInt32(a[0])), 1); + Allow("String", "Remove", (recv, a) => ((string)recv!).Remove(Convert.ToInt32(a[0]), Convert.ToInt32(a[1])), 2); + Allow("String", "Insert", (recv, a) => ((string)recv!).Insert(Convert.ToInt32(a[0]), (string)a[1]!), 2); + Allow("String", "ToCharArray",(recv, _) => ((string)recv!).ToCharArray(), 0); + Allow("String", "CompareTo", (recv, a) => ((string)recv!).CompareTo(a[0] as string), 1); + AllowStatic("String", "Compare", (_, a) => string.Compare(a[0] as string, a[1] as string, StringComparison.CurrentCulture), 2); + Allow("String", "PadLeft", (recv, a) => ((string)recv!).PadLeft(Convert.ToInt32(a[0])), 1); + Allow("String", "PadLeft", (recv, a) => ((string)recv!).PadLeft(Convert.ToInt32(a[0]), AsChar(a[1])), 2); + Allow("String", "PadRight", (recv, a) => ((string)recv!).PadRight(Convert.ToInt32(a[0])), 1); + Allow("String", "PadRight", (recv, a) => ((string)recv!).PadRight(Convert.ToInt32(a[0]), AsChar(a[1])), 2); + Allow("String", "Split", (recv, a) => ((string)recv!).Split(AsChar(a[0])), 1); + Allow("String", "ToString", (recv, _) => recv, 0); + + // RuntimeHelpers.InitializeArray — fallback no-op. The interpreter pattern-matches + // the Roslyn-emitted "newarr; dup; ldtoken ; call InitializeArray" sequence in + // ScriptInterpreter.Newarr and does the fill eagerly, so this delegate is normally + // unreachable. Registered so BclCoverageTests sees the MemberRef as bound. + AllowStatic("RuntimeHelpers", "InitializeArray", (_, _) => null, 2); + + // Array.Empty() — Roslyn emits this when a params T[] parameter receives no arguments. + var arrayEmptyDef = typeof(System.Array).GetMethod(nameof(System.Array.Empty))!; + _openGenericMethods[("Array", "Empty", 0)] = new List { arrayEmptyDef }; + + // string.Join(string, IEnumerable) — the HUD staple `string.Join(",", list)` + // binds the generic overload through a MethodSpec. + foreach (var sjm in typeof(string).GetMethods(BindingFlags.Public | BindingFlags.Static)) + { + if (sjm.Name == "Join" && sjm.IsGenericMethodDefinition && sjm.GetParameters().Length == 2 + && sjm.GetParameters()[0].ParameterType == typeof(string)) + { _openGenericMethods[("String", "Join", 2)] = new List { sjm }; break; } + } + + // Array.IndexOf(T[], T) / Sort(T[]) / Reverse(T[]) — C# binds the GENERIC + // overloads for typed arrays, reached through MethodSpecs; register the open definitions + // for lazy instantiation. + foreach (var aim in typeof(System.Array).GetMethods(BindingFlags.Public | BindingFlags.Static)) + { + if (!aim.IsGenericMethodDefinition) continue; + int argc = aim.GetParameters().Length; + if ((aim.Name == "IndexOf" && argc == 2) || + ((aim.Name == "Sort" || aim.Name == "Reverse") && argc == 1)) + { + var key = ("Array", aim.Name, argc); + if (!_openGenericMethods.ContainsKey(key)) + _openGenericMethods[key] = new List { aim }; + } + } + + // Math — double-true now that R8 slots exist: the call site widens through conv.r8 + // and the result rides an R8 slot (bit-exact parity with compiled C#). + // Methods with int and float overloads runtime-switch on first-arg type. Each arm casts + // to (object) to suppress C# switch-expression type unification (which would otherwise + // widen int→float across arms and box every result as float). + AllowStatic("Math", "Abs", (_, a) => a[0] switch + { + int i => (object)Math.Abs(i), + long l => (object)Math.Abs(l), + float f => (object)Math.Abs(f), + _ => (object)(float)Math.Abs(Convert.ToSingle(a[0])), + }, 1); + AllowStatic("Math", "Min", (_, a) => (a[0], a[1]) switch + { + (int x, int y) => (object)Math.Min(x, y), + (long x, long y) => (object)Math.Min(x, y), + (float x, float y) => (object)Math.Min(x, y), + _ => (object)(float)Math.Min(Convert.ToSingle(a[0]), Convert.ToSingle(a[1])), + }, 2); + AllowStatic("Math", "Max", (_, a) => (a[0], a[1]) switch + { + (int x, int y) => (object)Math.Max(x, y), + (long x, long y) => (object)Math.Max(x, y), + (float x, float y) => (object)Math.Max(x, y), + _ => (object)(float)Math.Max(Convert.ToSingle(a[0]), Convert.ToSingle(a[1])), + }, 2); + AllowStatic("Math", "Clamp", (_, a) => (a[0], a[1], a[2]) switch + { + (int x, int lo, int hi) => (object)Math.Clamp(x, lo, hi), + (float x, float lo, float hi) => (object)Math.Clamp(x, lo, hi), + _ => (object)(float)Math.Clamp(Convert.ToSingle(a[0]), Convert.ToSingle(a[1]), Convert.ToSingle(a[2])), + }, 3); + AllowStatic("Math", "Sign", (_, a) => a[0] switch + { + int i => (object)Math.Sign(i), + long l => (object)Math.Sign(l), + float f => (object)Math.Sign(f), + _ => (object)Math.Sign(Convert.ToSingle(a[0])), + }, 1); + AllowStatic("Math", "Sqrt", (_, a) => Math.Sqrt(AsR8(a[0])), 1); + AllowStatic("Math", "Pow", (_, a) => Math.Pow(AsR8(a[0]), AsR8(a[1])), 2); + AllowStatic("Math", "Sin", (_, a) => Math.Sin(AsR8(a[0])), 1); + AllowStatic("Math", "Cos", (_, a) => Math.Cos(AsR8(a[0])), 1); + AllowStatic("Math", "Tan", (_, a) => Math.Tan(AsR8(a[0])), 1); + AllowStatic("Math", "Asin", (_, a) => Math.Asin(AsR8(a[0])), 1); + AllowStatic("Math", "Acos", (_, a) => Math.Acos(AsR8(a[0])), 1); + AllowStatic("Math", "Atan", (_, a) => Math.Atan(AsR8(a[0])), 1); + AllowStatic("Math", "Atan2", (_, a) => Math.Atan2(AsR8(a[0]), AsR8(a[1])), 2); + AllowStatic("Math", "Floor", (_, a) => Math.Floor(AsR8(a[0])), 1); + AllowStatic("Math", "Ceiling", (_, a) => Math.Ceiling(AsR8(a[0])), 1); + AllowStatic("Math", "Round", (_, a) => Math.Round(AsR8(a[0])), 1); + AllowStatic("Math", "Truncate", (_, a) => Math.Truncate(AsR8(a[0])), 1); + AllowStatic("Math", "Exp", (_, a) => Math.Exp(AsR8(a[0])), 1); + AllowStatic("Math", "Log", (_, a) => Math.Log(AsR8(a[0])), 1); + AllowStatic("Math", "Log10", (_, a) => Math.Log10(AsR8(a[0])), 1); + // Math.PI and Math.E are `const double` — Roslyn inlines as ldc.r8 literals at use + // sites, so no MemberRef is emitted and no binding is needed. + + // MathF — the float-native twin gameplay code actually writes. Same surface as the Math + // shims above, no double round-trip. + AllowStatic("MathF", "Abs", (_, a) => MathF.Abs(Convert.ToSingle(a[0])), 1); + AllowStatic("MathF", "Min", (_, a) => MathF.Min(Convert.ToSingle(a[0]), Convert.ToSingle(a[1])), 2); + AllowStatic("MathF", "Max", (_, a) => MathF.Max(Convert.ToSingle(a[0]), Convert.ToSingle(a[1])), 2); + AllowStatic("MathF", "Sign", (_, a) => MathF.Sign(Convert.ToSingle(a[0])), 1); + AllowStatic("MathF", "Sqrt", (_, a) => MathF.Sqrt(Convert.ToSingle(a[0])), 1); + AllowStatic("MathF", "Pow", (_, a) => MathF.Pow(Convert.ToSingle(a[0]), Convert.ToSingle(a[1])), 2); + AllowStatic("MathF", "Sin", (_, a) => MathF.Sin(Convert.ToSingle(a[0])), 1); + AllowStatic("MathF", "Cos", (_, a) => MathF.Cos(Convert.ToSingle(a[0])), 1); + AllowStatic("MathF", "Tan", (_, a) => MathF.Tan(Convert.ToSingle(a[0])), 1); + AllowStatic("MathF", "Atan2", (_, a) => MathF.Atan2(Convert.ToSingle(a[0]), Convert.ToSingle(a[1])), 2); + AllowStatic("MathF", "Floor", (_, a) => MathF.Floor(Convert.ToSingle(a[0])), 1); + AllowStatic("MathF", "Ceiling", (_, a) => MathF.Ceiling(Convert.ToSingle(a[0])), 1); + AllowStatic("MathF", "Round", (_, a) => MathF.Round(Convert.ToSingle(a[0])), 1); + AllowStatic("MathF", "Round", (_, a) => MathF.Round(Convert.ToSingle(a[0]), Convert.ToInt32(a[1])), 2); + AllowStatic("MathF", "Truncate", (_, a) => MathF.Truncate(Convert.ToSingle(a[0])), 1); + AllowStatic("MathF", "Exp", (_, a) => MathF.Exp(Convert.ToSingle(a[0])), 1); + AllowStatic("MathF", "Log", (_, a) => MathF.Log(Convert.ToSingle(a[0])), 1); + + // Numeric formatting/parsing — the HUD staples. Formatted ToString on the I4/R4 slot + // families needs the receiver's real type; the slot has erased char/bool identity but a + // FORMATTED ToString is only meaningful on int/float anyway. + Allow("Single", "ToString", (recv, _) => Convert.ToSingle(recv).ToString(), 0); + Allow("Single", "ToString", (recv, a) => Convert.ToSingle(recv).ToString((string?)a[0]), 1); + Allow("Int32", "ToString", (recv, a) => Convert.ToInt32(recv).ToString((string?)a[0]), 1); + // uint is analyzer-legal but rides I4 slots: the receiver may arrive boxed as a wrapped + // NEGATIVE int (3000000000u -> -1294967296), so reinterpret the bits, never Convert.ToUInt32. + Allow("UInt32", "ToString", (recv, _) => unchecked((uint)Convert.ToInt64(recv)).ToString(), 0); + Allow("UInt32", "ToString", (recv, a) => unchecked((uint)Convert.ToInt64(recv)).ToString((string?)a[0]), 1); + // 64-bit receivers arrive boxed as their true type (box_prim), but a value that crossed + // through an O slot may be boxed long — reinterpret bits, never checked-Convert. + Allow("Int64", "ToString", (recv, a) => AsI8(recv).ToString((string?)a[0]), 1); + Allow("UInt64", "ToString", (recv, _) => unchecked((ulong)AsI8(recv)).ToString(), 0); + Allow("UInt64", "ToString", (recv, a) => unchecked((ulong)AsI8(recv)).ToString((string?)a[0]), 1); + Allow("Double", "ToString", (recv, _) => AsR8(recv).ToString(), 0); + Allow("Double", "ToString", (recv, a) => AsR8(recv).ToString((string?)a[0]), 1); + // NaN/Infinity guards — the classic defensive checks around physics and division. + AllowStatic("Single", "IsNaN", (_, a) => float.IsNaN(Convert.ToSingle(a[0])) ? 1 : 0, 1); + AllowStatic("Single", "IsInfinity", (_, a) => float.IsInfinity(Convert.ToSingle(a[0])) ? 1 : 0, 1); + AllowStatic("Int32", "TryParse", (_, a) => + { + if (int.TryParse(a[0] as string, out var v)) { a[1] = v; return 1; } + a[1] = 0; return 0; + }, 2, typeof(HostBinding).GetMethod(nameof(TryGetValueShape), + BindingFlags.NonPublic | BindingFlags.Static)!.GetParameters()); + AllowStatic("Int64", "TryParse", (_, a) => + { + if (long.TryParse(a[0] as string, out var v)) { a[1] = v; return 1; } + a[1] = 0L; return 0; + }, 2, typeof(HostBinding).GetMethod(nameof(TryGetValueShape), + BindingFlags.NonPublic | BindingFlags.Static)!.GetParameters()); + AllowStatic("Double", "TryParse", (_, a) => + { + if (double.TryParse(a[0] as string, out var v)) { a[1] = v; return 1; } + a[1] = 0d; return 0; + }, 2, typeof(HostBinding).GetMethod(nameof(TryGetValueShape), + BindingFlags.NonPublic | BindingFlags.Static)!.GetParameters()); + AllowStatic("Single", "TryParse", (_, a) => + { + if (float.TryParse(a[0] as string, out var v)) { a[1] = v; return 1; } + a[1] = 0f; return 0; + }, 2, typeof(HostBinding).GetMethod(nameof(TryGetValueShape), + BindingFlags.NonPublic | BindingFlags.Static)!.GetParameters()); + + // Bitmask checks on [Flags] enums. Receiver and argument both arrive as properly-typed + // boxed enums (box_enum). + Allow("Enum", "HasFlag", (recv, a) => ((Enum)recv!).HasFlag((Enum)a[0]!) ? 1 : 0, 1); + + // Primitive/enum receiver basics — GetHashCode/CompareTo/Equals on I4/R4 slot values. + Allow("Int32", "GetHashCode", (recv, _) => Convert.ToInt32(recv).GetHashCode(), 0); + Allow("Single", "GetHashCode", (recv, _) => Convert.ToSingle(recv).GetHashCode(), 0); + Allow("Int32", "CompareTo", (recv, a) => Convert.ToInt32(recv).CompareTo(Convert.ToInt32(a[0])), 1); + Allow("Single", "CompareTo", (recv, a) => Convert.ToSingle(recv).CompareTo(Convert.ToSingle(a[0])), 1); + // Enum receivers arrive as typed boxed enums (box_enum / the constrained-enum path). + Allow("Enum", "GetHashCode", (recv, _) => recv!.GetHashCode(), 0); + Allow("Enum", "CompareTo", (recv, a) => ((IComparable)recv!).CompareTo(a[0]), 1); + + // char classification statics — input/text parsing. Args ride I4 slots boxed as int. + AllowStatic("Char", "IsDigit", (_, a) => char.IsDigit(AsChar(a[0])) ? 1 : 0, 1); + AllowStatic("Char", "IsLetter", (_, a) => char.IsLetter(AsChar(a[0])) ? 1 : 0, 1); + AllowStatic("Char", "IsLetterOrDigit", (_, a) => char.IsLetterOrDigit(AsChar(a[0])) ? 1 : 0, 1); + AllowStatic("Char", "IsWhiteSpace", (_, a) => char.IsWhiteSpace(AsChar(a[0])) ? 1 : 0, 1); + AllowStatic("Char", "IsUpper", (_, a) => char.IsUpper(AsChar(a[0])) ? 1 : 0, 1); + AllowStatic("Char", "IsLower", (_, a) => char.IsLower(AsChar(a[0])) ? 1 : 0, 1); + AllowStatic("Char", "ToUpper", (_, a) => char.ToUpper(AsChar(a[0])), 1); + AllowStatic("Char", "ToLower", (_, a) => char.ToLower(AsChar(a[0])), 1); + + // Array.IndexOf — the generic static binds as IndexOf; the non-generic overload + // serves every element type. + AllowStatic("Array", "IndexOf", (_, a) => Array.IndexOf((Array)a[0]!, a[1]), 2); + AllowStatic("Array", "Copy", (_, a) => { Array.Copy((Array)a[0]!, (Array)a[1]!, Convert.ToInt32(a[2])); return null; }, 3); + AllowStatic("Array", "Copy", (_, a) => { Array.Copy((Array)a[0]!, Convert.ToInt32(a[1]), (Array)a[2]!, Convert.ToInt32(a[3]), Convert.ToInt32(a[4])); return null; }, 5); + AllowStatic("Array", "Clear", (_, a) => { Array.Clear((Array)a[0]!, Convert.ToInt32(a[1]), Convert.ToInt32(a[2])); return null; }, 3); + + // StringBuilder — HUD string building without per-frame concat garbage. + AllowConstructor("StringBuilder", (_, _2) => new StringBuilder(), 0); + AllowConstructor("StringBuilder", (_, a) => a[0] is int cap ? new StringBuilder(cap) : new StringBuilder((string?)a[0]), 1); + Allow("StringBuilder", "Append", (recv, a) => ((StringBuilder)recv!).Append(a[0]), 1); + Allow("StringBuilder", "AppendLine", (recv, _) => ((StringBuilder)recv!).AppendLine(), 0); + Allow("StringBuilder", "AppendLine", (recv, a) => ((StringBuilder)recv!).AppendLine(a[0]?.ToString()), 1); + Allow("StringBuilder", "Clear", (recv, _) => ((StringBuilder)recv!).Clear(), 0); + Allow("StringBuilder", "ToString", (recv, _) => ((StringBuilder)recv!).ToString(), 0); + Allow("StringBuilder", "get_Length", (recv, _) => ((StringBuilder)recv!).Length, 0); + + // System.Random — seeded, deterministic across both sides of the oracle. + // Defensive throws — `throw new InvalidOperationException("...")` on bad state. + AllowConstructor("Exception", (_, a) => new Exception((string?)a[0]), 1); + AllowConstructor("InvalidOperationException", (_, _2) => new InvalidOperationException(), 0); + AllowConstructor("InvalidOperationException", (_, a) => new InvalidOperationException((string?)a[0]), 1); + AllowConstructor("ArgumentException", (_, a) => new ArgumentException((string?)a[0]), 1); + AllowConstructor("ArgumentOutOfRangeException",(_, a) => new ArgumentOutOfRangeException((string?)a[0]), 1); + AllowConstructor("ArgumentNullException", (_, a) => new ArgumentNullException((string?)a[0]), 1); + AllowConstructor("NotSupportedException", (_, a) => new NotSupportedException((string?)a[0]), 1); + AllowConstructor("IndexOutOfRangeException", (_, a) => new IndexOutOfRangeException((string?)a[0]), 1); + AllowConstructor("KeyNotFoundException", (_, a) => new System.Collections.Generic.KeyNotFoundException((string?)a[0]), 1); + + // Range slices — `arr[1..4]` lowers to Index conversions + `new Range` + + // RuntimeHelpers.GetSubArray(array, range). + AllowStatic("Index", "op_Implicit", (_, a) => (Index)Convert.ToInt32(a[0]), 1); + AllowConstructor("Index", (_, a) => new Index(Convert.ToInt32(a[0]), + a[1] is bool fromEnd ? fromEnd : Convert.ToInt32(a[1]) != 0), 2); + AllowConstructor("Range", (_, a) => new Range((Index)a[0]!, (Index)a[1]!), 2); + var gsa = typeof(System.Runtime.CompilerServices.RuntimeHelpers) + .GetMethod("GetSubArray", BindingFlags.Public | BindingFlags.Static); + if (gsa != null) + _openGenericMethods[("RuntimeHelpers", "GetSubArray", 2)] = new List { gsa }; + + foreach (var afm in typeof(System.Array).GetMethods(BindingFlags.Public | BindingFlags.Static)) + { + if (afm.Name == "Fill" && afm.IsGenericMethodDefinition && afm.GetParameters().Length == 2) + { _openGenericMethods[("Array", "Fill", 2)] = new List { afm }; break; } + } + + AllowConstructor("Random", (_, _2) => new Random(), 0); + AllowConstructor("Random", (_, a) => new Random(Convert.ToInt32(a[0])), 1); + Allow("Random", "Next", (recv, _) => ((Random)recv!).Next(), 0); + Allow("Random", "Next", (recv, a) => ((Random)recv!).Next(Convert.ToInt32(a[0])), 1); + Allow("Random", "Next", (recv, a) => ((Random)recv!).Next(Convert.ToInt32(a[0]), Convert.ToInt32(a[1])), 2); + // netstandard2.1 (the editor profile) has no Random.NextSingle — same distribution via NextDouble. + Allow("Random", "NextSingle", (recv, _) => (float)((Random)recv!).NextDouble(), 0); + + // Wall-clock cooldowns and save stamps. DateTime/TimeSpan are host structs the script + // only ever holds boxed; float-view accessors keep results in the script's number space. + AllowStatic("DateTime", "get_Now", (_, _2) => DateTime.Now, 0); + AllowStatic("DateTime", "get_UtcNow", (_, _2) => DateTime.UtcNow, 0); + AllowStatic("DateTime", "op_Subtraction", (_, a) => (DateTime)a[0]! - (DateTime)a[1]!, 2); + Allow("DateTime", "get_Hour", (recv, _) => ((DateTime)recv!).Hour, 0); + Allow("DateTime", "get_Minute", (recv, _) => ((DateTime)recv!).Minute, 0); + Allow("DateTime", "get_Second", (recv, _) => ((DateTime)recv!).Second, 0); + Allow("DateTime", "ToString", (recv, a) => ((DateTime)recv!).ToString((string?)a[0]), 1); + Allow("TimeSpan", "get_TotalSeconds", (recv, _) => (float)((TimeSpan)recv!).TotalSeconds, 0); + Allow("TimeSpan", "get_TotalMilliseconds", (recv, _) => (float)((TimeSpan)recv!).TotalMilliseconds, 0); + AllowStatic("Environment", "get_TickCount", (_, _2) => Environment.TickCount, 0); + // Roslyn's IEnumerable iterator boilerplate checks thread affinity in GetEnumerator. + AllowStatic("Environment", "get_CurrentManagedThreadId", (_, _2) => Environment.CurrentManagedThreadId, 0); + + // Enum.TryParse(string, out T) — config/save parsing; the MethodSpec instantiation + // carries real ParameterInfo, so the byref out rides the standard write-back path. + foreach (var etp in typeof(Enum).GetMethods(BindingFlags.Public | BindingFlags.Static)) + { + if (etp.Name == "TryParse" && etp.IsGenericMethodDefinition && etp.GetParameters().Length == 2 + && etp.GetParameters()[0].ParameterType == typeof(string)) + { _openGenericMethods[("Enum", "TryParse", 2)] = new List { etp }; break; } + } + AllowStatic("Guid", "NewGuid", (_, _2) => Guid.NewGuid(), 0); + Allow("Guid", "ToString", (recv, _) => ((Guid)recv!).ToString(), 0); + + // List extras beyond the core set above; Sort/ToArray need the closed generic, so + // dispatch by reflection on the instance (AOT-safe — the instantiation already exists). + Allow("List`1", "Sort", (recv, _) => { recv!.GetType().GetMethod("Sort", Type.EmptyTypes)!.Invoke(recv, null); return null; }, 0); + Allow("List`1", "ToArray", (recv, _) => recv!.GetType().GetMethod("ToArray")!.Invoke(recv, null), 0); + // Predicate members — the arg is a real closed delegate (Predicate) built by the + // delegate machinery, so reflection Invoke dispatches it directly. + Allow("List`1", "AddRange", (recv, a) => { recv!.GetType().GetMethod("AddRange")!.Invoke(recv, new[] { a[0] }); return null; }, 1); + Allow("List`1", "Reverse", (recv, _) => { recv!.GetType().GetMethod("Reverse", Type.EmptyTypes)!.Invoke(recv, null); return null; }, 0); + Allow("List`1", "GetRange", (recv, a) => recv!.GetType().GetMethod("GetRange")!.Invoke(recv, new object?[] { Convert.ToInt32(a[0]), Convert.ToInt32(a[1]) }), 2); + Allow("List`1", "Find", (recv, a) => NormalizeIntegralReturn(recv!.GetType().GetMethod("Find")!.Invoke(recv, new[] { a[0] })), 1); + Allow("List`1", "FindIndex", (recv, a) => recv!.GetType().GetMethod("FindIndex", new[] { typeof(Predicate<>).MakeGenericType(recv.GetType().GetGenericArguments()) })!.Invoke(recv, new[] { a[0] }), 1); + Allow("List`1", "Exists", (recv, a) => (bool)recv!.GetType().GetMethod("Exists")!.Invoke(recv, new[] { a[0] })! ? 1 : 0, 1); + Allow("List`1", "RemoveAll", (recv, a) => recv!.GetType().GetMethod("RemoveAll")!.Invoke(recv, new[] { a[0] }), 1); + + // Queue/Stack — pooling and undo stacks. No non-generic interface carries their + // members, so reflection-dispatch per member. + Allow("Queue`1", "Enqueue", (recv, a) => { recv!.GetType().GetMethod("Enqueue")!.Invoke(recv, new[] { a[0] }); return null; }, 1); + Allow("Queue`1", "Dequeue", (recv, _) => recv!.GetType().GetMethod("Dequeue")!.Invoke(recv, null), 0); + Allow("Queue`1", "Peek", (recv, _) => recv!.GetType().GetMethod("Peek")!.Invoke(recv, null), 0); + Allow("Queue`1", "Clear", (recv, _) => { recv!.GetType().GetMethod("Clear")!.Invoke(recv, null); return null; }, 0); + Allow("Queue`1", "get_Count", (recv, _) => ((System.Collections.ICollection)recv!).Count, 0); + Allow("Stack`1", "Push", (recv, a) => { recv!.GetType().GetMethod("Push")!.Invoke(recv, new[] { a[0] }); return null; }, 1); + Allow("Stack`1", "Pop", (recv, _) => recv!.GetType().GetMethod("Pop")!.Invoke(recv, null), 0); + Allow("Stack`1", "Peek", (recv, _) => recv!.GetType().GetMethod("Peek")!.Invoke(recv, null), 0); + Allow("Stack`1", "Clear", (recv, _) => { recv!.GetType().GetMethod("Clear")!.Invoke(recv, null); return null; }, 0); + Allow("Stack`1", "get_Count", (recv, _) => ((System.Collections.ICollection)recv!).Count, 0); + + // Attach FastIsFlat paths to the always-float Math methods above — AllowBcl doesn't run + // BuildTypedDelegates for Math, so Fasts are attached by hand. Multi-arm dispatch methods + // (Abs, Sign, Min, Max, Clamp) stay on the slow delegate path: their result type depends + // on the argument type, and mixing int and float results in the same R4 dst slot would + // corrupt the int arm's value. + + // (double) → double — the closures compute at full width and write R8 dsts + AttachFlatDouble("Math", "Sqrt", 1, (_, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + Math.Sqrt(NumReadDouble(num, ref_, slotT, bp + (int)ir[argBase])))); + AttachFlatDouble("Math", "Sin", 1, (_, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + Math.Sin(NumReadDouble(num, ref_, slotT, bp + (int)ir[argBase])))); + AttachFlatDouble("Math", "Cos", 1, (_, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + Math.Cos(NumReadDouble(num, ref_, slotT, bp + (int)ir[argBase])))); + AttachFlatDouble("Math", "Tan", 1, (_, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + Math.Tan(NumReadDouble(num, ref_, slotT, bp + (int)ir[argBase])))); + AttachFlatDouble("Math", "Asin", 1, (_, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + Math.Asin(NumReadDouble(num, ref_, slotT, bp + (int)ir[argBase])))); + AttachFlatDouble("Math", "Acos", 1, (_, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + Math.Acos(NumReadDouble(num, ref_, slotT, bp + (int)ir[argBase])))); + AttachFlatDouble("Math", "Atan", 1, (_, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + Math.Atan(NumReadDouble(num, ref_, slotT, bp + (int)ir[argBase])))); + AttachFlatDouble("Math", "Floor", 1, (_, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + Math.Floor(NumReadDouble(num, ref_, slotT, bp + (int)ir[argBase])))); + AttachFlatDouble("Math", "Ceiling", 1, (_, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + Math.Ceiling(NumReadDouble(num, ref_, slotT, bp + (int)ir[argBase])))); + AttachFlatDouble("Math", "Round", 1, (_, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + Math.Round(NumReadDouble(num, ref_, slotT, bp + (int)ir[argBase])))); + AttachFlatDouble("Math", "Truncate", 1, (_, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + Math.Truncate(NumReadDouble(num, ref_, slotT, bp + (int)ir[argBase])))); + AttachFlatDouble("Math", "Exp", 1, (_, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + Math.Exp(NumReadDouble(num, ref_, slotT, bp + (int)ir[argBase])))); + AttachFlatDouble("Math", "Log", 1, (_, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + Math.Log(NumReadDouble(num, ref_, slotT, bp + (int)ir[argBase])))); + AttachFlatDouble("Math", "Log10", 1, (_, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + Math.Log10(NumReadDouble(num, ref_, slotT, bp + (int)ir[argBase])))); + + // (double, double) → double + AttachFlatDouble("Math", "Atan2", 2, (_, num, ref_, slotT, ir, argBase, dst, bp) => + { + int s0 = bp + (int)ir[argBase], s1 = bp + (int)ir[argBase + 1]; + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + Math.Atan2(NumReadDouble(num, ref_, slotT, s0), NumReadDouble(num, ref_, slotT, s1))); + }); + AttachFlatDouble("Math", "Pow", 2, (_, num, ref_, slotT, ir, argBase, dst, bp) => + { + int s0 = bp + (int)ir[argBase], s1 = bp + (int)ir[argBase + 1]; + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + Math.Pow(NumReadDouble(num, ref_, slotT, s0), NumReadDouble(num, ref_, slotT, s1))); + }); + + return this; + } + + // Parameter shape borrowed by the Dictionary`2.TryGetValue shim: the lowerer classifies + // byref call sites from Entry.Params, which hand-written shims otherwise don't carry. + internal static long AsI8(object? v) => v switch + { + long l => l, ulong u => unchecked((long)u), int i => i, uint u4 => u4, + double d => (long)d, float f => (long)f, _ => Convert.ToInt64(v), + }; + + internal static double AsR8(object? v) => v switch + { + double d => d, float f => f, long l => l, ulong u => u, int i => i, + _ => Convert.ToDouble(v), + }; + + static bool TryGetValueShape(object key, out object? value) { value = null; return false; } + static void DeconstructShape(out object? key, out object? value) { key = null; value = null; } + + // Auto-register all public members of T and its base types via reflection. + // Walks the inheritance chain so base-class members (e.g. ButtonControl.isPressed + // inherited by KeyControl) are registered under their declaring type name. + // Skips open generic type definitions; closed generics (e.g. InputControl) + // are registered so their members resolve correctly. Stops at Object / ValueType. + public HostBinding AllowType(Type type) + { + AllowTypeWithBases(type); + // Auto-flatten 4-byte-field structs even without a generic type argument: the pin-based + // marshaller needs no MakeGenericMethod, so auto-bound structs (Rect, LayerMask, game + // structs, ...) stop boxing at every host-call boundary. Blittable structs that don't + // qualify (sub-4-byte fields, e.g. Color32) keep the boxed path and the perf warning. + if (type.IsValueType && !type.IsEnum && IsSlot4FlatCandidate(type)) + { + BuildStructLayoutNonGeneric(type); + if (_structLayoutsByType.ContainsKey(type)) + { + // Without generic Fast closures (value-type MakeGenericMethod is off-limits + // here), flat args would be pin-boxed per OPERATOR call — costlier than the old + // stay-boxed flow. Pure-arithmetic operators sidestep the boundary entirely: + // the IL inspection below marks them and the lowerer synthesizes per-field IR. + InspectAndMarkOperators(type, warnOnReject: false); + } + } + else + WarnIfFlatStructCandidate(type); + // Build the allocation-free Fast delegates the generic AllowType() would — otherwise + // every method on a type registered this way (e.g. UnityHostBinding's Mathf/Time/Physics) + // takes the boxing slow path. Reference types only: a reference T uses IL2CPP shared + // generics (AOT-safe); value types must use AllowTypeStruct() and a value-type + // MakeGenericMethod is an AOT hazard, so they're skipped here. + if (!type.IsValueType && !type.IsEnum) + { + try + { + typeof(HostBinding) + .GetMethod(nameof(BuildTypedDelegates), BindingFlags.NonPublic | BindingFlags.Instance)! + .MakeGenericMethod(type) + .Invoke(this, null); + } + catch { /* best-effort fast-path; falls back to the (correct) slow path on failure */ } + } + // AOT-safe static-method fast paths (no MakeGenericMethod). Fills static-class members + // (Mathf/Time/Physics) that the generic path above can't, and any static methods it missed. + BuildStaticPrimitiveFastDelegates(type); + return this; + } + + /// + /// Register the NON-PUBLIC members (fields, properties, methods — instance AND static) of + /// and its user-defined base types, so an interpreter-run [CodeReload] body — + /// compiled with access checks disabled (BinderFlags.IgnoreAccessibility) — can read/write private + /// state (including private statics like the `s_Instance = this;` singleton pattern) and call private + /// helpers on its target type. Public members are already covered by . + /// + /// The base-chain walk stops at the first UnityEngine / System / Unity.* type, so we never register + /// (nor, via the dev link.xml, force-preserve) the private internals of MonoBehaviour, Component or the + /// BCL — only the user's own component hierarchy. Non-public members go through reflection Get/Set/Invoke, + /// which is AOT-safe on IL2CPP as long as the members survive stripping. + /// + public HostBinding AllowNonPublicInstanceMembers(Type type) + { + const BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly; + for (var t = type; t != null; t = t.BaseType) + { + // Always process the target type itself; only stop CLIMBING once we reach an engine/BCL base + // (MonoBehaviour, Component, object, …) — we never want to register their private internals. + if (t != type) + { + var ns = t.Namespace ?? string.Empty; + if (ns.StartsWith("UnityEngine", StringComparison.Ordinal) || + ns.StartsWith("UnityEditor", StringComparison.Ordinal) || + ns.StartsWith("System", StringComparison.Ordinal) || + ns.StartsWith("Unity.", StringComparison.Ordinal)) + break; + } + + var name = t.Name; + + foreach (var f in t.GetFields(flags)) + { + if (SkipType(f.FieldType)) continue; + RegisterField(name, f); + } + + // Non-public STATIC fields and methods too: a reloaded body may touch its own + // type's private statics (the ubiquitous `s_Instance = this;` singleton pattern). + // Public statics are already covered by AllowType's static walk. + const BindingFlags statFlags = BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly; + foreach (var f in t.GetFields(statFlags)) + { + if (SkipType(f.FieldType)) continue; + RegisterField(name, f); + } + RegisterMethods(t.GetMethods(statFlags), name, isStatic: true); + + // Non-public instance properties → get_/set_ method calls. Accessor arity from the + // accessor itself — indexers take the index (see the public property pass). + foreach (var p in t.GetProperties(flags)) + { + if (SkipType(p.PropertyType)) continue; + if (p.GetMethod != null && !SkipMethod(p.GetMethod)) + { + var g = p.GetMethod; + var gp = g.GetParameters(); + if (gp.Length == 0) + Allow(name, g.Name, (recv, _) => g.Invoke(recv, null), 0, mi: g); + else + Allow(name, g.Name, (recv, args) => g.Invoke(recv, args), gp.Length, gp, mi: g); + } + if (p.SetMethod != null && !SkipMethod(p.SetMethod)) + { + var s = p.SetMethod; + var spms = s.GetParameters(); + Allow(name, s.Name, (recv, args) => { s.Invoke(recv, args); return null; }, spms.Length, spms, mi: s); + } + } + + // Non-public instance methods (RegisterMethods skips get_/set_ via IsSpecialName) + RegisterMethods(t.GetMethods(flags), name, isStatic: false); + } + return this; + } + + public HostBinding AllowType() + { + AllowTypeWithBases(typeof(T)); + // Auto-promote a blittable struct to the non-boxing flat path (equivalent to + // AllowTypeStruct). Compile-time generic over the concrete T → AOT-safe, no + // reflection. Must run before BuildTypedDelegates so its flat ctor/operator fast paths + // see the layout. Component-wise operators/ctors additionally inline (structurally + // verified, quiet on rejection). + if (IsFlatStructCandidate(typeof(T))) + { + BuildStructLayoutCore(); + InspectAndMarkOperators(typeof(T), warnOnReject: false); + } + BuildTypedDelegates(); + return this; + } + + // A blittable (reference-free) struct registered via AllowType is left boxed — every value + // crossing the host-call boundary allocates. AllowTypeStruct() flows it through flat numeric + // frame slots with zero boxing. Warn so the perf footgun is visible at registration time. + static void WarnIfFlatStructCandidate(Type type) + { + if (IsFlatStructCandidate(type)) + Warn( + $"[IlInterpreter] {type.Name} is a blittable struct registered via AllowType — values box on " + + $"every host-call boundary. Use AllowTypeStruct<{type.Name}>() for the non-boxing flat path."); + } + + static bool IsFlatStructCandidate(Type t) + { + if (!t.IsValueType || t.IsEnum || t.IsPrimitive || t.IsPointer || t.IsByRef) return false; + foreach (var f in t.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) + { + var ft = f.FieldType; + if (ft.IsPrimitive || ft.IsEnum) continue; + if (ft.IsValueType && IsFlatStructCandidate(ft)) continue; + return false; // reference field (or non-blittable) → AllowTypeStruct doesn't apply + } + return true; + } + + // Flat-eligibility used by the AUTOMATIC (non-generic) flattening path: every transitive + // field must be a fixed-width int/float — 4-byte, or a sub-4 integer handled by the + // ldfld_vt_{u1,i1,u2,i2} widening / stfld_vt_{b1,b2} truncating ops — an int-backed enum, + // or a nested struct that qualifies. bool and char stay excluded: their Marshal layout + // diverges from the managed layout (bool marshals 4-byte, char ANSI 1-byte), so the flat + // byte image would not match the managed struct. Explicit AllowTypeStruct() keeps the + // wider IsFlatStructCandidate behavior the caller opted into. + static bool IsSlot4FlatCandidate(Type t) + { + if (!t.IsValueType || t.IsEnum || t.IsPrimitive || t.IsPointer || t.IsByRef) return false; + foreach (var f in t.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) + { + var ft = f.FieldType; + if (ft == typeof(int) || ft == typeof(uint) || ft == typeof(float)) continue; + if (ft == typeof(byte) || ft == typeof(sbyte) || ft == typeof(short) || ft == typeof(ushort)) continue; + if (ft.IsEnum && Enum.GetUnderlyingType(ft) == typeof(int)) continue; + if (ft.IsValueType && !ft.IsPrimitive && !ft.IsEnum && IsSlot4FlatCandidate(ft)) continue; + return false; + } + return true; + } + + // Non-generic fast-delegate builder for STATIC methods + static property getters with primitive + // (or ref) signatures. Static members have no `this`, so Func/Func/... bind + // without the declaring type — which is the only way to fast-path STATIC CLASSES (Mathf, Time, + // Physics): they can't be generic type args, so BuildTypedDelegates can't run for them, and + // the non-generic AllowType(Type) MakeGenericMethod path throws on them. Uses no MakeGenericMethod + // → AOT-safe on IL2CPP. Sets FlatReturnSType so the lowerer allocates a flat (R4/I4) dst slot. + void BuildStaticPrimitiveFastDelegates(Type type) + { + var statBind = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly; + string tn = type.Name; + foreach (var m in type.GetMethods(statBind)) + { + if (m.IsGenericMethodDefinition) continue; + // Skip operators/set_ accessors; allow get_ property getters (e.g. Time.deltaTime). + if (m.IsSpecialName && !m.Name.StartsWith("get_", StringComparison.Ordinal)) continue; + var ps = m.GetParameters(); + // Plain static methods live in _byHandle; property getters (IsSpecialName) live in _entries. + if (!_byHandle.TryGetValue(m.MethodHandle.Value, out var entry) + && !_entries.TryGetValue($"{tn}.{m.Name}/{ps.Length}", out entry)) continue; + if (entry.Fast != null) continue; // already fast (e.g. ref type via BuildTypedDelegates) + var rt = m.ReturnType; + + if (rt == typeof(float)) + { + entry.FlatReturnSType = SType.R4; entry.FastIsFlat = true; + if (ps.Length == 0) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), m); + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), del()); + } + else if (ps.Length == 1 && ps[0].ParameterType == typeof(float)) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), m); + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), del(NumReadFloat(num, ref_, slotT, bp + (int)ir[argBase]))); + } + else if (ps.Length == 2 && ps[0].ParameterType == typeof(float) && ps[1].ParameterType == typeof(float)) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), m); + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { int s0 = bp + (int)ir[argBase], s1 = bp + (int)ir[argBase + 1]; + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), del(NumReadFloat(num, ref_, slotT, s0), NumReadFloat(num, ref_, slotT, s1))); }; + } + else if (ps.Length == 3 && ps[0].ParameterType == typeof(float) && ps[1].ParameterType == typeof(float) && ps[2].ParameterType == typeof(float)) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), m); + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { int s0 = bp + (int)ir[argBase], s1 = bp + (int)ir[argBase + 1], s2 = bp + (int)ir[argBase + 2]; + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), del(NumReadFloat(num, ref_, slotT, s0), NumReadFloat(num, ref_, slotT, s1), NumReadFloat(num, ref_, slotT, s2))); }; + } + else { entry.FastIsFlat = false; entry.FlatReturnSType = SType.O; } // unhandled arity — leave slow + } + else if (rt == typeof(int)) + { + entry.FlatReturnSType = SType.I4; entry.FastIsFlat = true; + if (ps.Length == 0) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), m); + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), del()); + } + else if (ps.Length == 1 && ps[0].ParameterType == typeof(int)) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), m); + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), del(NumReadInt(num, ref_, slotT, bp + (int)ir[argBase]))); + } + else if (ps.Length == 2 && ps[0].ParameterType == typeof(int) && ps[1].ParameterType == typeof(int)) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), m); + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { int s0 = bp + (int)ir[argBase], s1 = bp + (int)ir[argBase + 1]; + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), del(NumReadInt(num, ref_, slotT, s0), NumReadInt(num, ref_, slotT, s1))); }; + } + else { entry.FastIsFlat = false; entry.FlatReturnSType = SType.O; } + } + else if (ps.Length == 0 && !rt.IsValueType && rt != typeof(void)) + { + // static () → reference type (factory/getter): store the ref straight into refFrame. + var del = (Func)Delegate.CreateDelegate(typeof(Func), m); + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => ref_[bp + dst] = del(); + } + } + } + + // Like AllowType() but also installs Unsafe.Unbox-based field accessors for struct types. + // Replaces FieldInfo.GetValue (~23 ns) with direct byte-frame reads (~2 ns) for float/int fields. + // IL2CPP-safe: the where T : struct constraint ensures Unsafe.Unbox is AOT-compiled for T. + // Call this instead of AllowType() for performance-critical struct host types (V3, Color, etc.). + // operatorsArePure: opt-in S4 operator inlining. When true, the IL of each operator is + // inspected at registration time; pure arithmetic operators are marked inlineable and the + // lowerer will synthesize field-by-field IR instead of emitting call_host. + public HostBinding AllowTypeStruct(bool operatorsArePure = false) where T : struct + { + AllowTypeWithBases(typeof(T)); + // Struct field/layout delegates first so BuildTypedDelegates can consult + // _structLayoutsByType when building flat-write ctor FastFlat paths. + BuildStructLayoutCore(); + InstallUnsafeStructFieldAccessors(); + BuildTypedDelegates(); + // Operator/ctor inlining is verified STRUCTURALLY (component-wise IL match), so it is + // always safe to attempt; operatorsArePure now only controls whether rejections warn. + InspectAndMarkOperators(typeof(T), warnOnReject: operatorsArePure); + return this; + } + + // Builds the StructLayout the IR lowerer consumes for flat (Vt-slot) struct support, plus per-field + // flat metadata (byte offset + SType). Constraint-free so the unconstrained AllowType() can call + // it to auto-promote a blittable struct to the non-boxing flat path. It's a compile-time generic + // (each concrete T at a call site), so no reflection MakeGenericMethod — AOT-safe. + void BuildStructLayoutCore() + { + int size = Marshal.SizeOf(); + // Boundary marshalling straight off the unmanaged frame. `(T)boxed` unboxes a copy (no + // `where T : struct` needed, unlike Unsafe.Unbox); the bytes written are identical, + // and it's a read-from-box → write-to-frame so a copy is fine. + BoxFromPtrDelegate box = src => { T val = Unsafe.ReadUnaligned(src); return val!; }; + CopyToPtrDelegate copy = (dst, boxed) => Unsafe.WriteUnaligned(dst, (T)boxed!); + FinishStructLayout(typeof(T), size, box, copy); + } + + // Type-only flavor for structs that reach us without a generic type argument — the + // non-generic AllowType(Type) path that auto-bind uses. The layout DATA is plain reflection; + // the marshalling delegates use a pinned-box memcpy instead of Unsafe.ReadUnaligned, + // avoiding the value-type MakeGenericMethod that is unsafe under IL2CPP/AOT. Registration + // runs a byte round-trip self-check and refuses the flat path (boxed fallback) on any + // Marshal-vs-managed layout surprise. + void BuildStructLayoutNonGeneric(Type type) + { + int size = Marshal.SizeOf(type); + BoxFromPtrDelegate box = src => + { + object boxed = Activator.CreateInstance(type)!; + var h = GCHandle.Alloc(boxed, GCHandleType.Pinned); + try { Buffer.MemoryCopy(src, (void*)h.AddrOfPinnedObject(), size, size); } + finally { h.Free(); } + return boxed; + }; + CopyToPtrDelegate copy = (dst, boxed) => + { + var h = GCHandle.Alloc(boxed, GCHandleType.Pinned); + try { Buffer.MemoryCopy((void*)h.AddrOfPinnedObject(), dst, size, size); } + finally { h.Free(); } + }; + + // Round-trip self-check: a recognizable byte pattern must survive box → copy-back. + // Catches pinned-layout drift (e.g. a runtime where the box payload isn't the raw + // struct bytes) at registration time instead of corrupting frames at run time. + if (size <= 1024) + { + byte* probe = stackalloc byte[size]; + byte* echo = stackalloc byte[size]; + for (int i = 0; i < size; i++) probe[i] = (byte)(0xA5 ^ i); + try + { + copy(echo, box(probe)); + for (int i = 0; i < size; i++) + if (echo[i] != probe[i]) + { + Warn($"[IlInterpreter] {type.Name}: pinned-box round-trip mismatch at byte {i} — keeping the boxed path."); + return; + } + } + catch (Exception ex) + { + Warn($"[IlInterpreter] {type.Name}: pinned-box marshalling unavailable ({ex.GetType().Name}) — keeping the boxed path."); + return; + } + } + + FinishStructLayout(type, size, box, copy); + } + + void FinishStructLayout(Type type, int size, BoxFromPtrDelegate box, CopyToPtrDelegate copy) + { + var typeName = type.Name; + var layout = new StructLayout + { + Type = type, + Size = size, + TypeName = typeName, + Fields = new Dictionary(), + BoxFromPtr = box, + CopyToPtr = copy, + }; + RuntimeHelpers.PrepareDelegate(layout.BoxFromPtr); + RuntimeHelpers.PrepareDelegate(layout.CopyToPtr); + var instBind = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly; + foreach (var fi in type.GetFields(instBind)) + { + var key = $"{typeName}.{fi.Name}"; + int byteOffset; + try { byteOffset = (int)Marshal.OffsetOf(type, fi.Name); } + catch { continue; } // non-blittable field — skip + + SType pst; + byte kind = 0; // full 4-byte cell unless a sub-4 primitive + if (fi.FieldType == typeof(float)) pst = SType.R4; + else if (fi.FieldType == typeof(int) || fi.FieldType == typeof(uint) + || fi.FieldType == typeof(bool)) pst = SType.I4; + else if (fi.FieldType == typeof(byte)) { pst = SType.I4; kind = 1; } + else if (fi.FieldType == typeof(sbyte)) { pst = SType.I4; kind = 2; } + else if (fi.FieldType == typeof(ushort)) { pst = SType.I4; kind = 3; } + else if (fi.FieldType == typeof(short)) { pst = SType.I4; kind = 4; } + else if (fi.FieldType.IsEnum && Enum.GetUnderlyingType(fi.FieldType) == typeof(int)) pst = SType.I4; + else pst = SType.O; + + layout.Fields[fi.Name] = (byteOffset, pst); + if (kind != 0) (layout.FieldKinds ??= new Dictionary())[fi.Name] = kind; + + if (!_fields.TryGetValue(key, out var fe)) continue; + fe.DeclaringStruct = layout; + fe.ByteOffset = byteOffset; + fe.PrimitiveSt = pst; + fe.PrimitiveKind = kind; + } + _structLayouts[typeName] = layout; + _structLayoutsByType[type] = layout; + MarkTrivialAccessors(type, layout); + } + + // IL-verify each public property accessor of a flat struct as a single backing-field + // access; matches get {ldarg.0; ldfld f; ret} and set {ldarg.0; ldarg.1; stfld f; ret} + // (the exact Release shape of Rect.width-style wrappers). Verified accessors get their + // backing field's byte offset stamped on the Entry so the lowerer can inline them. + void MarkTrivialAccessors(Type type, StructLayout layout) + { + var tn = type.Name; + foreach (var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)) + { + // Offsets come straight from the backing FieldInfo — layout.Fields only carries + // PUBLIC fields, and Rect-style backing fields (m_Width) are private. + var g = prop.GetMethod; + if (g != null && TryReadIl(g, out var gil) + && TryMatchAccessorIl(gil, g, isSetter: false, out var gfld) + && TryAccessorField(type, layout, gfld, out int gOff, out SType gSt, out var gVtLay) + && _entries.TryGetValue($"{tn}.get_{prop.Name}/0", out var gentry)) + { + gentry.AccessorOffset = gOff; + gentry.AccessorSt = gSt; + gentry.AccessorVtLayout = gVtLay; + } + var st = prop.SetMethod; + if (st != null && TryReadIl(st, out var sil) + && TryMatchAccessorIl(sil, st, isSetter: true, out var sfld) + && TryAccessorField(type, layout, sfld, out int sOff, out SType sSt, out var sVtLay) + && _entries.TryGetValue($"{tn}.set_{prop.Name}/1", out var sentry)) + { + sentry.AccessorOffset = sOff; + sentry.AccessorSt = sSt; + sentry.AccessorVtLayout = sVtLay; + } + } + } + + bool TryAccessorField(Type type, StructLayout layout, FieldInfo fld, out int off, out SType st, + out StructLayout? vtLay) + { + off = 0; st = SType.O; vtLay = null; + if (fld.DeclaringType != type) return false; + var ft = fld.FieldType; + int fieldSize = 4; + if (ft == typeof(float)) st = SType.R4; + else if (ft == typeof(int) || ft == typeof(uint) + || (ft.IsEnum && Enum.GetUnderlyingType(ft) == typeof(int))) st = SType.I4; + // Struct-typed backing field (Bounds.m_Center : Vector3) with a flat layout of its own: + // the accessor becomes a byte-range copy. The field type must already be registered flat — + // curated types are (Vector3 precedes any auto-bound consumer in CreateStandard). + else if (ft.IsValueType && !ft.IsEnum && _structLayoutsByType.TryGetValue(ft, out vtLay)) + { st = SType.Vt; fieldSize = vtLay.Size; } + else return false; + try { off = (int)Marshal.OffsetOf(type, fld.Name); } + catch (Exception) { return false; } + return off >= 0 && off + fieldSize <= layout.Size; + } + + static bool TryMatchAccessorIl(byte[] il, MethodBase scope, bool isSetter, out FieldInfo field) + { + field = null!; + int idx = 0; + if (!ExpectLdarg(il, ref idx, 0)) return false; + if (isSetter && !ExpectLdarg(il, ref idx, 1)) return false; + byte opByte = isSetter ? (byte)0x7D /* stfld */ : (byte)0x7B /* ldfld */; + if (idx + 5 > il.Length || il[idx] != opByte) return false; + int tok = BitConverter.ToInt32(il, idx + 1); + idx += 5; + if (idx + 1 != il.Length || il[idx] != 0x2A /* ret */) return false; + try { field = (FieldInfo)scope.Module.ResolveField(tok)!; } + catch (Exception) { return false; } + return field != null; + } + + // Optimization: replace the reflective float/int field accessors with Unsafe.Unbox-based ones + // (~2 ns vs ~23 ns) for boxed-struct field access. Requires `where T : struct` (Unsafe.Unbox), + // so it's only installed via AllowTypeStruct(); AllowType auto-promotion keeps the (correct, + // slower) reflective accessors for the rare boxed-field case. Run after BuildStructLayoutCore. + void InstallUnsafeStructFieldAccessors() where T : struct + { +#if ILINTERPRETER_UNSAFE_UNBOX + var type = typeof(T); + var typeName = type.Name; + var instBind = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly; + foreach (var fi in type.GetFields(instBind)) + { + if (!_fields.TryGetValue($"{typeName}.{fi.Name}", out var fe)) continue; + int off = fe.ByteOffset; + if (fi.FieldType == typeof(float)) + { + fe.Get = obj => (object)Unsafe.ReadUnaligned(ref Unsafe.Add(ref Unsafe.As(ref Unsafe.Unbox(obj!)), off)); + fe.Set = (obj, val) => Unsafe.WriteUnaligned(ref Unsafe.Add(ref Unsafe.As(ref Unsafe.Unbox(obj!)), off), val is float f ? f : val is int i ? (float)i : 0f); + RuntimeHelpers.PrepareDelegate(fe.Get); + RuntimeHelpers.PrepareDelegate(fe.Set); + } + else if (fi.FieldType == typeof(int)) + { + fe.Get = obj => (object)Unsafe.ReadUnaligned(ref Unsafe.Add(ref Unsafe.As(ref Unsafe.Unbox(obj!)), off)); + fe.Set = (obj, val) => Unsafe.WriteUnaligned(ref Unsafe.Add(ref Unsafe.As(ref Unsafe.Unbox(obj!)), off), val is int i ? i : 0); + RuntimeHelpers.PrepareDelegate(fe.Get); + RuntimeHelpers.PrepareDelegate(fe.Set); + } + } +#else + // Unity's bundled System.Runtime.CompilerServices.Unsafe predates Unsafe.Unbox (added in + // 6.0), so the boxed-struct fast path won't compile here. The reflective float/int accessors + // installed by AllowTypeWithBases stay in place — correct, just slower for boxed-struct field + // access (the flat VM path uses byte offsets directly and is unaffected). Define + // ILINTERPRETER_UNSAFE_UNBOX (and supply a 6.0+ Unsafe) to restore the optimization. +#endif + } + + internal bool TryGetStructLayout(string typeName, out StructLayout? layout) => + _structLayouts.TryGetValue(typeName, out layout); + + internal bool TryGetStructLayout(Type type, out StructLayout? layout) => + _structLayoutsByType.TryGetValue(type, out layout); + + // Verify and mark operators/ctors the lowerer may INLINE as per-field arithmetic + // (EmitInlinedOp). Marking is only safe when the IL is STRUCTURALLY component-wise — + // "uses only pure opcodes" is not enough (a Quaternion-style op_Multiply is pure IL but + // not per-field, and name-driven synthesis would silently mis-evaluate it). The verifier + // accepts exactly: + // operator: for each field f_i in layout order: ARITH — where a + // struct param contributes `ldarg.k; ldfld f_i` and a scalar param `ldarg.k` + // (unary: `ldarg.0; ldfld f_i; neg`) — then `newobj ; ret`. + // ctor: for each field f_i: `ldarg.0; ldarg.(i+1); stfld f_i` — then `ret`. + // Anything else (locals, branches, calls, reordered fields, debug-shaped IL) degrades to + // the normal call path. warnOnReject keeps the explicit AllowTypeStruct(operatorsArePure) + // opt-in loud while the automatic flatten path stays quiet. + void InspectAndMarkOperators(Type type, bool warnOnReject = true) + { + if (!_structLayoutsByType.TryGetValue(type, out var lay) || lay == null) return; + var fieldOrder = FieldOrderByOffset(type, lay); + if (fieldOrder == null) return; // non-numeric or unresolvable fields — nothing to inline + + var statBind = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly; + (string Name, byte Arith)[] ops = + { + ("op_Addition", (byte)0x58), ("op_Subtraction", (byte)0x59), + ("op_Multiply", (byte)0x5A), ("op_Division", (byte)0x5B), + ("op_UnaryNegation", (byte)0x65), + }; + foreach (var (opName, arith) in ops) + { + // Overloads of one operator (e.g. op_Multiply(V3,float) and (float,V3)) share ONE + // Entry, and the entry-level flag can't distinguish them — so mark only when EVERY + // overload verifies; a single unverified sibling would otherwise inline with the + // verified overload's semantics. + bool any = false, all = true; + foreach (var m in type.GetMethods(statBind)) + { + if (m.Name != opName) continue; + any = true; + if (m.ReturnType == type + && VerifyComponentwiseOperator(m, type, fieldOrder, arith, out var ctorUsed) + && ctorUsed != null && VerifyFieldOrderCtor(ctorUsed, fieldOrder)) + continue; + all = false; + if (warnOnReject) + Warn($"[IlInterpreter] operator {m.Name} on {type.Name} is not component-wise field arithmetic — not inlined (falls back to the call path)"); + } + if (any && all) + { + foreach (var m in type.GetMethods(statBind)) + if (m.Name == opName && _byHandle.TryGetValue(m.MethodHandle.Value, out var entry)) + entry.IsInlineableOp = true; + } + } + // The all-fields, field-order ctor: `new V3(x, y, z)` inlines to per-field stores. + foreach (var ctor in type.GetConstructors(BindingFlags.Public | BindingFlags.Instance)) + { + var ps = ctor.GetParameters(); + if (ps.Length != fieldOrder.Length) continue; + if (!VerifyFieldOrderCtor(ctor, fieldOrder)) continue; + var key = $"{type.Name}..ctor/{ps.Length}"; + if (_entries.TryGetValue(key, out var ctorEntry)) + ctorEntry.IsInlineableOp = true; + } + } + + // The struct's instance fields sorted by flat byte offset. Null when any field is missing + // from the layout or is not a 4-byte numeric (the inliner emits I4/R4 arithmetic only). + FieldInfo[]? FieldOrderByOffset(Type type, StructLayout lay) + { + var fis = type.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); + if (fis.Length == 0 || fis.Length != lay.Fields.Count) return null; + var order = new FieldInfo[fis.Length]; + var offs = new int[fis.Length]; + for (int i = 0; i < fis.Length; i++) + { + if (!lay.Fields.TryGetValue(fis[i].Name, out var e)) return null; + if (e.St != SType.I4 && e.St != SType.R4) return null; + // Sub-4 field: the inliner's per-field 4-byte ops would read/clobber neighbors. + if (lay.FieldKinds != null && lay.FieldKinds.ContainsKey(fis[i].Name)) return null; + order[i] = fis[i]; offs[i] = e.Offset; + } + for (int a = 0; a < order.Length - 1; a++) + for (int b = a + 1; b < order.Length; b++) + if (offs[b] < offs[a]) + { + (offs[a], offs[b]) = (offs[b], offs[a]); + (order[a], order[b]) = (order[b], order[a]); + } + return order; + } + + static bool TryReadIl(MethodBase m, out byte[] il) + { + il = Array.Empty(); + try + { + var body = m.GetMethodBody(); + if (body == null) return false; + var bytes = body.GetILAsByteArray(); + if (bytes == null || bytes.Length == 0) return false; + il = bytes; + return true; + } + catch (Exception) { return false; } // AOT runtimes may throw instead of returning null + } + + static bool ExpectLdarg(byte[] il, ref int idx, int argIndex) + { + if (idx >= il.Length) return false; + byte b = il[idx]; + if (argIndex <= 3 && b == (byte)(0x02 + argIndex)) { idx++; return true; } + if (b == 0x0E && idx + 1 < il.Length && il[idx + 1] == argIndex) { idx += 2; return true; } // ldarg.s + return false; + } + + static bool ExpectFieldToken(byte[] il, ref int idx, byte opByte, MethodBase scope, FieldInfo want) + { + if (idx + 5 > il.Length || il[idx] != opByte) return false; + int tok = BitConverter.ToInt32(il, idx + 1); + idx += 5; + if (tok == want.MetadataToken) return true; // FieldDef in the same module — the common case + try { return scope.Module.ResolveField(tok) == want; } + catch (Exception) { return false; } + } + + bool VerifyComponentwiseOperator(MethodInfo m, Type type, FieldInfo[] fieldOrder, byte arith, + out ConstructorInfo? ctor) + { + ctor = null; + if (!TryReadIl(m, out var il)) return false; + var ps = m.GetParameters(); + if (ps.Length < 1 || ps.Length > 2) return false; + bool anyStruct = false; + var isStructArg = new bool[ps.Length]; + for (int a = 0; a < ps.Length; a++) + { + var pt = ps[a].ParameterType; + if (pt == type) { isStructArg[a] = true; anyStruct = true; } + else if (pt != typeof(float) && pt != typeof(int)) return false; + } + if (!anyStruct) return false; + + int idx = 0; + for (int f = 0; f < fieldOrder.Length; f++) + { + for (int a = 0; a < ps.Length; a++) + { + if (!ExpectLdarg(il, ref idx, a)) return false; + if (isStructArg[a] && !ExpectFieldToken(il, ref idx, 0x7B /* ldfld */, m, fieldOrder[f])) return false; + } + if (idx >= il.Length || il[idx++] != arith) return false; + } + if (idx + 5 > il.Length || il[idx] != 0x73 /* newobj */) return false; + int ctorTok = BitConverter.ToInt32(il, idx + 1); + idx += 5; + ConstructorInfo? cb; + try { cb = m.Module.ResolveMethod(ctorTok) as ConstructorInfo; } + catch (Exception) { return false; } + if (cb == null || cb.DeclaringType != type) return false; + if (idx + 1 != il.Length || il[idx] != 0x2A /* ret */) return false; + ctor = cb; + return true; + } + + bool VerifyFieldOrderCtor(ConstructorInfo ctor, FieldInfo[] fieldOrder) + { + if (ctor.GetParameters().Length != fieldOrder.Length) return false; + if (!TryReadIl(ctor, out var il)) return false; + int idx = 0; + for (int f = 0; f < fieldOrder.Length; f++) + { + if (!ExpectLdarg(il, ref idx, 0)) return false; // this + if (!ExpectLdarg(il, ref idx, f + 1)) return false; // param f + if (!ExpectFieldToken(il, ref idx, 0x7D /* stfld */, ctor, fieldOrder[f])) return false; + } + return idx + 1 == il.Length && il[idx] == 0x2A /* ret */; + } + + HostBinding AllowTypeWithBases(Type type) + { + var t = type; + while (t != null && t != typeof(object) && t != typeof(ValueType)) + { + if (!t.IsGenericTypeDefinition && _registeredTypes.Add(t)) + { + if (t.IsGenericType) + { + var args = t.GetGenericArguments(); + var key = (t.Name, args[0].Name); + if (!_genericTypes.ContainsKey(key)) + _genericTypes[key] = t; + } + AllowTypeImpl(t); + } + t = t.BaseType; + } + return this; + } + + HostBinding AllowTypeImpl(Type type) + { + var name = type.Name; + var instBind = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly; + var statBind = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly; + + foreach (var f in type.GetFields(instBind)) + { + if (SkipType(f.FieldType)) continue; + RegisterField(name, f); + } + + // Static fields (ldsfld/stsfld both dispatch through FieldEntry). fi.GetValue(null)/SetValue(null, v) + // work whether obj is null or not for a static, so the same RegisterField marshalling applies. + foreach (var f in type.GetFields(statBind)) + { + if (SkipType(f.FieldType)) continue; + RegisterField(name, f); + } + + // Instance properties → get_Prop / set_Prop method calls. Accessor arity comes from the + // accessor itself, NOT a plain-property assumption: an INDEXER's get_Item takes the index + // (set_Item takes index + value). Hardcoding 0/1 registered `get_Item/0` whose entry + // popped no argument — the call site then read the index as the RECEIVER + // (`root[root.childCount-1]` failed with "cannot run on a receiver of type Int32"). + foreach (var p in type.GetProperties(instBind)) + { + if (SkipType(p.PropertyType)) continue; + if (p.GetMethod != null && !SkipMethod(p.GetMethod)) + { + var g = p.GetMethod; + var gp = g.GetParameters(); + if (gp.Length == 0) + Allow(name, g.Name, (recv, _) => g.Invoke(recv, null), 0, mi: g); + else + Allow(name, g.Name, (recv, args) => g.Invoke(recv, args), gp.Length, gp, mi: g); + } + if (p.SetMethod != null && !SkipMethod(p.SetMethod)) + { + var s = p.SetMethod; + var spms = s.GetParameters(); + Allow(name, s.Name, (recv, args) => { s.Invoke(recv, args); return null; }, spms.Length, spms, mi: s); + } + } + + foreach (var p in type.GetProperties(statBind)) + { + if (SkipType(p.PropertyType)) continue; + if (p.GetMethod != null && !SkipMethod(p.GetMethod)) + { + var g = p.GetMethod; + AllowStatic(name, g.Name, (_, _2) => g.Invoke(null, null), 0, mi: g); + } + if (p.SetMethod != null && !SkipMethod(p.SetMethod)) + { + var s = p.SetMethod; + AllowStatic(name, s.Name, (_, args) => { s.Invoke(null, args); return null; }, 1, s.GetParameters(), mi: s); + } + } + + RegisterMethods(type.GetMethods(instBind), name, isStatic: false); + RegisterMethods(type.GetMethods(statBind), name, isStatic: true); + + // Operator methods (op_Addition, op_Multiply, op_UnaryNegation, etc.) + // Group by name so overloads (e.g. Vector3*float and float*Vector3) can be dispatched + // at call-time by checking the runtime type of the first argument. + var opByName = new Dictionary>(); + foreach (var m in type.GetMethods(statBind)) + { + if (!m.IsSpecialName || !m.Name.StartsWith("op_", StringComparison.Ordinal)) continue; + if (SkipMethod(m)) continue; + if (!opByName.TryGetValue(m.Name, out var lst)) opByName[m.Name] = lst = new List(); + lst.Add(m); + } + foreach (var (opName, overloads) in opByName) + { + if (overloads.Count == 1) + { + var method = overloads[0]; + var mp = method.GetParameters(); + AllowStatic(name, opName, (_, args) => method.Invoke(null, args), mp.Length, mp, mi: method); + } + else if (overloads.Count == 2) + { + // Two overloads: find first param index where signatures diverge, dispatch on that. + // Using args[0] alone breaks when both overloads share the same first-arg type + // (e.g. op_Multiply(Quaternion,Quaternion) vs op_Multiply(Quaternion,Vector3)). + var m0 = overloads[0]; + var m1 = overloads[1]; + var p0 = m0.GetParameters(); + var p1 = m1.GetParameters(); + int dispatchIdx = 0; + for (int i = 0; i < p0.Length; i++) + if (p0[i].ParameterType != p1[i].ParameterType) { dispatchIdx = i; break; } + var tDispatch = p0[dispatchIdx].ParameterType; + AllowStatic(name, opName, (_, args) => + { + var pick = args[dispatchIdx]?.GetType() == tDispatch ? m0 : m1; + return pick.Invoke(null, args); + }, p0.Length, mi: m0); + _byHandle[m1.MethodHandle.Value] = _byHandle[m0.MethodHandle.Value]; + } + else + { + // 3+ overloads (StyleLength.op_Implicit(float | Length | StyleKeyword)): the + // aliased-pair Fast machinery above doesn't scale past two, so these were + // skipped entirely — leaving the operator unbound whenever the call site's + // signature didn't decode. Register a name-keyed dispatcher like the same-arity + // ctor one: pick by the args' runtime types, coerce boxed ints after the pick. + // Deliberately NOT put in _byHandle (no mi): a call site that resolves its exact + // MethodInfo synthesizes a per-overload fallback entry instead, and the + // Fast/inline builders (which attach per-handle) never see this reflective entry. + var byArity = new Dictionary>(); + foreach (var m in overloads) + { + int n = m.GetParameters().Length; + if (!byArity.TryGetValue(n, out var lst)) byArity[n] = lst = new List(); + lst.Add(m); + } + foreach (var (arity, group) in byArity) + { + if (group.Count == 1) + { + var m = group[0]; + var mp = m.GetParameters(); + AllowStatic(name, opName, (_, args) => m.Invoke(null, args), arity, mp, mi: m); + continue; + } + var all = group.ToArray(); + var pss = new ParameterInfo[all.Length][]; + for (int i = 0; i < all.Length; i++) pss[i] = all[i].GetParameters(); + AllowStatic(name, opName, (_, args) => + { + int pick = PickOverloadByArgs(pss, args); + if (pick < 0) pick = 0; + CoerceArgs(args, pss[pick]); + return all[pick].Invoke(null, args); + }, arity); + } + } + } + + var ctors = type.GetConstructors(BindingFlags.Public | BindingFlags.Instance); + var ctorGroups = new Dictionary>(); + foreach (var ctor in ctors) + { + if (SkipMethod(ctor)) continue; + int n = ctor.GetParameters().Length; + if (!ctorGroups.TryGetValue(n, out var lst)) ctorGroups[n] = lst = new List(); + lst.Add(ctor); + } + foreach (var (arity, overloads) in ctorGroups) + { + if (overloads.Count == 1) + { + var ctor = overloads[0]; + var cp = ctor.GetParameters(); + AllowConstructor(name, (_, args) => ctor.Invoke(args), arity, cp, ctor); + continue; + } + // Same-arity overloads (e.g. StyleLength(float | Length | StyleKeyword)): one entry + // that picks the overload by the args' runtime types at call time. Entry.Params stays + // null — the boxed-int coercions depend on WHICH overload wins, so the delegate + // coerces after picking instead of letting Entry.Invoke coerce up front. + var all = overloads.ToArray(); + var pss = new ParameterInfo[all.Length][]; + for (int i = 0; i < all.Length; i++) pss[i] = all[i].GetParameters(); + AllowConstructor(name, (_, args) => + { + int pick = PickOverloadByArgs(pss, args); + if (pick < 0) pick = 0; + CoerceArgs(args, pss[pick]); + return all[pick].Invoke(args); + }, arity, ci: all[0]); + } + + return this; + } + + // Index of the same-arity overload whose parameters best accept the runtime args, -1 when + // none fits. Exact type matches outscore coercible ones, so `(float)` vs `(MyEnum)` resolves + // to float for a boxed float and to MyEnum for a boxed int — every I4-slot value (int, bool, + // enum, …) crosses the boundary as a boxed int, so an int arg matches any CoerceArgs target. + // Null args match any reference-type parameter. + static int PickOverloadByArgs(ParameterInfo[][] pss, object?[] args) + { + int best = -1, bestScore = -1; + for (int c = 0; c < pss.Length; c++) + { + var ps = pss[c]; + int score = 0; bool ok = true; + for (int i = 0; i < ps.Length && ok; i++) + { + var pt = ps[i].ParameterType; + var a = i < args.Length ? args[i] : null; + if (a == null) { ok = !pt.IsValueType; continue; } + var at = a.GetType(); + if (at == pt) { score += 2; continue; } + if (a is int && (pt.IsEnum || pt == typeof(bool) || pt == typeof(char) + || pt == typeof(byte) || pt == typeof(sbyte) + || pt == typeof(short) || pt == typeof(ushort) + || pt == typeof(uint))) + { score += 1; continue; } + if (pt.IsAssignableFrom(at)) { score += 1; continue; } + ok = false; + } + if (ok && score > bestScore) { best = c; bestScore = score; } + } + return best; + } + + // Build typed-delegate fast paths for all operators and methods on T that match a known + // signature shape: replaces the MethodInfo.Invoke-based Delegate with a typed closure and + // populates Entry.Fast so the interpreter can bypass ArgBuf + Entry.Invoke entirely. + // + // Called only from AllowType() where T is a concrete type known at compile time — that's + // the AOT-safety guarantee: every generic instantiation here is written explicitly; no + // MakeGenericMethod calls happen at call time. + void BuildTypedDelegates() + { + var type = typeof(T); + bool isRef = !type.IsValueType; // open-instance delegates require reference receiver + // FastIsFlat can only be set when T has a StructLayout — without one the lowerer + // can't allocate a Vt dst slot, and the flat-write closure would scribble into a + // boxed-result O slot. AllowType alone (no AllowTypeStruct) leaves T flat-incapable. + bool flatOk = type.IsValueType && _structLayoutsByType.ContainsKey(type); + var statBind = BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly; + var instBind = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly; + + // Safe slot readers used by Fast delegates — a slot's actual frame depends on slotT. + static float RF(byte* num, object?[] ref_, SType[] slotT, int s) + { + var t = slotT[s - FastFrameBase]; + if (t == SType.R4) return Unsafe.ReadUnaligned(num + (s * 4)); + if (t == SType.I4) return (float)Unsafe.ReadUnaligned(num + (s * 4)); + if (t == SType.Vt) return 0f; // Vt refFrame entries are not cleared; never read them + var v = ref_[s]; return v is float f ? f : v is int i ? (float)i : 0f; + } + static int RI(byte* num, object?[] ref_, SType[] slotT, int s) + { + var t = slotT[s - FastFrameBase]; + if (t == SType.I4) return Unsafe.ReadUnaligned(num + (s * 4)); + if (t == SType.R4) return (int)Unsafe.ReadUnaligned(num + (s * 4)); + if (t == SType.Vt) return 0; // Vt refFrame entries are not cleared; never read them + var v = ref_[s]; return v is int i ? i : v is bool b ? (b?1:0) : 0; + } + // Generic Vt-or-boxed reader for value-type T. Picks flat bytes when the slot is Vt + // (Stage 2 fast path) or unboxes the refFrame entry otherwise (compatibility with + // boxed args that flow in from ldfld_o on a class field). + static TVal RT(byte* num, object?[] ref_, SType[] slotT, int s) + { + if (slotT[s - FastFrameBase] == SType.Vt) return Unsafe.ReadUnaligned(num + (s * 4)); + return (TVal)ref_[s]!; + } + + // --- Static operators and methods --- + // T args (including struct types) always live in refFrame O-slots: host call returns are + // allocated as SType.O (AllocSlot(..., SType.O) in the lowerer), and there is no slot + // reuse — every AllocSlot call creates a fresh slot with a fixed type for the method's + // lifetime. So ref_[s] is the correct way to read a T arg regardless of IsValueType. + // + // Overloaded operators aliased in AllowTypeImpl (e.g. op_Multiply(V3,float) and + // op_Multiply(float,V3)) share a single Entry. We handle them separately below: + // collect the two overloads, build typed delegates for each, then attach a Fast that + // dispatches by whether ref_[s0] is T (true → T-first overload, false → float-first). + var seenMethods = new Dictionary>(EntryReferenceComparer.Instance); + foreach (var m in type.GetMethods(statBind)) + { + if (m.IsGenericMethodDefinition) continue; + if (!_byHandle.TryGetValue(m.MethodHandle.Value, out var e2)) continue; + if (!seenMethods.TryGetValue(e2, out var lst)) seenMethods[e2] = lst = new List(); + lst.Add(m); + } + foreach (var (entry, methods) in seenMethods) + { + if (methods.Count == 2) + { + // Aliased pair: two overloads sharing one Entry. Build per-overload typed delegates + // and a Fast that dispatches by whether the first arg is T. + var mA = methods[0]; var mB = methods[1]; + var psA = mA.GetParameters(); var psB = mB.GetParameters(); + var rtA = mA.ReturnType; + bool aIsTV = psA[0].ParameterType == type; + bool bIsTV = psB[0].ParameterType == type; + + // (T,float)→T + (float,T)→T — the common operator*(V3,float) + operator*(float,V3) case. + // Guard aIsTV != bIsTV: pairs like (Color,Color)+(Color,float) both have T first and must + // not enter this path — the wrong method would be passed to CreateDelegate. + if (psA.Length == 2 && rtA == type && rtA == mB.ReturnType && aIsTV != bIsTV) + { + var mTF = aIsTV ? mA : mB; var mFT = aIsTV ? mB : mA; + var delTF = (Func)Delegate.CreateDelegate(typeof(Func), mTF); + var delFT = (Func)Delegate.CreateDelegate(typeof(Func), mFT); + entry.Delegate = (_, a) => a[0] is T tv + ? (object)delTF(tv, (float)a[1]!)! + : (object)delFT((float)a[0]!, (T)a[1]!)!; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int s0 = bp + (int)ir[argBase], s1 = bp + (int)ir[argBase + 1]; + if (ref_[s0] is T t0) ref_[bp + dst] = delTF(t0, RF(num, ref_, slotT, s1)); + else ref_[bp + dst] = delFT(RF(num, ref_, slotT, s0), (T)ref_[s1]!); + }; + if (flatOk) + { + entry.FastIsFlat = true; entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int s0 = bp + (int)ir[argBase], s1 = bp + (int)ir[argBase + 1]; + // Dispatch by which arg looks like T (Vt slot or boxed T). + // Either arg may be a boxed T arriving from an ldfld_o on a class field, + // so RT handles both Vt and refFrame paths. + bool s0IsT = slotT[s0 - FastFrameBase] == SType.Vt + ? true + : ref_[s0] is T; + if (s0IsT) + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + delTF(RT(num, ref_, slotT, s0), RF(num, ref_, slotT, s1))); + else + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + delFT(RF(num, ref_, slotT, s0), RT(num, ref_, slotT, s1))); + }; + } + } + + // (T,T)→T + (T,float)→T — Color-like: same first arg, dispatch on second arg type. + // Both overloads must return T and have T as first arg. Second arg is T for one, float for other. + // Scoped to same-return-type pairs only (differing-return Quaternion case stays on slow path). + if (psA.Length == 2 && rtA == type && mB.ReturnType == type && aIsTV && bIsTV) + { + bool aTT = psA[1].ParameterType == type; + bool bTT = psB[1].ParameterType == type; + bool aTF = psA[1].ParameterType == typeof(float); + bool bTF = psB[1].ParameterType == typeof(float); + if ((aTT && bTF) || (aTF && bTT)) + { + var mTT = aTT ? mA : mB; var mTF = aTT ? mB : mA; + var delTT = (Func)Delegate.CreateDelegate(typeof(Func), mTT); + var delTF = (Func)Delegate.CreateDelegate(typeof(Func), mTF); + entry.Delegate = (_, a) => a[1] is T t1 + ? (object)delTT((T)a[0]!, t1)! + : (object)delTF((T)a[0]!, (float)a[1]!)!; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int s0 = bp + (int)ir[argBase], s1 = bp + (int)ir[argBase + 1]; + if (ref_[s1] is T t1v) ref_[bp + dst] = delTT((T)ref_[s0]!, t1v); + else ref_[bp + dst] = delTF((T)ref_[s0]!, RF(num, ref_, slotT, s1)); + }; + if (flatOk) + { + entry.FastIsFlat = true; entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int s0 = bp + (int)ir[argBase], s1 = bp + (int)ir[argBase + 1]; + if (slotT[s1 - FastFrameBase] == SType.Vt) + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + delTT(RT(num, ref_, slotT, s0), RT(num, ref_, slotT, s1))); + else + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + delTF(RT(num, ref_, slotT, s0), RF(num, ref_, slotT, s1))); + }; + } + } + } + continue; + } + + // Single overload — build typed Delegate + Fast. + var method = methods[0]; + var ps = method.GetParameters(); + var rt = method.ReturnType; + + // (T, T) → T e.g. op_Addition(V3, V3) → V3 + if (ps.Length == 2 && ps[0].ParameterType == type && ps[1].ParameterType == type && rt == type) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), method); + entry.Delegate = (_, a) => (object)del((T)a[0]!, (T)a[1]!)!; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int s0 = bp + (int)ir[argBase], s1 = bp + (int)ir[argBase + 1]; + ref_[bp + dst] = del((T)ref_[s0]!, (T)ref_[s1]!); + }; + if (flatOk) + { + entry.FastIsFlat = true; entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int s0 = bp + (int)ir[argBase], s1 = bp + (int)ir[argBase + 1]; + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + del(RT(num, ref_, slotT, s0), + RT(num, ref_, slotT, s1))); + }; + } + continue; + } + + // (T, float) → T e.g. op_Multiply(V3, float) → V3 + if (ps.Length == 2 && ps[0].ParameterType == type && ps[1].ParameterType == typeof(float) && rt == type) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), method); + entry.Delegate = (_, a) => (object)del((T)a[0]!, (float)a[1]!)!; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int s0 = bp + (int)ir[argBase], s1 = bp + (int)ir[argBase + 1]; + ref_[bp + dst] = del((T)ref_[s0]!, RF(num, ref_, slotT, s1)); + }; + if (flatOk) + { + entry.FastIsFlat = true; entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int s0 = bp + (int)ir[argBase], s1 = bp + (int)ir[argBase + 1]; + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + del(RT(num, ref_, slotT, s0), + RF(num, ref_, slotT, s1))); + }; + } + continue; + } + + // (float, T) → T e.g. op_Multiply(float, V3) → V3 + if (ps.Length == 2 && ps[0].ParameterType == typeof(float) && ps[1].ParameterType == type && rt == type) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), method); + entry.Delegate = (_, a) => (object)del((float)a[0]!, (T)a[1]!)!; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int s0 = bp + (int)ir[argBase], s1 = bp + (int)ir[argBase + 1]; + ref_[bp + dst] = del(RF(num, ref_, slotT, s0), (T)ref_[s1]!); + }; + if (flatOk) + { + entry.FastIsFlat = true; entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int s0 = bp + (int)ir[argBase], s1 = bp + (int)ir[argBase + 1]; + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + del(RF(num, ref_, slotT, s0), + RT(num, ref_, slotT, s1))); + }; + } + continue; + } + + // (T, T) → int e.g. op_Equality, op_LessThan returning bool (int in script) + if (ps.Length == 2 && ps[0].ParameterType == type && ps[1].ParameterType == type + && (rt == typeof(int) || rt == typeof(bool))) + { + if (rt == typeof(bool)) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), method); + entry.Delegate = (_, a) => del((T)a[0]!, (T)a[1]!) ? (object)1 : 0; + // FastIsFlat: write 1/0 int directly into numFrame, no boxing. An int result is + // always flat-safe, so no non-flat fallback is needed (RT reads either frame). + entry.FastIsFlat = true; entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int s0 = bp + (int)ir[argBase], s1 = bp + (int)ir[argBase + 1]; + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + del(RT(num, ref_, slotT, s0), RT(num, ref_, slotT, s1)) ? 1 : 0); + }; + } + else + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), method); + entry.Delegate = (_, a) => (object)del((T)a[0]!, (T)a[1]!); + // FastIsFlat: write int directly into numFrame (always flat-safe). + entry.FastIsFlat = true; entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int s0 = bp + (int)ir[argBase], s1 = bp + (int)ir[argBase + 1]; + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + del(RT(num, ref_, slotT, s0), RT(num, ref_, slotT, s1))); + }; + } + continue; + } + + // (T) → float e.g. Vector3.Magnitude + if (ps.Length == 1 && ps[0].ParameterType == type && rt == typeof(float)) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), method); + entry.Delegate = (_, a) => (object)del((T)a[0]!); + entry.FastIsFlat = true; entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int s0 = bp + (int)ir[argBase]; + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), del(RT(num, ref_, slotT, s0))); + }; + continue; + } + + // (T, T) → float e.g. Vector3.Dot, Vector3.Distance + if (ps.Length == 2 && ps[0].ParameterType == type && ps[1].ParameterType == type && rt == typeof(float)) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), method); + entry.Delegate = (_, a) => (object)del((T)a[0]!, (T)a[1]!); + entry.FastIsFlat = true; entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int s0 = bp + (int)ir[argBase], s1 = bp + (int)ir[argBase + 1]; + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + del(RT(num, ref_, slotT, s0), RT(num, ref_, slotT, s1))); + }; + continue; + } + + // (T) → T e.g. op_UnaryNegation(V3) → V3 + if (ps.Length == 1 && ps[0].ParameterType == type && rt == type) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), method); + entry.Delegate = (_, a) => (object)del((T)a[0]!)!; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int s0 = bp + (int)ir[argBase]; + ref_[bp + dst] = del((T)ref_[s0]!); + }; + if (flatOk) + { + entry.FastIsFlat = true; entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int s0 = bp + (int)ir[argBase]; + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + del(RT(num, ref_, slotT, s0))); + }; + } + continue; + } + + // () → T e.g. static factory like V3.Zero (rare; no args) + if (ps.Length == 0 && rt == type) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), method); + entry.Delegate = (_, _) => (object)del()!; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => ref_[bp + dst] = del(); + if (flatOk) + { + entry.FastIsFlat = true; entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), del()); + } + continue; + } + + // (float, float) → float e.g. Vector2.Dot, Distance etc. + if (ps.Length == 2 && ps[0].ParameterType == typeof(float) && ps[1].ParameterType == typeof(float) && rt == typeof(float)) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), method); + entry.Delegate = (_, a) => (object)del((float)a[0]!, (float)a[1]!); + entry.FastIsFlat = true; entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int s0 = bp + (int)ir[argBase], s1 = bp + (int)ir[argBase + 1]; + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + del(RF(num, ref_, slotT, s0), RF(num, ref_, slotT, s1))); + }; + continue; + } + + // (float) → float e.g. Mathf.Sqrt, Abs, Cos, Sin etc. + if (ps.Length == 1 && ps[0].ParameterType == typeof(float) && rt == typeof(float)) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), method); + entry.Delegate = (_, a) => (object)del((float)a[0]!); + entry.FastIsFlat = true; entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + del(RF(num, ref_, slotT, bp + (int)ir[argBase]))); + continue; + } + + // (int) → int e.g. Math.Abs(int), Math.Sign(int) + if (ps.Length == 1 && ps[0].ParameterType == typeof(int) && rt == typeof(int)) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), method); + entry.Delegate = (_, a) => (object)del((int)a[0]!); + entry.FastIsFlat = true; entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + del(RI(num, ref_, slotT, bp + (int)ir[argBase]))); + continue; + } + + // (int, int) → int e.g. Math.Min(int,int), Math.Max(int,int) + if (ps.Length == 2 && ps[0].ParameterType == typeof(int) && ps[1].ParameterType == typeof(int) && rt == typeof(int)) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), method); + entry.Delegate = (_, a) => (object)del((int)a[0]!, (int)a[1]!); + entry.FastIsFlat = true; entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int s0 = bp + (int)ir[argBase], s1 = bp + (int)ir[argBase + 1]; + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + del(RI(num, ref_, slotT, s0), RI(num, ref_, slotT, s1))); + }; + continue; + } + } + + // --- Constructors for value-type T: build flat-write delegates for the common shapes. + // Optimisation: when every param matches a same-named primitive field on T, we bypass + // ConstructorInfo.Invoke entirely and write the fields' bytes directly into numFrame at + // their layout offsets. This is what V3(float,float,float) — the bench's hot path — looks + // like in practice. The fallback uses ctor.Invoke on a temp args array (slow but correct + // for ctors that do non-trivial work). + if (type.IsValueType + && _structLayoutsByType.TryGetValue(type, out var ctorLayout)) + { + var ctors = type.GetConstructors(BindingFlags.Public | BindingFlags.Instance); + // Entries key ctors by NAME/ARITY, and Entry.Invoke dispatches same-arity overloads + // by runtime arg type. A Fast closure binds ONE ConstructorInfo, so installing it on + // an ambiguous arity would clobber that dispatch (TriCtor(float) running the int + // overload) — skip those arities and leave them on the reflective path. + var ctorArityCounts = new Dictionary(); + for (int ci = 0; ci < ctors.Length; ci++) + { + int a = ctors[ci].GetParameters().Length; + ctorArityCounts[a] = ctorArityCounts.TryGetValue(a, out var c) ? c + 1 : 1; + } + for (int ci = 0; ci < ctors.Length; ci++) + { + var ctor = ctors[ci]; + var cps = ctor.GetParameters(); + if (ctorArityCounts[cps.Length] > 1) continue; + if (!_entries.TryGetValue($"{type.Name}..ctor/{cps.Length}", out var ctorEntry)) continue; + + // 0-arg ctor: just zero the destination bytes. + if (cps.Length == 0) + { + int sz = ctorLayout.Size; + ctorEntry.FastIsFlat = true; ctorEntry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int dstOff = (bp + dst) * 4; + for (int b = 0; b < sz; b++) num[dstOff + b] = 0; + }; + continue; + } + + // Field-init shortcut: every param has same name and matching primitive type as a + // declared field on T. Build a per-arg (offset, kind) plan once. + int[]? argOffsets = new int[cps.Length]; + int[]? argKinds = new int[cps.Length]; // 0 = float, 1 = int + bool allFieldInit = true; + for (int p = 0; p < cps.Length; p++) + { + var pn = cps[p].Name; + if (pn == null || !ctorLayout.Fields.TryGetValue(pn, out var fld)) + { allFieldInit = false; break; } + if (cps[p].ParameterType == typeof(float) && fld.St == SType.R4) + { argOffsets[p] = fld.Offset; argKinds[p] = 0; } + else if (cps[p].ParameterType == typeof(int) && fld.St == SType.I4) + { argOffsets[p] = fld.Offset; argKinds[p] = 1; } + else + { allFieldInit = false; break; } + } + + if (allFieldInit) + { + int sz = ctorLayout.Size; + var offs = argOffsets!; + var kinds = argKinds!; + ctorEntry.FastIsFlat = true; ctorEntry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int dstOff = (bp + dst) * 4; + // Zero any holes so padding bytes match GetUninitializedObject's bytes. + for (int b = 0; b < sz; b++) num[dstOff + b] = 0; + for (int p = 0; p < offs.Length; p++) + { + int srcSlot = bp + (int)ir[argBase + p]; + if (kinds[p] == 0) + Unsafe.WriteUnaligned(num + (dstOff + offs[p]), + RF(num, ref_, slotT, srcSlot)); + else + Unsafe.WriteUnaligned(num + (dstOff + offs[p]), + RI(num, ref_, slotT, srcSlot)); + } + }; + continue; + } + + // Generic fallback for ctors that do real work: pay the per-call args array + // and Invoke + Unsafe.As copy. Better than the boxed path because we + // still skip the heap box for the result and read the args we have flat. + var captured = ctor; + int paramCount = cps.Length; + ctorEntry.FastIsFlat = true; ctorEntry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + var args = new object?[paramCount]; + for (int p = 0; p < paramCount; p++) + { + int s = bp + (int)ir[argBase + p]; + var pt = cps[p].ParameterType; + // Every I4-classified primitive lives in the NUMERIC frame — ref_[s] is + // null for them, and ConstructorInfo.Invoke turns a null arg into 0 + // (silent zeroed fields; caught by the host-surface sweep on ColorLike). + if (pt == typeof(float)) args[p] = RF(num, ref_, slotT, s); + else if (pt == typeof(int)) args[p] = RI(num, ref_, slotT, s); + else if (pt == typeof(bool)) args[p] = RI(num, ref_, slotT, s) != 0; + else if (pt == typeof(char)) args[p] = (char)RI(num, ref_, slotT, s); + else if (pt == typeof(byte)) args[p] = (byte)RI(num, ref_, slotT, s); + else if (pt == typeof(sbyte)) args[p] = (sbyte)RI(num, ref_, slotT, s); + else if (pt == typeof(short)) args[p] = (short)RI(num, ref_, slotT, s); + else if (pt == typeof(ushort)) args[p] = (ushort)RI(num, ref_, slotT, s); + else if (pt == typeof(uint)) args[p] = unchecked((uint)RI(num, ref_, slotT, s)); + else if (pt.IsEnum) args[p] = Enum.ToObject(pt, RI(num, ref_, slotT, s)); + // A flat-struct arg (Vector3 into Bounds..ctor) lives in the numeric + // frame — ref_[s] is null there, and Invoke would zero the param. + else if (slotT[s] == SType.Vt && pt.IsValueType + && _structLayoutsByType.TryGetValue(pt, out var pLay)) + args[p] = pLay.BoxFromPtr(num + s * 4); + else args[p] = ref_[s]; + } + var boxed = captured.Invoke(args); + T val = (T)boxed!; + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), val); + }; + } + } + + // --- Instance methods & property accessors for VALUE-TYPE T with a flat layout --- + // Open-instance delegates over a struct method take `ref T`, so these closures read + // the receiver IN PLACE: from its Vt frame slot (no box; mutations land directly in + // the frame bytes — the lowerer's nested-offset/write-back machinery composes on top), + // or, for boxed receivers (O slot from a class field), by deferring to Entry.Invoke, + // whose reflective call mutates the box in place as recvWriteBack expects. + // FastVtRecv tells the executor the closure handles Vt receivers itself; it reads the + // receiver slot index from ir[argBase - 3] (the call_host recv operand). + if (!isRef && flatOk) + { + foreach (var m in type.GetMethods(instBind)) // includes get_/set_ accessor methods + { + if (m.IsGenericMethodDefinition) continue; + if (!_byHandle.TryGetValue(m.MethodHandle.Value, out var entry)) continue; + if (entry.Fast != null) continue; + var e = entry; // captured by the closures below + var ps = m.GetParameters(); + var rt = m.ReturnType; + + // () → float (get_magnitude, get_sqrMagnitude) + if (ps.Length == 0 && rt == typeof(float)) + { + var del = (RefRecvFn)Delegate.CreateDelegate(typeof(RefRecvFn), m); + entry.FastVtRecv = true; entry.FastIsFlat = true; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int rs = (int)ir[argBase - 3]; + if (slotT[rs] == SType.Vt) + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), del(ref Unsafe.AsRef(num + ((bp + rs) * 4)))); + else + { + var r = e.Invoke(recv, Array.Empty()); + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), r is float f ? f : r is int ri ? (float)ri : 0f); + } + }; + continue; + } + + // () → int / bool (get_isNormalized-style) + if (ps.Length == 0 && (rt == typeof(int) || rt == typeof(bool))) + { + if (rt == typeof(bool)) + { + var del = (RefRecvFn)Delegate.CreateDelegate(typeof(RefRecvFn), m); + entry.FastVtRecv = true; entry.FastIsFlat = true; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int rs = (int)ir[argBase - 3]; + if (slotT[rs] == SType.Vt) + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), del(ref Unsafe.AsRef(num + ((bp + rs) * 4))) ? 1 : 0); + else + { + var r = e.Invoke(recv, Array.Empty()); + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), r is int ri ? ri : r is bool rb ? (rb ? 1 : 0) : 0); + } + }; + } + else + { + var del = (RefRecvFn)Delegate.CreateDelegate(typeof(RefRecvFn), m); + entry.FastVtRecv = true; entry.FastIsFlat = true; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int rs = (int)ir[argBase - 3]; + if (slotT[rs] == SType.Vt) + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), del(ref Unsafe.AsRef(num + ((bp + rs) * 4)))); + else + { + var r = e.Invoke(recv, Array.Empty()); + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), r is int ri ? ri : 0); + } + }; + } + continue; + } + + // () → T (get_normalized) — dst is a Vt slot (ReturnStruct is set by the parser). + if (ps.Length == 0 && rt == type) + { + var del = (RefRecvFn)Delegate.CreateDelegate(typeof(RefRecvFn), m); + entry.FastVtRecv = true; entry.FastIsFlat = true; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int rs = (int)ir[argBase - 3]; + if (slotT[rs] == SType.Vt) + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), del(ref Unsafe.AsRef(num + ((bp + rs) * 4)))); + else + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), (T)e.Invoke(recv, Array.Empty())!); + }; + continue; + } + + // () → void (Normalize()) + if (ps.Length == 0 && rt == typeof(void)) + { + var del = (RefRecvAct)Delegate.CreateDelegate(typeof(RefRecvAct), m); + entry.FastVtRecv = true; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int rs = (int)ir[argBase - 3]; + if (slotT[rs] == SType.Vt) del(ref Unsafe.AsRef(num + ((bp + rs) * 4))); + else e.Invoke(recv, Array.Empty()); + }; + continue; + } + + // (float) → void (Scale(f), computed set_ accessors) + if (ps.Length == 1 && ps[0].ParameterType == typeof(float) && rt == typeof(void)) + { + var del = (RefRecvAct1F)Delegate.CreateDelegate(typeof(RefRecvAct1F), m); + entry.FastVtRecv = true; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int rs = (int)ir[argBase - 3]; + float a0 = RF(num, ref_, slotT, bp + (int)ir[argBase]); + if (slotT[rs] == SType.Vt) del(ref Unsafe.AsRef(num + ((bp + rs) * 4)), a0); + else e.Invoke(recv, new object?[] { a0 }); + }; + continue; + } + + // (int) → void + if (ps.Length == 1 && ps[0].ParameterType == typeof(int) && rt == typeof(void)) + { + var del = (RefRecvAct1I)Delegate.CreateDelegate(typeof(RefRecvAct1I), m); + entry.FastVtRecv = true; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int rs = (int)ir[argBase - 3]; + int a0 = RI(num, ref_, slotT, bp + (int)ir[argBase]); + if (slotT[rs] == SType.Vt) del(ref Unsafe.AsRef(num + ((bp + rs) * 4)), a0); + else e.Invoke(recv, new object?[] { a0 }); + }; + continue; + } + + // (float, float) → void and (float, float, float) → void (Set(x, y[, z])) + if (rt == typeof(void) && (ps.Length == 2 || ps.Length == 3) + && ps[0].ParameterType == typeof(float) && ps[1].ParameterType == typeof(float) + && (ps.Length == 2 || ps[2].ParameterType == typeof(float))) + { + if (ps.Length == 2) + { + var del = (RefRecvAct2F)Delegate.CreateDelegate(typeof(RefRecvAct2F), m); + entry.FastVtRecv = true; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int rs = (int)ir[argBase - 3]; + float a0 = RF(num, ref_, slotT, bp + (int)ir[argBase]); + float a1 = RF(num, ref_, slotT, bp + (int)ir[argBase + 1]); + if (slotT[rs] == SType.Vt) del(ref Unsafe.AsRef(num + ((bp + rs) * 4)), a0, a1); + else e.Invoke(recv, new object?[] { a0, a1 }); + }; + } + else + { + var del = (RefRecvAct3F)Delegate.CreateDelegate(typeof(RefRecvAct3F), m); + entry.FastVtRecv = true; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int rs = (int)ir[argBase - 3]; + float a0 = RF(num, ref_, slotT, bp + (int)ir[argBase]); + float a1 = RF(num, ref_, slotT, bp + (int)ir[argBase + 1]); + float a2 = RF(num, ref_, slotT, bp + (int)ir[argBase + 2]); + if (slotT[rs] == SType.Vt) del(ref Unsafe.AsRef(num + ((bp + rs) * 4)), a0, a1, a2); + else e.Invoke(recv, new object?[] { a0, a1, a2 }); + }; + } + continue; + } + + // (float) → float + if (ps.Length == 1 && ps[0].ParameterType == typeof(float) && rt == typeof(float)) + { + var del = (RefRecvFn1F)Delegate.CreateDelegate(typeof(RefRecvFn1F), m); + entry.FastVtRecv = true; entry.FastIsFlat = true; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int rs = (int)ir[argBase - 3]; + float a0 = RF(num, ref_, slotT, bp + (int)ir[argBase]); + if (slotT[rs] == SType.Vt) + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), del(ref Unsafe.AsRef(num + ((bp + rs) * 4)), a0)); + else + { + var r = e.Invoke(recv, new object?[] { a0 }); + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), r is float f ? f : r is int ri ? (float)ri : 0f); + } + }; + continue; + } + + // (int) → int + if (ps.Length == 1 && ps[0].ParameterType == typeof(int) && rt == typeof(int)) + { + var del = (RefRecvFn1I)Delegate.CreateDelegate(typeof(RefRecvFn1I), m); + entry.FastVtRecv = true; entry.FastIsFlat = true; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int rs = (int)ir[argBase - 3]; + int a0 = RI(num, ref_, slotT, bp + (int)ir[argBase]); + if (slotT[rs] == SType.Vt) + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), del(ref Unsafe.AsRef(num + ((bp + rs) * 4)), a0)); + else + { + var r = e.Invoke(recv, new object?[] { a0 }); + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), r is int ri ? ri : 0); + } + }; + continue; + } + } + } + + // --- Instance methods: only for reference types (open-instance delegates require ref receiver) --- + if (isRef) + { + foreach (var m in type.GetMethods(instBind)) + { + if (m.IsSpecialName || m.IsGenericMethodDefinition) continue; + if (!_byHandle.TryGetValue(m.MethodHandle.Value, out var entry)) continue; + var ps = m.GetParameters(); + var rt = m.ReturnType; + + // () → float + if (ps.Length == 0 && rt == typeof(float)) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), null, m); + entry.Delegate = (recv, _) => (object)del((T)recv!); + // FastFlat shape for primitive returns: writes float bytes directly into + // numFrame, dropping the per-call float box. Lowerer allocates an R4 dst + // when this is set on a primitive-returning entry. + entry.FastIsFlat = true; entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), del((T)recv!)); + continue; + } + + // () → T + if (ps.Length == 0 && rt == type) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), null, m); + entry.Delegate = (recv, _) => (object)del((T)recv!)!; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + ref_[bp + dst] = del((T)recv!); + continue; + } + + // (T) → void + if (ps.Length == 1 && ps[0].ParameterType == type && rt == typeof(void)) + { + var del = (Action)Delegate.CreateDelegate(typeof(Action), null, m); + entry.Delegate = (recv, a) => { del((T)recv!, (T)a[0]!); return null; }; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + del((T)recv!, (T)ref_[bp + (int)ir[argBase]]!); + continue; + } + + // (float) → void + if (ps.Length == 1 && ps[0].ParameterType == typeof(float) && rt == typeof(void)) + { + var del = (Action)Delegate.CreateDelegate(typeof(Action), null, m); + entry.Delegate = (recv, a) => { del((T)recv!, (float)a[0]!); return null; }; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + del((T)recv!, RF(num, ref_, slotT, bp + (int)ir[argBase])); + continue; + } + + // (int) → void + if (ps.Length == 1 && ps[0].ParameterType == typeof(int) && rt == typeof(void)) + { + var del = (Action)Delegate.CreateDelegate(typeof(Action), null, m); + entry.Delegate = (recv, a) => { del((T)recv!, (int)a[0]!); return null; }; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + del((T)recv!, RI(num, ref_, slotT, bp + (int)ir[argBase])); + continue; + } + + // () → void (e.g. Jump(), Reset()) + if (ps.Length == 0 && rt == typeof(void)) + { + var del = (Action)Delegate.CreateDelegate(typeof(Action), null, m); + entry.Delegate = (recv, _) => { del((T)recv!); return null; }; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => del((T)recv!); + continue; + } + + // (float, float) → void and (float, float, float) → void — the Translate/Rotate/ + // Set(x, y[, z]) family. Profiling showed these falling to the reflection slow path + // (MethodBaseInvoker + per-call arg boxing), ~25% of a host-call-heavy loop. + if (rt == typeof(void) && (ps.Length == 2 || ps.Length == 3) + && ps[0].ParameterType == typeof(float) && ps[1].ParameterType == typeof(float) + && (ps.Length == 2 || ps[2].ParameterType == typeof(float))) + { + if (ps.Length == 2) + { + var del = (Action)Delegate.CreateDelegate(typeof(Action), null, m); + entry.Delegate = (recv, a) => { del((T)recv!, (float)a[0]!, (float)a[1]!); return null; }; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + del((T)recv!, + RF(num, ref_, slotT, bp + (int)ir[argBase]), + RF(num, ref_, slotT, bp + (int)ir[argBase + 1])); + } + else + { + var del = (Action)Delegate.CreateDelegate(typeof(Action), null, m); + entry.Delegate = (recv, a) => { del((T)recv!, (float)a[0]!, (float)a[1]!, (float)a[2]!); return null; }; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + del((T)recv!, + RF(num, ref_, slotT, bp + (int)ir[argBase]), + RF(num, ref_, slotT, bp + (int)ir[argBase + 1]), + RF(num, ref_, slotT, bp + (int)ir[argBase + 2])); + } + continue; + } + + // (float) → float (e.g. GetAxis-style scaling helpers) + if (ps.Length == 1 && ps[0].ParameterType == typeof(float) && rt == typeof(float)) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), null, m); + entry.Delegate = (recv, a) => (object)del((T)recv!, (float)a[0]!); + entry.FastIsFlat = true; entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + del((T)recv!, RF(num, ref_, slotT, bp + (int)ir[argBase]))); + continue; + } + + // (int) → int + if (ps.Length == 1 && ps[0].ParameterType == typeof(int) && rt == typeof(int)) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), null, m); + entry.Delegate = (recv, a) => (object)del((T)recv!, (int)a[0]!); + entry.FastIsFlat = true; entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), + del((T)recv!, RI(num, ref_, slotT, bp + (int)ir[argBase]))); + continue; + } + + // () → S where S is a registered struct (e.g. IWorld.GetPosition() → V3). + // A Func closed over a value-type S is the usual IL2CPP/AOT risk; + // link.xml registration of the script's host types covers it. + if (ps.Length == 0 && rt.IsValueType && _structLayoutsByType.TryGetValue(rt, out var retLay)) + { + var helper = typeof(HostBinding).GetMethod(nameof(BindInstReturnsStruct), + BindingFlags.NonPublic | BindingFlags.Static)!.MakeGenericMethod(type, rt); + helper.Invoke(null, new object[] { entry, m }); + continue; + } + + // (S) → void where S is a registered struct (e.g. IWorld.SetPosition(V3)). + if (ps.Length == 1 && ps[0].ParameterType.IsValueType && rt == typeof(void) + && _structLayoutsByType.TryGetValue(ps[0].ParameterType, out var argLay)) + { + var helper = typeof(HostBinding).GetMethod(nameof(BindInstTakesStructVoid), + BindingFlags.NonPublic | BindingFlags.Static)!.MakeGenericMethod(type, ps[0].ParameterType); + helper.Invoke(null, new object[] { entry, m }); + continue; + } + + // () → int or () → bool (e.g. Count, IsValid). FastIsFlat is REQUIRED for + // numeric returns: the lowerer allocates a numeric (I4) dst whenever the + // method's return type is numeric, so the closure must write numFrame — + // a boxed write to refFrame leaves the numeric cell uninitialized (zeros on + // Mono, garbage on IL2CPP: the Transform.childCount player bug). + if (ps.Length == 0 && (rt == typeof(int) || rt == typeof(bool))) + { + if (rt == typeof(bool)) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), null, m); + entry.Delegate = (recv, _) => del((T)recv!) ? (object)1 : 0; + entry.FastIsFlat = true; entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), del((T)recv!) ? 1 : 0); + } + else + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), null, m); + entry.Delegate = (recv, _) => (object)del((T)recv!); + entry.FastIsFlat = true; entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), del((T)recv!)); + } + continue; + } + + // () → reference type (any object return not handled above). Func via + // reference covariance; store the ref straight into refFrame — no boxing/reflection. + if (ps.Length == 0 && !rt.IsValueType && rt != typeof(void)) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), null, m); + entry.Delegate = (recv, _) => del((T)recv!); + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + ref_[bp + dst] = del((T)recv!); + continue; + } + } + } + + // --- Instance property getters/setters: only for reference types --- + if (!isRef) return; + var typeName = type.Name; + foreach (var p in type.GetProperties(instBind)) + { + if (SkipType(p.PropertyType)) continue; + // Indexers don't fit the zero-arg getter shapes below (their /1 keys wouldn't match + // the /0 lookups anyway, but a same-name /0 twin must never bind a 2-arg accessor). + if (p.GetIndexParameters().Length > 0) continue; + if (p.GetMethod != null && !SkipMethod(p.GetMethod)) + { + var g = p.GetMethod; + var key = $"{typeName}.{g.Name}/0"; + if (_entries.TryGetValue(key, out var entry)) + { + // Numeric getters must be FastIsFlat and write numFrame — the lowerer + // allocates a numeric dst for numeric return types (see the () → int + // method shape above for the failure mode). + if (g.ReturnType == typeof(float)) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), null, g); + entry.Delegate = (recv, _) => (object)del((T)recv!); + entry.FastIsFlat = true; entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), del((T)recv!)); + } + else if (g.ReturnType == type) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), null, g); + entry.Delegate = (recv, _) => (object)del((T)recv!)!; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + ref_[bp + dst] = del((T)recv!); + } + else if (g.ReturnType == typeof(bool)) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), null, g); + entry.Delegate = (recv, _) => del((T)recv!) ? (object)1 : 0; + entry.FastIsFlat = true; entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), del((T)recv!) ? 1 : 0); + } + else if (g.ReturnType == typeof(int)) + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), null, g); + entry.Delegate = (recv, _) => (object)del((T)recv!); + entry.FastIsFlat = true; entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), del((T)recv!)); + } + else if (!g.ReturnType.IsValueType) + { + // Returns a reference type (e.g. GameObject.transform → Transform). Func + // binds via reference covariance; the result is already an object, so store it + // straight into refFrame — no boxing, no reflection. AOT-safe (closed over T). + var del = (Func)Delegate.CreateDelegate(typeof(Func), null, g); + entry.Delegate = (recv, _) => del((T)recv!); + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + ref_[bp + dst] = del((T)recv!); + } + } + } + if (p.SetMethod != null && !SkipMethod(p.SetMethod)) + { + var s = p.SetMethod; + var pt = s.GetParameters()[0].ParameterType; + var key = $"{typeName}.{s.Name}/1"; + if (_entries.TryGetValue(key, out var entry)) + { + if (pt == typeof(float)) + { + var del = (Action)Delegate.CreateDelegate(typeof(Action), null, s); + entry.Delegate = (recv, a) => { del((T)recv!, (float)a[0]!); return null; }; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + del((T)recv!, RF(num, ref_, slotT, bp + (int)ir[argBase])); + } + else if (pt == type) + { + var del = (Action)Delegate.CreateDelegate(typeof(Action), null, s); + entry.Delegate = (recv, a) => { del((T)recv!, (T)a[0]!); return null; }; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + del((T)recv!, (T)ref_[bp + (int)ir[argBase]]!); + } + else if (pt == typeof(int)) + { + var del = (Action)Delegate.CreateDelegate(typeof(Action), null, s); + entry.Delegate = (recv, a) => { del((T)recv!, (int)a[0]!); return null; }; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + del((T)recv!, RI(num, ref_, slotT, bp + (int)ir[argBase])); + } + else if (pt == typeof(bool)) + { + var del = (Action)Delegate.CreateDelegate(typeof(Action), null, s); + entry.Delegate = (recv, a) => { del((T)recv!, a[0] is int iv ? iv != 0 : (bool)a[0]!); return null; }; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + del((T)recv!, RI(num, ref_, slotT, bp + (int)ir[argBase]) != 0); + } + } + } + } + + } + + // Templates instantiated via reflection from BuildTypedDelegates when an instance method + // either returns or accepts a registered host struct. Cross-type generic shapes can't be + // expressed inline because BuildTypedDelegates only knows about T, not the struct type S. + // The reflection step (MakeGenericMethod with a value-type S) is the same IL2CPP risk that + // any AllowTypeStruct + AllowType combination already takes, and is exercised at registration + // time so the closed delegate is hot before the script runs. + static void BindInstReturnsStruct(Entry entry, MethodInfo m) + where TStruct : struct + { + var del = (Func)Delegate.CreateDelegate(typeof(Func), null, m); + entry.Delegate = (recv, _) => (object)del((TRecv)recv!)!; + entry.FastIsFlat = true; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + Unsafe.WriteUnaligned(num + ((bp + dst) * 4), del((TRecv)recv!)); + } + + static void BindInstTakesStructVoid(Entry entry, MethodInfo m) + where TStruct : struct + { + var del = (Action)Delegate.CreateDelegate(typeof(Action), null, m); + entry.Delegate = (recv, a) => { del((TRecv)recv!, (TStruct)a[0]!); return null; }; + entry.FastIsFlat = true; + entry.Fast = (recv, num, ref_, slotT, ir, argBase, dst, bp) => + { + int s0 = bp + (int)ir[argBase]; + TStruct val = slotT[s0 - FastFrameBase] == SType.Vt + ? Unsafe.ReadUnaligned(num + (s0 * 4)) + : (TStruct)ref_[s0]!; + del((TRecv)recv!, val); + }; + } + + // Flat-frame readers shared between BuildTypedDelegates and AllowBcl fast-path helpers. + // These mirror the local RF/RI statics inside BuildTypedDelegates but are accessible + // as private static members so AllowBcl can close over them without a generic instantiation. + static float NumReadFloat(byte* num, object?[] ref_, SType[] slotT, int s) + { + var t = slotT[s - FastFrameBase]; + if (t == SType.R4) return Unsafe.ReadUnaligned(num + (s * 4)); + if (t == SType.I4) return (float)Unsafe.ReadUnaligned(num + (s * 4)); + if (t == SType.Vt) return 0f; // Vt refFrame entries are not cleared; never read them + var v = ref_[s]; return v is float f ? f : v is int i ? (float)i : 0f; + } + + static double NumReadDouble(byte* num, object?[] ref_, SType[] slotT, int s) + { + var t = slotT[s - FastFrameBase]; + if (t == SType.R8) return Unsafe.ReadUnaligned(num + (s * 4)); + if (t == SType.R4) return Unsafe.ReadUnaligned(num + (s * 4)); + if (t == SType.I4) return Unsafe.ReadUnaligned(num + (s * 4)); + if (t == SType.I8) return Unsafe.ReadUnaligned(num + (s * 4)); + if (t == SType.Vt) return 0d; + var v = ref_[s]; return v is double d ? d : v is float f ? f : v is int i ? i : v is long l ? l : 0d; + } + + static int NumReadInt(byte* num, object?[] ref_, SType[] slotT, int s) + { + var t = slotT[s - FastFrameBase]; + if (t == SType.I4) return Unsafe.ReadUnaligned(num + (s * 4)); + if (t == SType.R4) return (int)Unsafe.ReadUnaligned(num + (s * 4)); + if (t == SType.Vt) return 0; // Vt refFrame entries are not cleared; never read them + var v = ref_[s]; return v is int i ? i : v is bool b ? (b?1:0) : 0; + } + + // Attach a FastIsFlat float-returning fast path to an already-registered entry. + // Sets FlatReturnSType = R4 so the lowerer allocates an R4 dst slot (required for + // flat writes when Method is null, e.g. AllowBcl hand-rolled entries). + // No-ops if the entry is not found (e.g. if AllowStatic was never called for it). + void AttachFlatDouble(string typeName, string methodName, int paramCount, FastCallDelegate fast) + { + var key = $"{typeName}.{methodName}/{paramCount}"; + if (!_entries.TryGetValue(key, out var entry)) return; + entry.FastIsFlat = true; + entry.FlatReturnSType = SType.R8; + entry.FastWideOk = true; + entry.Fast = fast; + } + + void RegisterMethods(MethodInfo[] methods, string typeName, bool isStatic) + { + // All non-special methods go directly into _byHandle; signature-based MemberRef + // resolution at parse time picks the exact overload via GetMethod + handle. + foreach (var m in methods) + { + if (m.IsSpecialName || SkipMethod(m)) continue; + if (m.IsGenericMethodDefinition) + { + var openKey = (typeName, m.Name, m.GetParameters().Length); + if (!_openGenericMethods.TryGetValue(openKey, out var overloads)) + _openGenericMethods[openKey] = overloads = new List(); + overloads.Add(m); + continue; + } + var mp = m.GetParameters(); + var captured = m; + _byHandle[m.MethodHandle.Value] = new Entry + { + Delegate = isStatic ? (_, args) => captured.Invoke(null, args) : (recv, args) => captured.Invoke(recv, args), + ParamCount = mp.Length, + HasThis = !isStatic, + Params = mp, + Method = m, + DeclaringType = m.DeclaringType, + }; + } + } + + static bool SkipType(Type t) => t.IsPointer || t.IsByRef || t.IsGenericTypeDefinition; + + // IsGenericMethodDefinition is NOT skipped — RegisterMethods diverts those into + // _openGenericMethods for lazy instantiation at script load time. Byref (ref/out) + // params are supported; only pointer params disqualify a method. + static bool SkipMethod(MethodBase m) + { + foreach (var p in m.GetParameters()) + if (p.ParameterType.IsPointer) return true; + return false; + } + + // Test helper; constructors resolve via methodName ".ctor". + internal bool HasMethod(string typeName, string methodName, int arity) => + _entries.ContainsKey($"{typeName}.{methodName}/{arity}"); + + internal bool TryGet(string key, int arity, [NotNullWhen(true)] out Entry? entry) => + _entries.TryGetValue($"{key}/{arity}", out entry); + + internal bool TryGet(string key, [NotNullWhen(true)] out Entry? entry) => + _entries.TryGetValue(key, out entry); + + internal bool TryGetField(string key, [NotNullWhen(true)] out FieldEntry? entry) => + _fields.TryGetValue(key, out entry); + + internal IReadOnlyCollection Collisions => _collisions; + internal IReadOnlyCollection RegisteredTypes => _registeredTypes; + + internal bool TryGetByHandle(IntPtr handle, [NotNullWhen(true)] out Entry? entry) => + _byHandle.TryGetValue(handle, out entry); + + internal bool TryGetGenericType(string outerName, string arg0Name, out Type? type) => + _genericTypes.TryGetValue((outerName, arg0Name), out type); + + internal bool TryGetOpenGenerics(string typeName, string methodName, int arity, out List? overloads) + { + if (_openGenericMethods.TryGetValue((typeName, methodName, arity), out var lst) && lst.Count > 0) + { overloads = lst; return true; } + overloads = null; return false; + } + + internal bool TryGetTypeByName(string name, out Type? type) + { + foreach (var t in _registeredTypes) + if (t.Name == name) { type = t; return true; } + type = null; return false; + } + + // Namespace-qualified variant: simple names collide across namespaces (UnityEngine.Application + // vs UnityEngine.WSA/Device.Application) and the first registered twin would win above. + internal bool TryGetTypeByFullName(string fullName, out Type? type) + { + foreach (var t in _registeredTypes) + if (t.FullName == fullName) { type = t; return true; } + type = null; return false; + } + + // Resolve a CLR full name through AutoBindResolver and AllowType the result on first use. + // Returns true when the type is registered after the call — whether this call bound it or a + // prior one did. Open generic definitions can't be AllowType'd directly, but they're + // remembered by short name so TryMakeClosedGenericType can instantiate them on demand when a + // TypeSpec member (e.g. AsyncOperationHandle`1.op_Implicit) needs the closed type. + internal bool TryAutoBindType(string fullName) + { + var resolver = AutoBindResolver; + if (resolver == null) return false; + if (!_autoBindCache.TryGetValue(fullName, out var t)) + { + try { t = resolver(fullName); } catch { t = null; } + _autoBindCache[fullName] = t; + } + if (t == null || t.IsPointer || t.IsByRef) return false; + if (t.IsGenericTypeDefinition) + { + if (!_openGenericTypeDefs.ContainsKey(t.Name)) _openGenericTypeDefs[t.Name] = t; + return false; + } + if (!_registeredTypes.Contains(t)) AllowType(t); + return true; + } + + // Open generic type definitions seen by the auto-bind pass, keyed by metadata short name + // ("AsyncOperationHandle`1"). Source for on-demand closed-type construction below. + readonly Dictionary _openGenericTypeDefs = new(); + + // Construct and register <arg0> from an auto-bind-seen open + // definition and an already-registered type argument. Registering via AllowType also populates + // _genericTypes, so subsequent members of the same instantiation hit TryGetGenericType directly. + // Runtime MakeGenericType is safe on IL2CPP when the closed type exists in the build's metadata + // (it does whenever the reloaded source's original assembly used it) — same caveat as + // GetOrMakeClosedMethod for generic methods. + internal bool TryMakeClosedGenericType(string outerName, string arg0Name, out Type? closed) + { + closed = null; + if (!_openGenericTypeDefs.TryGetValue(outerName, out var def)) return false; + if (def.GetGenericArguments().Length != 1) return false; + if (!TryGetTypeByName(arg0Name, out var arg) || arg == null) return false; + try { closed = def.MakeGenericType(arg); } catch { return false; } + if (!_registeredTypes.Contains(closed)) AllowType(closed); + return true; + } + + internal MethodInfo GetOrMakeClosedMethod(MethodInfo openDef, Type[] typeArgs) + { + var sb = new System.Text.StringBuilder(); + for (int i = 0; i < typeArgs.Length; i++) + { + if (i > 0) sb.Append(','); + sb.Append(typeArgs[i].FullName); + } + var key = (openDef.MethodHandle.Value, sb.ToString()); + if (_closedCache.TryGetValue(key, out var cached)) return cached; + var closed = openDef.MakeGenericMethod(typeArgs); + _closedCache[key] = closed; + return closed; + } +} + +sealed class EntryReferenceComparer : IEqualityComparer +{ + public static readonly EntryReferenceComparer Instance = new(); + public bool Equals(HostBinding.Entry? x, HostBinding.Entry? y) => ReferenceEquals(x, y); + public int GetHashCode(HostBinding.Entry obj) => RuntimeHelpers.GetHashCode(obj); +} +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/HostBinding.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/HostBinding.cs.meta new file mode 100644 index 0000000..51a950f --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/HostBinding.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 47a7b8492a07c4348a96952a3f0ea322 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/IFrameAllocator.cs b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/IFrameAllocator.cs new file mode 100644 index 0000000..6510ede --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/IFrameAllocator.cs @@ -0,0 +1,18 @@ +#nullable enable + +namespace IlInterpreter.Interpreter +{ + // Supplies the Vm engine's unmanaged numeric frame. Injected so the engine stays + // UnityEngine-free: the default is Marshal-based (works everywhere incl. IL2CPP), while a + // Unity host can provide a NativeArray/UnsafeUtility-backed implementation. + // + // Contract: Alloc returns memory aligned to at least 8 bytes (both AllocHGlobal and + // UnsafeUtility.Malloc(...,8,...) satisfy this), so a Value* frame and inline structs up to + // 8-byte field alignment are safe to address. The returned block is owned by the caller until + // passed back to Free; implementations must not move or GC it. + unsafe interface IFrameAllocator + { + void* Alloc(int byteCount); + void Free(void* ptr); + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/IFrameAllocator.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/IFrameAllocator.cs.meta new file mode 100644 index 0000000..9437c2b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/IFrameAllocator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4d4b0ac718cfb5d4e9ed7c0fe4803d74 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/IScript.cs b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/IScript.cs new file mode 100644 index 0000000..465e708 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/IScript.cs @@ -0,0 +1,23 @@ +#nullable enable +using System; +using System.Collections.Generic; +namespace IlInterpreter +{ + +/// +/// Represents a compiled, validated script that can be executed by the interpreter. +/// Instances are produced by the host compilation layer (Unity.Pipeline.Compilation) and +/// consumed by IlInterpreter.Interpreter. +/// +interface IScript +{ + /// Name of the script class (as declared in source). + string Name { get; } + + /// + /// The compiled IL bytes. These have been validated by the IL validator and + /// are safe to interpret. + /// + ReadOnlyMemory Il { get; } +} +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/IScript.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/IScript.cs.meta new file mode 100644 index 0000000..1337ad8 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/IScript.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 285de7e71faedf64da123cc7351300c0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/IrDisassembler.cs b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/IrDisassembler.cs new file mode 100644 index 0000000..1c0b00a --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/IrDisassembler.cs @@ -0,0 +1,106 @@ +#nullable enable +using System; +using System.Text; + +namespace IlInterpreter.Interpreter +{ + // Debug tool: render a lowered method's IR (slot types, token/string tables, decoded ops) as text + // — the missing "see what the lowerer produced" view for chasing slot-typing/marshalling bugs. + // Internal, for tests and probe harnesses. Op widths come from OpWidthForCoalesce (never drifts). + partial class ScriptInterpreter + { + /// Disassemble one loaded method by simple name (first match). Null if not loaded/found. + internal string? DisassembleMethod(string name) + { + if (_parsed == null || !_parsed.ByName.TryGetValue(name, out var m)) return null; + return DisassembleParsed(m); + } + + /// Disassemble every loaded method (declaration order by token). + internal string DisassembleAll() + { + var sb = new StringBuilder(); + if (_parsed == null) return "(no script loaded)"; + foreach (var m in _parsed.ByToken.Values) + sb.Append(DisassembleParsed(m)).Append('\n'); + return sb.ToString(); + } + + string DisassembleParsed(ParsedMethod m) + { + var sb = new StringBuilder(); + sb.Append($"=== {m.Name} (static={m.IsStatic}, args={m.ArgCount}, locals={m.LocalCount}, ret={m.ReturnSType}, argSTypes=[{string.Join(",", m.ArgSTypes)}]"); + var lo = m.Lowered; + if (lo == null) + { + sb.Append($") NOT LOWERED: {m.LoweringSkipReason ?? "(no reason)"}\n"); + return sb.ToString(); + } + sb.Append($", frameSize={lo.FrameSize})\n"); + + // Slot type table (slot -> SType), compact. + sb.Append(" slots: "); + for (int s = 0; s < lo.SlotTypes.Length; s++) + sb.Append($"{s}:{lo.SlotTypes[s]} "); + sb.Append('\n'); + + if (lo.Strings.Length > 0) + { + sb.Append(" strings: "); + for (int i = 0; i < lo.Strings.Length; i++) + sb.Append($"[{i}]=\"{lo.Strings[i]}\" "); + sb.Append('\n'); + } + + // Instruction stream. + var ir = lo.Ir; + int ip = 0; + while (ip < ir.Length) + { + var op = (Op)ir[ip]; + int w = IrLowerer.OpWidthForCoalesce(op, ir, ip); + if (w <= 0) { sb.Append($" {ip,4}: \n"); break; } + int il = ip < lo.IrToIlOffset.Length ? lo.IrToIlOffset[ip] : -1; + sb.Append($" {ip,4} (IL 0x{il:X4}): {op,-16}"); + for (int k = 1; k < w; k++) sb.Append($" {(int)ir[ip + k]}"); + sb.Append(Annotate(op, ir, ip, w, lo)); + sb.Append('\n'); + ip += w; + } + return sb.ToString(); + } + + // Human-readable suffix for the operands we can resolve: the ldstr literal, the target of a + // host/script call, and the field behind a ld/stsfld/ld/stfld. + string Annotate(Op op, uint[] ir, int ip, int w, LoweredMethod lo) + { + switch (op) + { + case Op.ldstr: + // [op, dst, strIdx] + int si = (int)ir[ip + 2]; + return si < lo.Strings.Length ? $" ; dst=s{(int)ir[ip + 1]} \"{lo.Strings[si]}\"" : " ; "; + case Op.call_host: + // [op, dst, recvSlot, tokIdx, argc, args...] + return $" ; dst=s{(int)ir[ip + 1]} recv=s{(int)ir[ip + 2]} -> {TokName(lo, (int)ir[ip + 3])}"; + case Op.call_script: + case Op.newobj_script: + case Op.newobj_host: + // [op, dst, tokIdx, argc, args...] + return $" ; dst=s{(int)ir[ip + 1]} -> {TokName(lo, (int)ir[ip + 2])}"; + case Op.ldsfld_i4: case Op.ldsfld_r4: case Op.ldsfld_o: + case Op.stsfld_i4: case Op.stsfld_r4: case Op.stsfld_o: + return $" ; {TokName(lo, (int)ir[ip + 2])}"; + default: + return ""; + } + } + + string TokName(LoweredMethod lo, int tokIdx) + { + if (_parsed == null || lo.Tokens == null || (uint)tokIdx >= (uint)lo.Tokens.Length) return $"tok#{tokIdx}"; + int tok = lo.Tokens[tokIdx]; + return _parsed.TokenNames.TryGetValue(tok, out var n) ? n : $"tok 0x{tok:X8}"; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/IrDisassembler.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/IrDisassembler.cs.meta new file mode 100644 index 0000000..fe90a8c --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/IrDisassembler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 52ef5529fb77441e29e1687a62aeaf5a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/MarshalFrameAllocator.cs b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/MarshalFrameAllocator.cs new file mode 100644 index 0000000..bebac2d --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/MarshalFrameAllocator.cs @@ -0,0 +1,23 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace IlInterpreter.Interpreter +{ + +// Default frame allocator used outside Unity (and anywhere a host doesn't inject its own). +// Marshal.AllocHGlobal is platform-neutral and AOT/IL2CPP-safe, and keeps the engine free of +// any Unity.Collections dependency. Returns 8-byte-aligned memory on all supported runtimes. +sealed unsafe class MarshalFrameAllocator : IFrameAllocator +{ + public static readonly MarshalFrameAllocator Instance = new(); + + public void* Alloc(int byteCount) => (void*)Marshal.AllocHGlobal(byteCount); + + public void Free(void* ptr) + { + if (ptr != null) Marshal.FreeHGlobal((nint)ptr); + } +} +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/MarshalFrameAllocator.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/MarshalFrameAllocator.cs.meta new file mode 100644 index 0000000..ecd0ab3 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/MarshalFrameAllocator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 34bdbc5d5dc71af4ababeaa8abc6be1c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Op.cs b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Op.cs new file mode 100644 index 0000000..f719021 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Op.cs @@ -0,0 +1,387 @@ +#nullable enable +using System; +using System.Collections.Generic; +namespace IlInterpreter.Interpreter +{ + +// Typed IR opcodes for the lowered-IR interpreter. +// +// Type suffixes: +// _i4 32-bit int (includes bool as 0/1) +// _r4 32-bit float +// _o object reference (string, ScriptObject, host ref, null) +// _struct boxed value type (flat blittable structs use the _vt ops instead) +// +// Encoding (all in uint[]): +// [op, dst, src1, src2] arithmetic, compare +// [op, dst, imm] ldc_i4, ldc_r4, ldnull, ldstr +// [op, target_ip] br +// [op, cond, target_ip] brtrue_i4, brfalse_i4, brtrue_o, brfalse_o +// [op, dst, recv, argc, arg0, ...] call_static, call_virtual, call_host, newobj +// [op, dst, src] mov, conv_*, ldfld_*, ldsfld_*, ldlen, newarr, ldelem_*, neg_* +// [op, recv, fldIdx/tok, src] stfld_*, stsfld_* +// [op, dst, arr, idx] ldelem_* (arr=slot, idx=slot) +// [op, arr, idx, src] stelem_* +// [op] ret_void +// [op, src] ret_i4, ret_r4, ret_o +enum Op : uint +{ + // --- No-op (usually elided during lowering) --- + nop, + + // --- Move (type-agnostic; routes between frames by slot type) --- + mov, // [op, dst, src] + + // --- Constants --- + ldc_i4, // [op, dst, imm_value] imm is the int value cast to uint + ldc_r4, // [op, dst, imm_bits] imm is BitConverter.SingleToUInt32Bits(f) + ldnull, // [op, dst] + ldstr, // [op, dst, str_idx] str_idx indexes into LoweredMethod.Strings + + // --- Integer arithmetic (i4) --- + add_i4, // [op, dst, src1, src2] + add_i4_nn, // both srcs in numFrame as I4 + sub_i4, + sub_i4_nn, + mul_i4, + mul_i4_nn, + div_i4, + div_i4_nn, + rem_i4, + rem_i4_nn, + neg_i4, // [op, dst, src] + neg_i4_n, // src in numFrame as I4 + + // --- Float arithmetic (r4) --- + add_r4, // [op, dst, src1, src2] + add_r4_nn, // both srcs in numFrame as R4 + sub_r4, + sub_r4_nn, + mul_r4, + mul_r4_nn, + div_r4, + div_r4_nn, + rem_r4, + rem_r4_nn, + neg_r4, // [op, dst, src] + neg_r4_n, // src in numFrame as R4 + + // --- Bitwise (i4 only; float has no bitwise) --- + and_i4, // [op, dst, src1, src2] + and_i4_nn, + or_i4, + or_i4_nn, + xor_i4, + xor_i4_nn, + not_i4, // [op, dst, src] + not_i4_n, + shl_i4, // [op, dst, src1, src2] + shl_i4_nn, + shr_i4, + shr_i4_nn, + shr_un_i4, + shr_un_i4_nn, + div_un_i4, // unsigned div/rem: uint is analyzer-legal, so `u / 2u` must run + div_un_i4_nn, + rem_un_i4, + rem_un_i4_nn, + + // --- Integer comparisons (produce 1/0 int) --- + ceq_i4, // [op, dst, src1, src2] + ceq_i4_nn, + cgt_i4, + cgt_i4_nn, + clt_i4, + clt_i4_nn, + cgt_un_i4, + cgt_un_i4_nn, + clt_un_i4, + clt_un_i4_nn, + + // --- Float comparisons --- + ceq_r4, // [op, dst, src1, src2] + ceq_r4_nn, + cgt_r4, + cgt_r4_nn, + clt_r4, + clt_r4_nn, + // Unordered float comparisons — what C# emits for float `<=`/`>=` (via cgt.un/clt.un). + // cgt_un_r4 = !(a <= b) (true when a > b OR either is NaN); clt_un_r4 = !(a >= b). + cgt_un_r4, // [op, dst, src1, src2] + clt_un_r4, // [op, dst, src1, src2] + + // --- Object/reference comparisons --- + ceq_o, // [op, dst, src1, src2] — reference equality + cgt_un_o, // [op, dst, src1, src2] — cgt.un on object (null check pattern) + + // --- Branches --- + br, // [op, target_ip] + brtrue_i4, // [op, cond, target_ip] + brfalse_i4, // [op, cond, target_ip] + brtrue_o, // [op, cond, target_ip] + brfalse_o, // [op, cond, target_ip] + + // --- Conversions --- + conv_i4_r4, // [op, dst, src] int → float + conv_r4_i4, // [op, dst, src] float → int + conv_i4_i1, // [op, dst, src] int → sbyte (sign-extend) + conv_i4_u1, // [op, dst, src] int → byte (zero-extend) + conv_i4_i2, // [op, dst, src] int → short + conv_i4_u2, // [op, dst, src] int → ushort + + // --- Host field access (via token + reflection-style lookup) --- + // dst = frame slot; obj = frame slot holding receiver; tok = field token index + ldfld_i4, // [op, dst, obj, tok_idx] + ldfld_r4, + ldfld_o, + ldfld_struct, + ldflda, // [op, dst, obj, tok_idx] — load field value (same as ldfld_o) + stfld_i4, // [op, obj, tok_idx, src] + stfld_r4, + stfld_o, + stfld_struct, + + // --- Script-class field access (flat typed storage) --- + // For script-defined classes, fields are stored in ScriptObject.PrimBytes (primitives) + // or ScriptObject.RefSlots (references). Byte offset is baked at lowering time. + // ldfld_sc_i4/r4: [op, dst, obj, byteOffset] — read from PrimBytes + // ldfld_sc_o: [op, dst, obj, refIdx] — read from RefSlots + // stfld_sc_i4/r4: [op, obj, byteOffset, src] — write to PrimBytes + // stfld_sc_o: [op, obj, refIdx, src] — write to RefSlots + // ldfld_sc_vt: [op, dst, obj, byteOffset] — copy N bytes from PrimBytes into Vt slot + // stfld_sc_vt: [op, obj, byteOffset, src] — copy N bytes from Vt slot into PrimBytes + ldfld_sc_i4, + ldfld_sc_r4, + ldfld_sc_o, + ldfld_sc_vt, + stfld_sc_i4, + stfld_sc_r4, + stfld_sc_o, + stfld_sc_vt, + + // --- Static field access --- + ldsfld_i4, // [op, dst, tok_idx] + ldsfld_r4, + ldsfld_o, + ldsfld_struct, + stsfld_i4, // [op, tok_idx, src] + stsfld_r4, + stsfld_o, + stsfld_struct, + + // --- Arrays --- + newarr, // [op, dst, len_src, elem_tok_idx] + // Typed-backing variants (same 5-word encoding as newarr): when the element type is + // statically System.Int32 / System.Single the executor allocates a real int[]/float[] + // instead of object?[], and ldelem/stelem take non-boxing direct paths — an int store + // into an object?[] element boxes (GC pressure in hot Update bodies) and Mono pays ~3x + // CoreCLR on that path. + newarr_i4, + newarr_r4, + // Flat-struct element arrays (ScriptVtArray backing): zero-init bytes = C# array semantics, + // no per-element allocation. Same 5-word encoding as newarr; elem layout resolved at lowering + // into LoweredMethod.LayoutByTokIdx. + newarr_vt, + ldlen, // [op, dst, arr_src] + ldelem_i4, // [op, dst, arr, idx] + ldelem_r4, + ldelem_o, + ldelem_struct, + stelem_i4, // [op, arr, idx, src] + stelem_r4, + stelem_o, + stelem_struct, + // Flat-struct element access: memcpy between the array's byte backing and a Vt frame slot + // (value semantics without clone_sc). Fall back to boxed forms for object?[]/host T[] arrays. + ldelem_vt, // [op, dst(Vt), arr, idx] + stelem_vt, // [op, arr, idx, src(Vt)] + + // --- Calls --- + // [op, dst, recv, argc, arg0, arg1, ...] + // dst = 0xFFFFFFFF for void calls (ret discarded) + // recv = 0xFFFFFFFF for static calls + call_script, // callee is a script-defined method; tok_idx in recv slot (reuse) + call_host, // callee is a host entry + // call_host with byref args. After arg0..argN comes a writeback table: + // wbCount, [argIdx, frameSlot, kind] × wbCount + // kind: 0 = frame slot, 1 = field (frameSlot=objSlot, plus tokIdx in next word), + // 2 = array element (frameSlot=arrSlot, plus idxSlot in next word). + // The slow Invoke path is always used (Fast skipped) so MethodInfo.Invoke writes + // back into the boxed args[] array, which we then copy into the right destination. + call_host_byref, + + // --- Object construction --- + newobj_script, // [op, dst, tok_idx, argc, arg0, ...] script-defined type ctor + newobj_host, // [op, dst, tok_idx, argc, arg0, ...] host type ctor + box_enum, // [op, dst, src, tok_idx] box an I4 value as its HOST ENUM type (resolved + // via ParsedAssembly.TokenTypes) so ToString/Format render the member name + new_delegate, // [op, dst, tok_idx, recv] delegate creation (ldftn/ldvirtftn + newobj); + // tok_idx indexes LoweredMethod.DelegateSiteByTokIdx (pre-resolved target + + // delegate type); recv is the receiver's O slot (holds null for statics) + + // --- Misc --- + box, // [op, dst, src] — read slot as object into refFrame + box_prim, // [op, dst, src, typecode] — box a primitive as its TRUE type (bool/char/… not int) + unbox_any, // [op, dst, src, tok_idx] + castclass, // [op, dst, src, tok_idx] + isinst, // [op, dst, src, tok_idx] + ldtoken, // [op, dst, tok_idx] + initobj, // [op, dst] — zero-initialize slot (for script struct locals) + switch_i4, // [op, val, n, ip0, ip1, ...] variable length; ip_default follows + + // --- Return --- + ret_void, // [op] + ret_i4, // [op, src] + ret_r4, // [op, src] + ret_o, // [op, src] + throw_o, // [op, src] — `throw` of a script-constructed exception; ends the block like ret + // Flat-struct return: reads the callee's Vt src bytes, memcpys them into the caller's + // (Vt) RetDst slot on frame pop; boxes once via the layout at the top-level boundary. + ret_vt, // [op, src(Vt)] + + // Zero-initialize a script-defined struct (O slot) without invoking a ctor. + // Used when the IL emits ldloca + initobj for a parameterless default ctor. + initobj_script, // [op, dst, typeDefTokIdx] + + // Ensure a script-defined struct O slot is non-null. Allocates a fresh zero-initialized + // ScriptObject only if the slot is currently null; leaves it untouched otherwise. + // Emitted by the stfld lowerer before field writes on struct locals that Roslyn considers + // "definitely assigned by field stores" (so no initobj in the IL) — our O slots start null. + ensure_script, // [op, dst, typeDefTokIdx] + + // Value-copy a script-defined struct: dst = shallow clone of the ScriptObject in src + // (copies PrimBytes + RefSlots). Emitted when a script struct is loaded as a VALUE + // (ldloc/ldarg/ldfld/ldelem) so each named location owns its instance — script structs + // are represented as ScriptObject references, so without this a copy would alias. A null + // or non-ScriptObject src is passed through unchanged. + clone_sc, // [op, dst, src] + + // --- Flat-struct (Vt slots): read/write primitive fields by byte offset, copy/box at boundary --- + // Vt slots reserve ceil(size/4) consecutive logical slots in numFrame. + // ldfld_vt_*/stfld_vt_* take a byte offset (within the Vt slot) instead of a token, + // since the field's offset is resolved at lowering time. + // box_vt/unbox_vt/mov_vt look up the StructLayout via lm.StructLayouts[src or dst]. + ldfld_vt_i4, // [op, dst, vtObj, byteOffset] + ldfld_vt_r4, // [op, dst, vtObj, byteOffset] + stfld_vt_i4, // [op, vtObj, byteOffset, src] + stfld_vt_r4, // [op, vtObj, byteOffset, src] + mov_vt, // [op, dst, src] — copy struct bytes (size from layout) + // Nested flat-struct field access: copy a SUB-RANGE of a Vt slot (a blittable struct field + // inlined inside another flat struct). Offsets are byte offsets within the receiver slot; + // the sub-struct's size comes from the dst/src slot's own layout. + ldfld_vt_vt, // [op, dst(Vt), vtObj, byteOffset] — memcpy size(dst) bytes out + stfld_vt_vt, // [op, vtObj, byteOffset, src(Vt)] — memcpy size(src) bytes in + // Sub-4-byte fields of flat host structs (Color32.r-class): loads widen into an I4 slot + // (zero- or sign-extended); stores truncate. Script structs never need these — the parser + // gives every script field its own 4-byte cell. + ldfld_vt_u1, // [op, dst(I4), vtObj, byteOffset] + ldfld_vt_i1, + ldfld_vt_u2, + ldfld_vt_i2, + stfld_vt_b1, // [op, vtObj, byteOffset, src] — writes low byte + stfld_vt_b2, // [op, vtObj, byteOffset, src] — writes low 2 bytes + box_vt, // [op, dst, src] — read Vt bytes, box as T into refFrame[dst] + unbox_vt, // [op, dst, src] — unbox refFrame[src] into Vt dst bytes + // Reuse existing newobj_host / call_host opcodes; executor branches on dst's slot type. + + // --- Operand-immediate forms: RHS literal embedded in the IR word --- + // Encoding: [op, dst, src, k_imm] (4 words). k_imm is the constant value cast to uint + // (BitConverter.SingleToUInt32Bits for floats). Executor reads it directly; no separate + // K-table lookup. Emitted by the lowerer when an `ldc_X tmp; binop_X_nn dst, src, tmp` + // pattern has tmp single-use. Subset is corpus-driven — only ops that show up in bench + // loops; expand on demand. Compare ops cover RHS-constant only (the canonical loop-bound + // pattern); LHS-constant doesn't appear in the bench corpus. + add_i4_nk, // [op, dst, src, k_int] + add_r4_nk, // [op, dst, src, k_bits] + sub_i4_nk, + sub_r4_nk, + mul_r4_nk, + clt_i4_nk, + clt_r4_nk, + cgt_i4_nk, + cgt_r4_nk, + ceq_i4_nk, + // Second _nk batch (profiling-driven): masks (`i & 255`), shifts (`acc >> 5`), scaling + // (`i * 3`) and float division/equality against a literal all showed up as hot + // `ldc; binop_nn` pairs in the bench op mix. Same [op, dst, src, k] encoding. + mul_i4_nk, + div_i4_nk, // k is the divisor (RHS only); k == 0 still faults like the slot form + rem_i4_nk, + and_i4_nk, + or_i4_nk, + xor_i4_nk, + shl_i4_nk, + shr_i4_nk, + shr_un_i4_nk, + div_r4_nk, + ceq_r4_nk, + + // --- Fused compare-and-branch --- + // Encoding: [op, s1, s2_or_k, target_ip] (4 words). _nn forms read both + // operands as slots; _nk forms read s1 as a slot and s2_or_k as an inline + // immediate. Always test "branch if cmp true" — for compare-then-brfalse + // patterns the lowerer fuses ceq → bne. Subset is corpus-driven (only the + // compare→branch patterns observed in bench loop bodies; no bge/ble, no + // LHS-constant `_kn` forms); add more on demand. + blt_i4_nn, // [op, s1, s2, target_ip] if (slot[s1] < slot[s2]) goto target + blt_i4_nk, // [op, s1, k, target_ip] if (slot[s1] < k) goto target + bgt_r4_nn, + bgt_r4_nk, + beq_i4_nn, + beq_i4_nk, + bne_i4_nn, + bne_i4_nk, + + // --- Numeric for-loop super-instruction --- + // Encoding: [op, induction_slot, limit_imm, target_ip] (4 words). + // Executor body: slot[N] += 1; if (slot[N] < limit) goto target. Three + // semantic steps (increment + bound check + back-edge) in one dispatch — + // analogous to Luau's LOP_FORNLOOP. Step is hardcoded to 1 (Roslyn-emitted + // C# `for (int i = ...; i < L; i++)` pattern). Variants for step != 1, + // reverse loops, and r4 induction are deferred until the bench corpus + // demands them. + // + // Lowerer pass detects `add_i4_nk slot[N], slot[N], 1; blt_i4_nk slot[N], + // K_limit, body_top` plus a preceding `ldc_i4 slot[N] = K_init; br -> + // blt_ip` with K_init statically less than K_limit. Replaces add+blt with + // for_i4_nk and redirects the entry br to body_top so the first body + // iteration isn't skipped. + for_i4_nk, // [op, induction_slot, limit_int, target_ip] + + // --- try/finally (non-exceptional path only) --- + // IL `leave T` lowers to push_cont(T), push_cont(outer handlers)…, br(innermost handler); + // IL `endfinally` lowers to br_cont, which pops the next continuation and jumps to it — + // chaining inner finally → outer finally → leave target. Exceptions thrown inside a try + // still propagate without running the finally (the whole dispatch falls back to the + // original compiled body via CodeReloadRegistry.TryInvokeCodeReload). + push_cont, // [op, target_ip] — push an IR continuation address + br_cont, // [op] — pop a continuation address and jump to it + + // --- 64-bit family (I8 = long/ulong, R8 = double) --- + // Wide slots: two consecutive 4-byte frame cells, filler cell typed O/null like Vt + // continuation cells. Methods whose frames contain a wide slot SKIP the optimizer + // passes wholesale (see LowerMethod), so no _nn/_nk fast forms exist and none of + // these ops appear in the pass tables. + ldc_i8, // [op, dst, lo, hi] + ldc_r8, // [op, dst, lo, hi] — IEEE754 double bits + add_i8, sub_i8, mul_i8, div_i8, rem_i8, // [op, dst, s1, s2] + div_un_i8, rem_un_i8, + and_i8, or_i8, xor_i8, + shl_i8, shr_i8, shr_un_i8, // [op, dst, value(I8), count(I4)] + neg_i8, not_i8, // [op, dst, src] + add_r8, sub_r8, mul_r8, div_r8, rem_r8, // [op, dst, s1, s2] + neg_r8, // [op, dst, src] + ceq_i8, cgt_i8, clt_i8, cgt_un_i8, clt_un_i8, // [op, dst(I4), s1, s2] + ceq_r8, cgt_r8, clt_r8, cgt_un_r8, clt_un_r8, // unordered variants for float semantics + conv_i8_i4, // [op, dst, src] — sign-extend i4 → i8 + conv_i8_u4, // zero-extend u4 → i8 + conv_i4_i8, // truncate i8 → i4 (also serves conv.u4) + conv_i8_r4, conv_r4_i8, + conv_i8_r8, conv_r8_i8, + conv_r8_r4, conv_r4_r8, + conv_r8_i4, conv_i4_r8, + conv_r8_u8, // ulong bits → double (conv.r.un) + brtrue_i8, brfalse_i8, // [op, src, target_ip] + ret_i8, ret_r8, // [op, src] +} +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Op.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Op.cs.meta new file mode 100644 index 0000000..336fccd --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Op.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bd7e60fa09b64c9458e396035345a26c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptDelegateAdapter.cs b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptDelegateAdapter.cs new file mode 100644 index 0000000..3a658ce --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptDelegateAdapter.cs @@ -0,0 +1,105 @@ +#nullable enable +using System; +using System.Reflection; + +namespace IlInterpreter.Interpreter +{ + partial class ScriptInterpreter + { + /// + /// The object behind a delegate whose target is an INTERPRETED method (a method group over a + /// script method, or a lambda's display-class method). The host holds an ordinary CLR delegate + /// of the exact requested type — System.Action, EventCallback<T>, a custom + /// delegate — and each invocation re-enters the VM, like does + /// for iterators. + /// + /// No Reflection.Emit: the delegate is built with Delegate.CreateDelegate over a + /// shape-matched generic forwarder (V0..V4 for void, F0..F4 otherwise) closed + /// over the delegate's Invoke signature. Same AOT posture as HostBinding's typed fast paths; + /// on IL2CPP a value-typed signature relies on full generic sharing. + /// + /// Lifetime: valid until the interpreter is re-Loaded or disposed — the same contract + /// as every other object that crosses the boundary. + /// + internal sealed class ScriptDelegateAdapter + { + readonly ScriptInterpreter _owner; + readonly ParsedMethod _target; + readonly object? _receiver; // null for static targets; prepended as arg 0 otherwise + readonly object _generation; // the ParsedAssembly this target was lowered with + + ScriptDelegateAdapter(ScriptInterpreter owner, ParsedMethod target, object? receiver) + { + _owner = owner; + _target = target; + _receiver = receiver; + _generation = owner._parsed!; + } + + public static Delegate Create( + ScriptInterpreter owner, Type delegateType, ParsedMethod target, object? receiver) + { + var invoke = delegateType.GetMethod("Invoke") + ?? throw new ScriptRuntimeException($"'{delegateType}' has no Invoke — not a delegate type"); + var ps = invoke.GetParameters(); + bool isVoid = invoke.ReturnType == typeof(void); + if (ps.Length > MaxArity) + throw new ScriptRuntimeException( + $"Delegate '{delegateType.Name}' has {ps.Length} parameters — method groups over " + + $"interpreted methods support up to {MaxArity}"); + foreach (var p in ps) + if (p.ParameterType.IsByRef) + throw new ScriptRuntimeException( + $"Delegate '{delegateType.Name}' has a ref/out parameter — not supported " + + "for method groups over interpreted methods"); + + var adapter = new ScriptDelegateAdapter(owner, target, receiver); + var shape = typeof(ScriptDelegateAdapter).GetMethod( + (isVoid ? "V" : "F") + ps.Length, BindingFlags.Public | BindingFlags.Instance)!; + int typeArgCount = ps.Length + (isVoid ? 0 : 1); + if (typeArgCount > 0) + { + var typeArgs = new Type[typeArgCount]; + for (int i = 0; i < ps.Length; i++) typeArgs[i] = ps[i].ParameterType; + if (!isVoid) typeArgs[ps.Length] = invoke.ReturnType; + shape = shape.MakeGenericMethod(typeArgs); + } + try + { + return Delegate.CreateDelegate(delegateType, adapter, shape); + } + catch (ArgumentException ex) + { + throw new ScriptRuntimeException( + $"Could not bind '{target.Name}' to delegate type '{delegateType.Name}': {ex.Message}"); + } + } + + const int MaxArity = 4; + + object? Call(object?[] args) + { + if (_receiver == null) + return _owner.InvokeDelegateTarget(_target, args, _generation); + var withReceiver = new object?[args.Length + 1]; + withReceiver[0] = _receiver; + Array.Copy(args, 0, withReceiver, 1, args.Length); + return _owner.InvokeDelegateTarget(_target, withReceiver, _generation); + } + + static readonly object?[] s_NoArgs = Array.Empty(); + + // Shape-matched forwarders — one per (void?, arity). Public so CreateDelegate binds them. + public void V0() => Call(s_NoArgs); + public void V1(A a) => Call(new object?[] { a }); + public void V2(A a, B b) => Call(new object?[] { a, b }); + public void V3(A a, B b, C c) => Call(new object?[] { a, b, c }); + public void V4(A a, B b, C c, D d) => Call(new object?[] { a, b, c, d }); + public R F0() => (R)Call(s_NoArgs)!; + public R F1(A a) => (R)Call(new object?[] { a })!; + public R F2(A a, B b) => (R)Call(new object?[] { a, b })!; + public R F3(A a, B b, C c) => (R)Call(new object?[] { a, b, c })!; + public R F4(A a, B b, C c, D d) => (R)Call(new object?[] { a, b, c, d })!; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptDelegateAdapter.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptDelegateAdapter.cs.meta new file mode 100644 index 0000000..e51f859 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptDelegateAdapter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 73f82ba15825e4cb38b92f41cecbb73c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptEnumerator.cs b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptEnumerator.cs new file mode 100644 index 0000000..23d46c8 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptEnumerator.cs @@ -0,0 +1,113 @@ +#nullable enable +using System; +using System.Collections; + +namespace IlInterpreter.Interpreter +{ + +sealed partial class ScriptInterpreter +{ + // Host-side IEnumerator over an interpreted iterator state machine. The host (Unity's + // coroutine scheduler, foreach, a manual MoveNext loop) drives the interface; each call + // re-enters the VM with the state machine ScriptObject as the receiver. Produced by + // WrapForHost whenever a script enumerator crosses the host boundary. + // + // Lifetime: valid until the owning interpreter is Unload()ed/Dispose()d or reLoad()ed — + // the state machine's methods belong to the loaded assembly. Driving a bridge after that + // ends the iterator like any other script error (see the guard below). + internal sealed class ScriptEnumerator : IEnumerator, IDisposable + { + readonly ScriptInterpreter _owner; + readonly EnumeratorMembers _members; + + // Set when a pump threw: the iterator is over. Without this guard an exception from + // an interpreted body propagates out of MoveNext into Unity's coroutine scheduler and + // kills the ENTIRE host coroutine chain that yielded on this bridge (a code-reload + // error froze the whole scene loop). A compiled body has the registry's + // fall-back-to-original safety net at dispatch; a coroutine body runs after dispatch, + // so this is its equivalent: log through the interpreter's sink and end the iterator — + // the outer coroutine resumes as if it completed. + bool _faulted; + + // Exposed for tests/diagnostics: the interpreted state machine instance. + internal ScriptObject StateMachine { get; } + + // Exposed for tests/diagnostics: the exception that ended this iterator, if any. The + // bridge deliberately swallows it (see _faulted) — but a differential harness driving + // oracle and interpreter side by side still needs to SEE the fault to check parity. + internal Exception? FaultException { get; private set; } + + internal ScriptEnumerator(ScriptInterpreter owner, ScriptObject stateMachine, + EnumeratorMembers members) + { + _owner = owner; + StateMachine = stateMachine; + _members = members; + } + + public bool MoveNext() + { + if (_faulted) return false; + try + { + return _owner.InvokeEnumeratorMember(_members.MoveNext, StateMachine) is bool b && b; + } + catch (Exception ex) + { + Fault("MoveNext", ex); + return false; + } + } + + // get_Current is a plain field read on the state machine — cheap and side-effect + // free, so no caching. A nested interpreted enumerator yielded as Current comes back + // wrapped (InvokeEnumeratorMember runs WrapForHost on its result). + public object? Current + { + get + { + if (_faulted) return null; + try + { + return _owner.InvokeEnumeratorMember(_members.GetCurrent, StateMachine); + } + catch (Exception ex) + { + Fault("Current", ex); + return null; + } + } + } + + // Iterator state machines don't support Reset (their own Reset throws + // NotSupportedException — the exact body the interpreter skips as a cold stub). + public void Reset() => throw new NotSupportedException(); + + public void Dispose() + { + if (_faulted || _members.Dispose == null) return; + try + { + _owner.InvokeEnumeratorMember(_members.Dispose, StateMachine); + } + catch (Exception ex) + { + Fault("Dispose", ex); + } + } + + void Fault(string where, Exception ex) + { + _faulted = true; + FaultException = ex; + // Full exception (type + stack), not just the message: a ScriptRuntimeException + // carries its location in the message, but a raw exception escaping the VM (an + // interpreter bug or a fast-path host throw) is only diagnosable from its stack. + _owner._logSink( + $"CodeReload: interpreted coroutine '{StateMachine.Type.Name}' threw in {where} — " + + $"ending this iterator so the host coroutine chain survives: {ex}"); + } + } +} + +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptEnumerator.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptEnumerator.cs.meta new file mode 100644 index 0000000..3ab94dd --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptEnumerator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2bc4e4aa52414750ab81e831065292cd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptException.cs b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptException.cs new file mode 100644 index 0000000..ede26aa --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptException.cs @@ -0,0 +1,53 @@ +#nullable enable +using System; +using System.Collections.Generic; +namespace IlInterpreter +{ + +/// Base exception for all IlInterpreter errors. +public class ScriptException : Exception +{ + /// Create the exception with a message. + /// The exception message. + public ScriptException(string message) : base(message) { } + /// Create the exception with a message and an inner cause. + /// The exception message. + /// The exception that caused this one, if any. + public ScriptException(string message, Exception? inner) : base(message, inner) { } +} + +/// Raised when script source fails to compile. +public class ScriptCompileException : ScriptException +{ + /// The compiler diagnostics that failed the compilation. + public IReadOnlyList Diagnostics { get; } + + /// Create the exception from the diagnostics that failed the compilation. + /// The compiler diagnostics that failed the compilation. + public ScriptCompileException(IReadOnlyList diagnostics) + : base($"Script compilation failed with {diagnostics.Count} error(s).") + { + Diagnostics = diagnostics; + } +} + +/// Raised when compiled IL fails validation. +public class ScriptValidationException : ScriptException +{ + /// Create the exception with a message. + /// The exception message. + public ScriptValidationException(string message) : base(message) { } +} + +/// Raised during interpreter execution. +public class ScriptRuntimeException : ScriptException +{ + /// Create the exception with a message. + /// The exception message. + public ScriptRuntimeException(string message) : base(message) { } + /// Create the exception with a message and an inner cause. + /// The exception message. + /// The exception that caused this one, if any. + public ScriptRuntimeException(string message, Exception? inner) : base(message, inner) { } +} +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptException.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptException.cs.meta new file mode 100644 index 0000000..8a49e95 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 32382bdf2a41c4141a26fb433b9395f6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptInterpreter.cs b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptInterpreter.cs new file mode 100644 index 0000000..e1e8658 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptInterpreter.cs @@ -0,0 +1,9104 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; +// The package bundles System.Reflection.Metadata renamed with a "UnityPipeline." prefix (Runtime/Plugins/CodeAnalysis); +// the dotnet test projects reference the same DLLs (IlInterpreter/BundledRoslyn.props). +using UnityPipeline.System.Reflection.Metadata; +using UnityPipeline.System.Reflection.Metadata.Ecma335; +using UnityPipeline.System.Reflection.PortableExecutable; +using System.Runtime.CompilerServices; + +namespace IlInterpreter.Interpreter +{ + +sealed partial class ScriptInterpreter : IDisposable +{ + public const int DefaultStepLimit = 1_000_000; + + // Per-invocation IL-opcode budget. Set higher for benchmarks or long-running + // workloads; the default catches accidental infinite loops in dev. + public int StepLimit = DefaultStepLimit; + + readonly HostBinding? _binding; + readonly Action _logSink; + readonly IFrameAllocator _allocator; + Vm? _vm; // lazily created on first Invoke + ParsedAssembly? _parsed; + ScriptObject? _instance; // the live "Script" instance (null for static-only scripts) + + // Per-size thread-local buffers for host-call arguments (sizes 0-8). + // Delegates registered via AllowType use MethodInfo.Invoke which requires an exact-length array. + [ThreadStatic] + static object?[][]? _argBufs; + + static object?[] ArgBuf(int count) + { + _argBufs ??= new object?[9][]; + if (count < _argBufs.Length) return _argBufs[count] ??= new object?[count]; + return new object?[count]; // rare: >8 args, just allocate + } + + public ScriptInterpreter(HostBinding? binding = null, Action? log = null, + IFrameAllocator? allocator = null) + { + _binding = binding; + _logSink = log ?? (_ => { }); + _allocator = allocator ?? MarshalFrameAllocator.Instance; + } + + // Parse the script IL; disposes any previously loaded assembly first (code reload). + // Throws ScriptValidationException if any method can't be lowered — failing at Load, + // where the user can act on it, rather than at Invoke time. + // lenient=true keeps loading when individual methods can't be lowered (each becomes a skipped + // stub queryable via TryGetLoweringSkip) instead of throwing for the whole assembly — see + // IrLowerer.LowerAll. Code reload passes true so one bad method doesn't drop a whole file's reload. + public void Load(IScript script, bool lenient = false) + { + _parsed?.PdbProvider?.Dispose(); + _parsed?.Pe.Dispose(); + // Parse reads attacker-reachable PE/metadata directly (System.Reflection.Metadata). Convert + // a malformed-image fault into a clean load failure rather than letting a raw + // BadImageFormatException/ArgumentException escape Load. ScriptExceptions (our own validation, + // e.g. a cyclic base chain) pass through unchanged. + try { _parsed = Parse(script.Il.ToArray(), _binding, _logSink); } + catch (ScriptException) { throw; } + catch (Exception ex) { throw new ScriptValidationException($"Failed to parse script assembly: {ex.Message}"); } + var failures = IrLowerer.LowerAll(_parsed, lenient); + if (failures.Count > 0) + { + var sb = new System.Text.StringBuilder("Script could not be lowered:"); + foreach (var f in failures) sb.Append('\n').Append(" ").Append(f.Name).Append(": ").Append(f.Reason); + _parsed.PdbProvider?.Dispose(); + _parsed.Pe.Dispose(); + _parsed = null; + throw new ScriptValidationException(sb.ToString()); + } + IrLowerer.BuildIrBlob(_parsed); + _instance = MakeInstance(_parsed); + // Run script static constructors eagerly (CLR runs them lazily; eager keeps the VM free of + // per-access init checks). The load-bearing case is the compiler-generated `<>c..cctor` + // that creates the singleton behind non-capturing lambdas — without it, `ldsfld <>9` + // reads null and a delegate over an instance method loses its receiver. A user static + // initializer that throws fails the Load, like everything else it validates. + foreach (var m in _parsed.ByToken.Values) + if (m.Name == ".cctor" && m.Lowered != null) + { + try { (_vm ??= new Vm(this)).Invoke(m, Array.Empty()); } + catch (ScriptException ex) + { + // Name the type whose static initializer faulted — a bare "array index out of + // bounds at IL+0x…" gives no clue which of an assembly's many .cctors blew up. + var typeName = _parsed.TypeDefToType.TryGetValue(m.DeclaringTypeDef, out var td) + ? td.Name : $"typedef 0x{m.DeclaringTypeDef:X8}"; + throw new ScriptRuntimeException( + $"static initializer of type '{typeName}' failed at load: {ex.Message}", ex); + } + } + } + + // Release the loaded assembly. Invoke() will throw until Load() is called again. + public void Unload() + { + _parsed?.PdbProvider?.Dispose(); + _parsed?.Pe.Dispose(); + _parsed = null; + _instance = null; + } + + public void Dispose() + { + Unload(); + _vm?.Dispose(); + _vm = null; + } + + // True if the loaded script defines a method with this (simple) name. Lets callers + // probe for an optional entry point (e.g. a code-reload override) without catching the + // "method not found" exception that Invoke throws. + public bool HasMethod(string name) => _parsed != null && _parsed.ByName.ContainsKey(name); + + // Host member refs of the loaded script that resolved to throwing stubs (or missing host + // fields) — the script runs, but reaching one of these sites throws ScriptRuntimeException. + // Callers surface these as load-time warnings instead of exploding mid-play on first call. + public IReadOnlyList UnboundHostMembers => + (IReadOnlyList?)_parsed?.UnboundHostMembers ?? Array.Empty(); + + // A method that exists but was skipped at load — Lowered==null with a reason — because it + // couldn't be lowered under lenient loading (see Load). Its call sites throw the reason if + // reached, so the code-reload executor skips registering just that override instead of the file. + public bool TryGetLoweringSkip(string methodName, out string reason) + { + if (_parsed != null && _parsed.ByName.TryGetValue(methodName, out var m) + && m.Lowered == null && m.LoweringSkipReason != null) + { reason = m.LoweringSkipReason; return true; } + reason = null!; + return false; + } + + // Resolve a host-invocable method by simple name, rejecting stubs that were skipped at + // load (cold enumerator members whose lowering failed). + ParsedMethod ResolveInvocable(string methodName) + { + if (_parsed == null) throw new ScriptRuntimeException("No script loaded — call Load() first"); + if (!_parsed.ByName.TryGetValue(methodName, out var method)) + throw new ScriptRuntimeException($"Method '{methodName}' not found"); + if (method.Lowered == null) + throw new ScriptRuntimeException( + $"Method '{methodName}' was skipped at load: {method.LoweringSkipReason}"); + return method; + } + + // Invoke a named method. + // For instance methods: args[0] = script instance, args[1..] = extraArgs. + // For static methods: args[0..] = extraArgs. + public object? Invoke(string methodName, params object?[] extraArgs) + { + var method = ResolveInvocable(methodName); + + // Hot no-arg path (OnUpdate/Run): the Vm places the receiver and runs with no object?[] + // allocation. Only the primitive return is boxed (at the API boundary). + if (extraArgs.Length == 0) + return WrapForHost((_vm ??= new Vm(this)).InvokeTyped(method)); + + var args = new object?[method.ArgCount]; + int slot = 0; + if (!method.IsStatic && _instance != null) args[slot++] = _instance; + for (int i = 0; i < extraArgs.Length && slot < method.ArgCount; i++) + args[slot++] = extraArgs[i]; + + return WrapForHost((_vm ??= new Vm(this)).Invoke(method, args)); + } + + // Typed 1-arg overload: bypasses object?[] allocation for primitive args. + // RyuJIT specializes per value-type T1; typeof checks fold to constants in + // each specialization, so no boxing occurs for int/float/bool callers. + // Void-returning methods (the common Unity Update pattern) allocate zero bytes. + // Numeric-returning methods re-box the result once (24 B); ref-returning methods + // have no boxing on either side. + public object? Invoke(string methodName, T1 a1) + { + var method = ResolveInvocable(methodName); + return WrapForHost((_vm ??= new Vm(this)).InvokeTyped(method, a1)); + } + + public object? Invoke(string methodName, T1 a1, T2 a2) + { + var method = ResolveInvocable(methodName); + return WrapForHost((_vm ??= new Vm(this)).InvokeTyped(method, a1, a2)); + } + + public object? Invoke(string methodName, T1 a1, T2 a2, T3 a3) + { + var method = ResolveInvocable(methodName); + return WrapForHost((_vm ??= new Vm(this)).InvokeTyped(method, a1, a2, a3)); + } + + // A script enumerator (iterator state machine) crossing to the host gets wrapped in a + // bridge the host can drive (Unity's StartCoroutine, foreach, LINQ over IEnumerator). + // Anything else passes through. ScriptObject is internal, so an unwrapped state machine + // would be useless to the caller anyway. + internal object? WrapForHost(object? result) + { + return result is ScriptObject so && _parsed != null && + _parsed.EnumeratorTypes.TryGetValue(so.Type, out var em) + ? new ScriptEnumerator(this, so, em) + : result; + } + + // Re-enter the VM to run one member of a script enumerator with an explicit receiver + // (the state machine ScriptObject). Used by the ScriptEnumerator bridge; safe to call + // while another Invoke is live (the Vm's _base reentrancy handling covers it). + internal object? InvokeEnumeratorMember(ParsedMethod member, ScriptObject receiver) + { + if (_parsed == null) throw new ScriptRuntimeException("No script loaded — call Load() first"); + if (member.Lowered == null) + throw new ScriptRuntimeException( + $"Method '{member.Name}' was skipped at load: {member.LoweringSkipReason}"); + return WrapForHost((_vm ??= new Vm(this)).InvokeReceiver(member, receiver)); + } + + // Re-enter the VM from a delegate created over an interpreted method (button click, event + // callback). args includes the receiver at [0] for instance targets. Same reentrancy story + // as InvokeEnumeratorMember. The generation check makes staleness a CLEAN error: the target's + // IR offsets are blob-absolute into the assembly it was lowered with, so a delegate surviving + // a re-Load would execute arbitrary words of the NEW blob — silently wrong, not crashing. + internal object? InvokeDelegateTarget(ParsedMethod target, object?[] args, object generation) + { + if (_parsed == null) throw new ScriptRuntimeException("No script loaded — call Load() first"); + if (!ReferenceEquals(_parsed, generation)) + throw new ScriptRuntimeException( + $"Delegate over '{target.Name}' was created by a previous script load and is no " + + "longer valid — re-run the code that created it after a reload"); + return WrapForHost((_vm ??= new Vm(this)).Invoke(target, args)); + } + + // Per-receiver delegate cache: `b.clicked += Click; b.clicked -= Click` must observe delegate + // equality, and script-adapter delegates only compare equal as the SAME instance. + readonly System.Runtime.CompilerServices.ConditionalWeakTable> + _delegatesByReceiver = new(); + + internal Delegate GetOrCreateDelegate(DelegateSite site, object? receiver) + { + if (receiver == null) + return site.CachedStatic ??= CreateDelegateCore(site, null); + var perReceiver = _delegatesByReceiver.GetOrCreateValue(receiver); + if (!perReceiver.TryGetValue(site, out var d)) + perReceiver[site] = d = CreateDelegateCore(site, receiver); + return d; + } + + Delegate CreateDelegateCore(DelegateSite site, object? receiver) + { + if (site.HostMethod is { } hm) + { + if (hm.IsStatic) + return Delegate.CreateDelegate(site.DelegateType, hm); + if (receiver == null) + throw new ScriptRuntimeException( + $"Cannot create a {site.DelegateType.Name} over instance method '{hm.Name}' with a null receiver"); + return Delegate.CreateDelegate(site.DelegateType, receiver, hm); + } + return ScriptDelegateAdapter.Create(this, site.DelegateType, site.ScriptMethod!, receiver); + } + + public object? Execute(IScript script, string methodName = "Run") + { + Load(script); + return Invoke(methodName); + } + + internal sealed class ParsedMethod + { + // Name/IlBytes/ArgSTypes are always set by Parse before the instance escapes; + // `= null!` marks that invariant (same idiom as Lowered below). + public string Name = null!; + public int Token; + public int ArgCount; + public int LocalCount; + public byte[] IlBytes = null!; + public bool IsStatic; + public bool IsVoid; + // True when the declared return type is bool (which stores as I4). The method-return boxing + // uses this to hand back a boxed bool rather than a boxed int, so a host caller casting the + // Invoke result to bool doesn't fault. + public bool ReturnIsBool; + // Return and parameter types for IR slot classification (set during Parse) + public SType ReturnSType; + public SType[] ArgSTypes = null!; // length = explicit param count (no `this` slot) + // Per-local struct layout. Non-null when the local is a registered host + // value type and should be allocated as a Vt slot in numFrame. + public HostBinding.StructLayout?[]? LocalStructLayouts; + // Per-local DECLARED slot type, from the LocalVarSig — the authoritative, stable backing: + // an IL local is single-typed, so its declared type (not last-wins store inference) says + // whether its value lives unboxed in the numeric frame (I4/R4) or boxed in refStack (O). + // Only the unambiguous, VM-consistent cases are captured (bool/char/sub-int/int -> I4, + // float -> R4, string/object/class/array/generic -> O); null entries (valuetype/enum, long, + // double, nint, byref, …) fall back to the inference pass. Non-null entries are FROZEN: the + // lowering neither infers nor retypes them, so a fast op is never emitted over a slot whose + // value is actually boxed. Null array when the sig gives nothing to freeze. + public SType?[]? LocalSTypes; + // Per-local flag: true when the local is a SCRIPT-defined struct (ELEMENT_TYPE_VALUETYPE + // referencing a TypeDef in this assembly). Such locals are O ScriptObject references, so a + // value load (ldloc) must clone to preserve struct copy semantics. Null when none are. + // The flat-resolution post-pass CLEARS entries whose struct turned out blittable — those + // locals get a Vt layout in LocalStructLayouts instead. + public bool[]? LocalIsScriptStruct; + // Per-local TypeDef token when the local is a script-defined struct (0 otherwise). Lets the + // post-pass resolve the local to a descriptor once all types are built. Null when none. + public int[]? LocalScriptStructTypeDefs; + // Per-explicit-param / return TypeDef token for script-struct types (0 = not one). + public int[]? ArgScriptStructTypeDefs; + public int ReturnScriptStructTypeDef; + // Per-explicit-param flat layout (parallel to ArgSTypes; entry non-null ⇔ ArgSTypes[i]==Vt). + public HostBinding.StructLayout?[]? ArgStructLayouts; + // Flat layout of a Vt return (ReturnSType == Vt). Null otherwise. + public HostBinding.StructLayout? ReturnStructLayout; + // Declaring TypeDef token (0 when unknown). Set at parse; lets the post-pass flatten + // `this` for instance methods declared on a blittable script struct. + public int DeclaringTypeDef; + // Flat layout for `this` (arg slot 0) when the declaring type is a flat script struct. + public HostBinding.StructLayout? ThisStructLayout; + // Doc is the source file name (no directory), "" when the PDB document had no name. + public (int IlOffset, int Line, string Doc)[]? SeqPoints; + // Finally clauses from the method body's exception-region table (offsets are IL byte + // offsets, End = exclusive). Null when the method has none. Consumed by the lowerer's + // leave/endfinally handling. Only the NON-exceptional path runs handlers. + public (int TryStart, int TryEnd, int HandlerStart, int HandlerEnd)[]? FinallyRegions; + // Fault-handler entry IL offsets. Fault handlers never run (the interpreter has no + // exception dispatch — see the region parse in Parse), but their bodies still lower as + // unreachable code; the lowerer treats each entry as a basic-block boundary. + public int[]? FaultHandlerStarts; + // True when the body has catch/filter clauses — those need real exception + // dispatch, which the interpreter doesn't do; lowering fails with a clear reason. + public bool HasUnsupportedEhClauses; + // True for enumerator members the host never drives (Reset — its body is + // `throw new NotSupportedException()`, which the interpreter can't lower). A lowering + // failure on a cold member becomes a skipped stub (LoweringSkipReason) instead of + // failing the whole Load. + public bool IsColdEnumeratorMember; + // Set when lowering this method failed but was tolerated (cold enumerator member). + // Lowered stays null; invoking the method throws this reason. + public string? LoweringSkipReason; + // Non-nullable post-Load for every invocable method: Load throws + // ScriptValidationException listing every method that didn't lower. The one exception + // is a cold enumerator member (IsColdEnumeratorMember) whose lowering failed — it keeps + // Lowered null and carries LoweringSkipReason; the Vm entry points guard against it. + public LoweredMethod Lowered = null!; + } + + // Output of the lowering pass for one method. + internal sealed class LoweredMethod + { + // All non-nullable fields are set by the lowering pass before the instance escapes. + public uint[] Ir = null!; // flat instruction stream (variable-width words) + public int FrameSize; // number of logical slots (numFrame = FrameSize*4 bytes, refFrame = FrameSize refs) + public int[] IrToIlOffset = null!; // ir word index → IL offset (for source mapping) + public string[] Strings = null!; // string table, indexed by ldstr immediate + public int[] Tokens = null!; // token table (field/type/method tokens), indexed by tok_idx immediate + // Per-slot type: I4/R4 → numeric byte frame; O → reference frame; Vt → flat struct + // bytes occupying ceil(StructLayouts[s].Size/4) consecutive slots. Indexed by slot number. + public SType[] SlotTypes = null!; + // Parallel to SlotTypes; non-null entries describe the struct layout for Vt slots. + public HostBinding.StructLayout?[]? StructLayouts; + // Pre-resolved fast-delegate cache, parallel to Tokens. For each tokIdx whose + // entry has a Fast closure, HostFastByTokIdx[tokIdx] is that closure. Eliminates + // the per-call_host `asm.HostCalls[tok]` dictionary lookup on the hot path. + // Null entries fall through to the slow path (which still does the dict lookup). + public FastCallDelegate?[]? HostFastByTokIdx; + // Parallel to HostFastByTokIdx: true when the entry's Fast closure handles a FLAT + // (Vt) receiver itself (Entry.FastVtRecv) — the executor may keep the fast path + // instead of dropping to the boxing slow path. + public bool[]? HostFastVtRecvByTokIdx; + public bool[]? HostFastWideOkByTokIdx; // Fast closure handles I8/R8 slots itself + + // Pre-resolved script callee per tokIdx. Eliminates the asm.ByToken[tok] dict + // lookup on the call_script / newobj_script hot path. Null for tokens that don't + // resolve to a script method (host calls, host ctors, fields, etc.). + public ParsedMethod?[]? CalleeByTokIdx; + + // Highest O-typed slot index + 1 (0 when the frame is all-numeric). Frame setup only + // needs to null refFrame slots the method can actually read as references — clearing + // the numeric remainder is wasted work on every call_script into a math-y helper. + public int RefClearLen; + + // This method's base offset inside ParsedAssembly.IrBlob. Execution ips are + // blob-absolute; diagnostics index IrToIlOffset with (ip - IrStart). + public int IrStart; + + // Arg index → frame slot. Null when identity (no Vt args): args live at slots + // 0..ArgCount-1. Non-null when a flat-struct arg occupies multiple slots, shifting + // the args after it. + public int[]? ArgSlot; + + // Sparse per-tokIdx flat layout for newarr_vt element types (parallel to Tokens). + public HostBinding.StructLayout?[]? LayoutByTokIdx; + + // Sparse per-tokIdx element Type for primitive arrays that need a typed runtime backing + // (bool[]/char[]/byte[]/sbyte[]/short[]/ushort[]). Int32/Single use the dedicated + // newarr_i4/newarr_r4 ops; every other primitive was previously object?[]-backed, which + // lost the element type (element ToString/boxing-identity wrong). Null when no such array. + public Type?[]? PrimArrayElemTypeByTokIdx; + + // Sparse per-tokIdx delegate-creation site (parallel to Tokens, keyed by the delegate + // ctor's tokIdx). Null when the method creates no delegates. + public DelegateSite?[]? DelegateSiteByTokIdx; + } + + // One ldftn/ldvirtftn + newobj delegate-creation site, pre-resolved at lowering: the runtime + // delegate type plus the target — a host MethodInfo (bound via Delegate.CreateDelegate) or an + // interpreted method (bound via a ScriptDelegateAdapter that re-enters the VM). + internal sealed class DelegateSite + { + public Type DelegateType = null!; + public MethodInfo? HostMethod; // exactly one of HostMethod / ScriptMethod is set + public ParsedMethod? ScriptMethod; + // Receiverless creations (static target) share one delegate per site, so repeated + // event `+=`/`-=` over the same method group observe delegate equality. + public Delegate? CachedStatic; + } + + sealed class HostEntry + { + public HostBinding.Entry Binding = null!; // the registered entry (handles int→bool coercion); always set at construction + public bool IsVoid; // true when return type is void — don't push result + // Per-arg flat-struct layouts (length = explicit param count, no receiver). + // Non-null entries indicate the parameter type was registered via AllowTypeStruct + // and its arg should be marshalled from a Vt slot at call time. null = boxed object. + public HostBinding.StructLayout?[]? ArgStructs; + // Receiver struct layout: non-null when the receiver is a flat struct (rare). + public HostBinding.StructLayout? ReceiverStruct; + // Return struct layout: non-null when the return type was registered via AllowTypeStruct. + public HostBinding.StructLayout? ReturnStruct; + // The EXACT overload this token resolved to. Aliased operator pairs (Quaternion's + // op_Multiply(Q,Q)->Q and op_Multiply(Q,V3)->V3) share one Entry whose Method is the + // FIRST overload — typing a call site from Entry.Method then mislabels the return + // (a Quaternion Vt dst for a Vector3 result => InvalidCastException at UnboxVt). + // Null when resolution didn't go through an exact MethodInfo (string fallback). + public MethodInfo? ResolvedMethod; + // Return SType from the call site's METADATA signature. The lowering types the result slot + // from ResolvedMethod when available; for string-keyed entries (hand-wired Allow/AllowBcl + // shims) there is no MethodInfo, and without this the slot defaulted to O — boxing every + // numeric host return, which broke `a.Length != a.Length` (reference-compared boxes) and + // any op that writes its result flat. + public SType SigRetSType = SType.O; + // How to box an I4-slot receiver for an instance host call. char and bool are stored in I4 + // slots but their boxed identity differs from int: 'r' (114) boxed as int renders "114" not + // "r", and a bool boxed as int renders "1"/"0" not "True"/"False". char and bool are the only + // I4-mapped receivers whose boxed identity changes the result (byte/short/... render the same + // digits as int). None for every other receiver. + public ReceiverBoxKind ReceiverBox; + } + + enum ReceiverBoxKind : byte { None, Char, Bool } + + + // Driver members of a script enumerator type (iterator state machine): what the host + // bridge invokes to pump it. Dispose is null when the type has no (parsed) Dispose. + internal readonly struct EnumeratorMembers + { + public readonly ParsedMethod MoveNext; + public readonly ParsedMethod GetCurrent; + public readonly ParsedMethod? Dispose; + public EnumeratorMembers(ParsedMethod moveNext, ParsedMethod getCurrent, ParsedMethod? dispose) + { + MoveNext = moveNext; GetCurrent = getCurrent; Dispose = dispose; + } + } + + sealed class ParsedAssembly + { + // Every non-nullable field is set by Parse's object initializer before the instance escapes. + public Dictionary ByToken = null!; + public Dictionary ByName = null!; + public Dictionary HostCalls = null!; // MemberRef token → host method + public Dictionary HostCtors = null!; // MemberRef token → host constructor + public Dictionary HostFields = null!; // MemberRef token → host field + public Dictionary HostFieldDeclTypeTok = null!; // host field MemberRef token → declaring TypeRef token (ensure-init of boxed struct locals) + public Dictionary TokenNames = null!; // MemberRef token → "Type.Method/N" for diagnostics + public Dictionary FieldSlots = null!; // FieldDef token → (type, slot) + public Dictionary FieldSTypes = null!; // FieldDef token → numeric type (for IR lowering) + public HashSet FieldIsScriptStruct = null!; // FieldDef tokens whose type is a script-defined struct (O storage, needs clone on value-load) + public Dictionary FieldToTypeDef = null!; // FieldDef token → declaring TypeDef token + public Dictionary CtorToType = null!; // .ctor MethodDef token → type + public Dictionary TypeDefToCtorTok = null!; // TypeDef token → default .ctor MethodDef token + public Dictionary TypeDefToType = null!; // TypeDef token → script type (for initobj) + public Dictionary TypesByName = null!; + // Script enumerator types (iterator state machines) → driver members for the host bridge. + public Dictionary EnumeratorTypes = null!; + public Dictionary TokenTypes = null!; // TypeRef/TypeSpec token → host Type (for castclass/isinst/ldtoken) + public MetadataReader Reader = null!; + public PEReader Pe = null!; + public MetadataReaderProvider? PdbProvider; + // Host member refs that resolved to throwing stubs (or missing host fields) — the script + // loaded, but reaching one of these call sites throws ScriptRuntimeException. Surfaced by + // ScriptInterpreter.UnboundHostMembers so callers can warn at load time. + public List UnboundHostMembers = new(); + + // SCRIPT static fields (FieldDef tokens accessed by ldsfld/stsfld), stored boxed, lazily. + // Unwritten fields read as null — matching CLR zero-init for the one pattern that needs + // this: the C# 11+ method-group delegate cache (`ldsfld <>O.__M; dup; brtrue …`), + // which null-checks before every use. Static ctors never run (pre-existing semantics), + // so a numeric static read before any write still fails, as it did before. + public Dictionary ScriptStatics = new(); + // Primitive (I4/R4) script statics, UNBOXED as raw bits (written by stsfld_i4/r4, read by + // ldsfld_i4/r4) — avoids a heap box on every static write. Miss = 0 (CLR zero-init); + // reference/long/double statics stay in the boxed ScriptStatics above. + public Dictionary ScriptStaticsNum = new(); + + // The host binding this assembly was parsed against — lets the LOWERER resolve + // flat layouts for host struct types (e.g. Vector3[] element layouts) by TypeRef name. + public HostBinding? HostSurface; + + // All methods' lowered IR concatenated (branch targets blob-absolute, one ret_void + // sentinel after each method's region). Built by IrLowerer.BuildIrBlob after LowerAll. + // Lets the Vm run script-to-script calls iteratively under a single `fixed` — no + // recursive Run() invocation (measured ~120ns per nested call on Mono) and no per-call + // array pin. + public uint[]? IrBlob; + } + + // CLR full name for a TypeRef — namespace-qualified, nested types joined with '+' — matching + // what Assembly.GetType expects. A nested TypeRef's ResolutionScope is its declaring TypeRef. + static string TypeRefFullName(MetadataReader reader, TypeReferenceHandle handle) + { + var tr = reader.GetTypeReference(handle); + var name = reader.GetString(tr.Name); + if (tr.ResolutionScope.Kind == HandleKind.TypeReference) + return TypeRefFullName(reader, (TypeReferenceHandle)tr.ResolutionScope) + "+" + name; + var ns = reader.GetString(tr.Namespace); + return ns.Length == 0 ? name : ns + "." + name; + } + + static ParsedAssembly Parse(byte[] bytes, HostBinding? binding, Action logSink) + { + var pe = new PEReader(new MemoryStream(bytes), PEStreamOptions.PrefetchEntireImage); + MetadataReader reader = pe.GetMetadataReader(); + + // --- Demand-time auto-bind: register this script's referenced host types on first use --- + // When the binding carries an AutoBindResolver policy, resolve every TypeRef the script + // references and AllowType the ones the policy accepts, BEFORE the MemberRef resolution + // below — every resolution site then sees the type as if it had been curated. What binds + // is entirely the resolver's decision (which types exist, which assemblies are policy- + // skipped); this pass just walks the refs. Type args of closed generics appear as their + // own TypeRef rows, so MethodSpec instantiation (AddComponent) benefits too. + if (binding?.AutoBindResolver != null) + foreach (var trHandle in reader.TypeReferences) + binding.TryAutoBindType(TypeRefFullName(reader, trHandle)); + + // --- Script methods --- + var byToken = new Dictionary(); + var byName = new Dictionary(); + + foreach (var handle in reader.MethodDefinitions) + { + var def = reader.GetMethodDefinition(handle); + var name = reader.GetString(def.Name); + var token = MetadataTokens.GetToken(handle); + + if (def.RelativeVirtualAddress == 0) continue; + + var body = pe.GetMethodBody(def.RelativeVirtualAddress); + var ilBytes = body.GetILBytes() ?? Array.Empty(); + var localCount = ReadLocalCount(reader, body.LocalSignature); + var localStrs = ReadLocalStructLayouts(reader, body.LocalSignature, localCount, binding); + var localScSt = ReadLocalIsScriptStruct(reader, body.LocalSignature, localCount, out var localScTds); + var localSTps = ReadLocalSTypes(reader, body.LocalSignature, localCount); + var isStatic = (def.Attributes & MethodAttributes.Static) != 0; + var sigBytes = reader.GetBlobBytes(def.Signature); + var (isVoid, retSType, retIsBool) = SigReturn(sigBytes); + var argSTypes = SigParamSTypes(sigBytes); + // Use signature param count, not Param-table count: Roslyn omits Param table entries + // for synthetic parameters in compiler-generated methods (closures, state machines). + var argCount = (isStatic ? 0 : 1) + argSTypes.Length; + + // Exception-region table: finally clauses are lowered (leave/endfinally continuation + // chain); catch/filter need real exception dispatch and fail lowering instead. + // FAULT clauses are IGNORED: a fault handler runs only under exception dispatch, + // which the interpreter never does — a script exception propagates straight to the + // host and the frame is abandoned — so skipping the region keeps normal-path + // semantics exact (fault must NOT run on normal exit). C# can't write a fault + // clause; Roslyn emits them in iterator/async MoveNext bodies, so this is what lets + // `yield return` state machines with try/finally lower. The handler body still + // lowers (as unreachable code); its start is recorded so the lowerer treats it as a + // basic-block boundary. + (int, int, int, int)[]? finRegions = null; + int[]? faultHandlerStarts = null; + bool unsupportedEh = false; + if (!body.ExceptionRegions.IsEmpty) + { + var fins = new List<(int, int, int, int)>(); + List? faults = null; + foreach (var er in body.ExceptionRegions) + { + if (er.Kind == ExceptionRegionKind.Finally) + fins.Add((er.TryOffset, er.TryOffset + er.TryLength, + er.HandlerOffset, er.HandlerOffset + er.HandlerLength)); + else if (er.Kind == ExceptionRegionKind.Fault) + (faults ??= new List()).Add(er.HandlerOffset); + else + unsupportedEh = true; + } + if (fins.Count > 0) finRegions = fins.ToArray(); + if (faults != null) faultHandlerStarts = faults.ToArray(); + } + + var (retScTd, argScTds) = ReadSigScriptStructTokens(sigBytes); + int declTypeDef = 0; + try { declTypeDef = MetadataTokens.GetToken(def.GetDeclaringType()); } catch (Exception) { } + var m = new ParsedMethod { Name = name, Token = token, DeclaringTypeDef = declTypeDef, ArgCount = argCount, LocalCount = localCount, IlBytes = ilBytes, IsStatic = isStatic, IsVoid = isVoid, ReturnIsBool = retIsBool, ReturnSType = retSType, ArgSTypes = argSTypes, LocalStructLayouts = localStrs, LocalSTypes = localSTps, LocalIsScriptStruct = localScSt, LocalScriptStructTypeDefs = localScTds, ArgScriptStructTypeDefs = argScTds, ReturnScriptStructTypeDef = retScTd, FinallyRegions = finRegions, FaultHandlerStarts = faultHandlerStarts, HasUnsupportedEhClauses = unsupportedEh }; + byToken[token] = m; + byName[name] = m; + } + + // --- Script-defined types: field slots, .ctor → type mapping, and name → type --- + var fieldSlots = new Dictionary(); + var fieldSTypes = new Dictionary(); + var fieldIsScStruct = new HashSet(); + var fieldToTypeDef = new Dictionary(); // FieldDef token → declaring TypeDef token + var ctorToType = new Dictionary(); + var typeDefToCtorTok = new Dictionary(); // TypeDef token → default .ctor MethodDef token + var typeDefToType = new Dictionary(); // TypeDef token → type + var typesByName = new Dictionary(); + // Script types implementing System.Collections.IEnumerator → their driver members, + // so the host bridge (ScriptEnumerator) can pump an interpreted state machine. + var enumeratorTypes = new Dictionary(); + // (descriptor, per-field nested-struct TypeDef token) pending resolution once all types exist. + var pendingStructFields = new List<(ScriptTypeDescriptor desc, int[] typeDefs)>(); + + // This type's own INSTANCE fields, declaration order. Statics are excluded: an enum's + // members are static literals typed as the enum itself, which made the descriptor + // self-referential and recursed ScriptObject.Create forever. + List GetOwnInstanceFields(TypeDefinition td) + { + var handles = td.GetFields(); + var result = new List(handles.Count); + foreach (var fh in handles) + if ((reader.GetFieldDefinition(fh).Attributes & FieldAttributes.Static) == 0) + result.Add(fh); + return result; + } + + // Base-first field layout ([root base]..[own]), walking in-assembly BaseTypes. ownStart = + // first own field. Invariant this fix relies on: a base field lands at the identical + // slot/offset in every descriptor that inherits it. + List BuildBaseFirstFields(TypeDefinition td, out int ownStart, int depth = 0) + { + // Guard against a cyclic base chain (A : B, B : A) in hostile metadata — an unbounded + // recursion here is a StackOverflowException, which .NET cannot catch (whole-process + // kill). A real inheritance depth never approaches this. + if (depth > 256) + throw new ScriptValidationException( + "base-type chain is too deep or cyclic — malformed metadata"); + List fields; + var bt = td.BaseType; + if (bt.Kind == HandleKind.TypeDefinition) + { + var baseTd = reader.GetTypeDefinition((TypeDefinitionHandle)bt); + var baseName = reader.GetString(baseTd.Name); + fields = (baseName == "ValueType" || baseName == "Enum") + ? new List() + : BuildBaseFirstFields(baseTd, out _, depth + 1); + } + else + { + fields = new List(); + } + ownStart = fields.Count; + fields.AddRange(GetOwnInstanceFields(td)); + return fields; + } + + foreach (var typeHandle in reader.TypeDefinitions) + { + var typeDef = reader.GetTypeDefinition(typeHandle); + var typeName = reader.GetString(typeDef.Name); + if (typeName == "") continue; + + // Detect a script-defined struct (base type System.ValueType, excluding enums whose base is + // System.Enum). Used to zero-init `new T[n]` elements to usable structs rather than nulls. + bool isStructType = false; + { + var bt = typeDef.BaseType; + string baseName = ""; + if (bt.Kind == HandleKind.TypeReference) + baseName = reader.GetString(reader.GetTypeReference((TypeReferenceHandle)bt).Name); + else if (bt.Kind == HandleKind.TypeDefinition) + baseName = reader.GetString(reader.GetTypeDefinition((TypeDefinitionHandle)bt).Name); + isStructType = baseName == "ValueType"; // "Enum" (also a value type) intentionally excluded + } + + // Assign field slots in declaration order, BASE-FIRST: inherited fields occupy the front + // (same indices/offsets as in their own descriptor), then this type's own fields. See + // BuildBaseFirstFields for the invariant this depends on. + var typeFields = BuildBaseFirstFields(typeDef, out int ownFieldStart).ToArray(); + var fieldSlotMap = new Dictionary(typeFields.Length); + var fldTypes = new SType[typeFields.Length]; + var fldOffsets = new int[typeFields.Length]; + HostBinding.StructLayout?[]? fldVtLayouts = null; // allocated on demand + bool[]? fldIsScStruct = null; // allocated on demand (nested value-type fields) + int[]? fldScStructTypeDef = null; // nested script-struct field's TypeDef token (resolved to a descriptor after the loop) + int primByteOff = 0; + int refSlotOff = 0; + for (int i = 0; i < typeFields.Length; i++) + { + int fieldToken = MetadataTokens.GetToken(typeFields[i]); + bool isOwnField = i >= ownFieldStart; + fieldSlotMap[fieldToken] = i; + // Global field maps are keyed by declaring type only, so register OWN fields here; + // an inherited field is registered by its own type's pass (base-first makes the + // value identical anyway, and re-keying it here corrupts declaring-type bookkeeping). + if (isOwnField) + fieldSlots[fieldToken] = (null!, i); // type filled in below + var fDef = reader.GetFieldDefinition(typeFields[i]); + var fSig = reader.GetBlobBytes(fDef.Signature); + // Field sig: [calling_conv(0x06), type_byte, ...] + // VALUETYPE (0x11) followed by compressed TypeRef/TypeDef token — check + // if it's a registered host struct; if so, store inline in PrimBytes (SType.Vt). + SType fst = SType.O; + HostBinding.StructLayout? vtLayout = null; + if (fSig.Length >= 2) + { + byte tb = fSig[1]; + // 0x03 = ELEMENT_TYPE_CHAR: char is I4-typed in the VM; omitting it typed a + // hoisted char field O (a ref slot), the mirror of the SigReturn char fix + // (found by fuzzing: a foreach-over-string char hoisted across a yield). + // nint/nuint (0x18/0x19) are NOT here: an I4 slot would truncate 64-bit + // handles (AndroidJNI-style IntPtrs); they ride O slots as boxed IntPtr. + if (tb is 0x02 or 0x03 or 0x04 or 0x05 or 0x06 or 0x07 or 0x08 or 0x09) + fst = SType.I4; + else if (tb == 0x0C) + fst = SType.R4; + else if (tb == 0x11 && fSig.Length >= 3) + { + // VALUETYPE: try to decode the TypeRef name and look up a struct layout + int codedIdx = 0, n = 2; + while (n < fSig.Length) + { + byte b = fSig[n++]; + if ((b & 0x80) == 0) { codedIdx |= b; break; } + if ((b & 0x40) == 0) { codedIdx = ((b & 0x3F) << 8) | fSig[n++]; break; } + codedIdx = ((b & 0x1F) << 24) | (fSig[n] << 16) | (fSig[n+1] << 8) | fSig[n+2]; n += 3; break; + } + int table = codedIdx & 0x03; int row = codedIdx >> 2; + string vtName = ""; + if (table == 1 && row > 0) // TypeRef + { + try { vtName = reader.GetString(reader.GetTypeReference(MetadataTokens.TypeReferenceHandle(row)).Name); } + catch { } + } + else if (table == 0 && row > 0) // TypeDef + { + try { vtName = reader.GetString(reader.GetTypeDefinition(MetadataTokens.TypeDefinitionHandle(row)).Name); } + catch { } + } + if (vtName != "" && binding != null && binding.TryGetStructLayout(vtName, out vtLayout) && vtLayout != null) + fst = SType.Vt; + else if (table == 0 && IsEnumTypeDef(reader, row)) + { + // VALUETYPE that is a script-defined ENUM: the value is a plain int, + // not a nested struct — classify I4 so loads/stores/compares treat it + // as a number and Create never allocates a ScriptObject for it. + fst = SType.I4; + } + else if (table == 0) + { + // VALUETYPE referencing a TypeDef in this assembly that isn't a registered + // host struct = a script-defined struct. Stored as O (boxed ScriptObject), + // so a value-load of this field must clone to preserve copy semantics. + if (isOwnField) fieldIsScStruct.Add(fieldToken); + (fldIsScStruct ??= new bool[typeFields.Length])[i] = true; + // Stash the field's own TypeDef token (0x02 table) to resolve to a descriptor + // after all types are built, so Create can allocate the nested struct. + (fldScStructTypeDef ??= new int[typeFields.Length])[i] = + MetadataTokens.GetToken(MetadataTokens.TypeDefinitionHandle(row)); + } + } + } + if (isOwnField) fieldSTypes[fieldToken] = fst; + fldTypes[i] = fst; + if (fst == SType.I4 || fst == SType.R4) + { + fldOffsets[i] = primByteOff; + primByteOff += 4; + } + else if (fst == SType.Vt && vtLayout != null) + { + // Align to 4 bytes (structs are naturally aligned in Marshal layout) + int align = (4 - primByteOff % 4) % 4; + primByteOff += align; + fldOffsets[i] = primByteOff; + primByteOff += vtLayout.Size; + if (primByteOff % 4 != 0) primByteOff += 4 - primByteOff % 4; + if (fldVtLayouts == null) fldVtLayouts = new HostBinding.StructLayout?[typeFields.Length]; + fldVtLayouts[i] = vtLayout; + } + else + { + fldOffsets[i] = refSlotOff; + refSlotOff++; + } + } + + var desc = new ScriptTypeDescriptor + { + Name = typeName, + FieldCount = typeFields.Length, + FieldSlots = fieldSlotMap, + FieldTypes = fldTypes, + FieldOffsets = fldOffsets, + PrimByteSize = primByteOff, + RefSlotCount = refSlotOff, + VtFieldLayouts = fldVtLayouts, + FieldIsScriptStruct = fldIsScStruct, + IsScriptStructValue = isStructType, + }; + + // Patch back the type reference into fieldSlots — OWN fields only (see isOwnField above). + foreach (var ft in fieldSlotMap) + if (ft.Value >= ownFieldStart) + fieldSlots[ft.Key] = (desc, ft.Value); + + typesByName[typeName] = desc; + if (fldScStructTypeDef != null) pendingStructFields.Add((desc, fldScStructTypeDef)); + + // Map TypeDef token → type descriptor (used by initobj lowering). + int typeDefTok = MetadataTokens.GetToken(typeHandle); + typeDefToType[typeDefTok] = desc; + // Map each OWN field → declaring TypeDef token (used by auto-initobj in stfld lowering). + // An inherited field's declaring TypeDef is registered when its own type is processed. + foreach (var ft in fieldSlotMap) + if (ft.Value >= ownFieldStart) + fieldToTypeDef[ft.Key] = typeDefTok; + + // Map each .ctor to this type; also record TypeDef → default-ctor for initobj handling. + foreach (var methodHandle in typeDef.GetMethods()) + { + var mDef = reader.GetMethodDefinition(methodHandle); + var mName = reader.GetString(mDef.Name); + if (mName != ".ctor") continue; + int ctorTok = MetadataTokens.GetToken(methodHandle); + ctorToType[ctorTok] = desc; + // Record the first ctor as the default; prefer the 0-arg ctor (ArgCount==1 = just `this`) + if (!typeDefToCtorTok.TryGetValue(typeDefTok, out _) || + (byToken.TryGetValue(ctorTok, out var ctorM) && ctorM.ArgCount == 1)) + typeDefToCtorTok[typeDefTok] = ctorTok; + } + + // --- Enumerator (iterator state-machine) detection --- + // A script type implementing System.Collections.IEnumerator — in practice a Roslyn + // `yield return` state machine — gets its driver members resolved so the host + // bridge (ScriptEnumerator) can pump it from Unity's coroutine scheduler. Reset is + // marked cold: its body is `throw new NotSupportedException()`, which the + // interpreter can't lower, and no driver ever calls it. + bool isEnumerator = false; + foreach (var ih in typeDef.GetInterfaceImplementations()) + { + var ii = reader.GetInterfaceImplementation(ih); + if (ii.Interface.Kind == HandleKind.TypeReference && + TypeRefFullName(reader, (TypeReferenceHandle)ii.Interface) == "System.Collections.IEnumerator") + { + isEnumerator = true; + break; + } + } + if (isEnumerator) + { + ParsedMethod? moveNext = null, getCurrent = null, dispose = null; + foreach (var mh in typeDef.GetMethods()) + { + if (!byToken.TryGetValue(MetadataTokens.GetToken(mh), out var pm)) continue; + switch (pm.Name) + { + case "MoveNext": + case "System.Collections.IEnumerator.MoveNext": + moveNext = pm; break; + // The non-generic getter — present in every flavor (a generic + // IEnumerator state machine also implements it). Overwrites a plain + // get_Current seen earlier; the plain name only fills when nothing + // better exists (hand-written enumerator without explicit impls). + case "System.Collections.IEnumerator.get_Current": + getCurrent = pm; break; + case "get_Current": + getCurrent ??= pm; break; + case "Dispose": + case "System.IDisposable.Dispose": + dispose = pm; break; + case "Reset": + case "System.Collections.IEnumerator.Reset": + pm.IsColdEnumeratorMember = true; break; + } + } + if (moveNext != null && getCurrent != null) + enumeratorTypes[desc] = new EnumeratorMembers(moveNext, getCurrent, dispose); + } + } + + // Resolve each script-struct field's nested TypeDef token to a descriptor now that every type + // is built (declaration order isn't guaranteed to be dependency order). Enables Create() to + // recursively allocate nested value-type fields. + foreach (var (desc, typeDefs) in pendingStructFields) + { + ScriptTypeDescriptor?[]? arr = null; + for (int i = 0; i < typeDefs.Length; i++) + if (typeDefs[i] != 0 && typeDefToType.TryGetValue(typeDefs[i], out var sub)) + (arr ??= new ScriptTypeDescriptor?[typeDefs.Length])[i] = sub; + desc.FieldStructDescriptors = arr; + } + + // --- Flat script-struct resolution (zero-GC structs) --- + // Recursively classify blittable script structs (no reference-frame fields, transitively), + // inline nested blittable struct FIELDS into the parent's PrimBytes (they were RefSlot + // ScriptObjects), and synthesize a FlatLayout so blittable structs live in Vt frame slots. + // Runs after FieldStructDescriptors resolution (needs nested descs) and before methods' + // flat metadata below. + { + var flatVisited = new HashSet(); + foreach (var d in typesByName.Values) + ResolveFlatScriptStruct(d, flatVisited, fieldSTypes, fieldIsScStruct); + + // Method metadata post-pass: locals/args/returns whose script-struct type resolved + // flat switch from the heap (O + clone_sc) representation to Vt. + foreach (var m in byToken.Values) + { + var ltds = m.LocalScriptStructTypeDefs; + if (ltds != null) + for (int j = 0; j < m.LocalCount && j < ltds.Length; j++) + if (ltds[j] != 0 && typeDefToType.TryGetValue(ltds[j], out var ld) && ld.FlatLayout != null) + { + (m.LocalStructLayouts ??= new HostBinding.StructLayout?[m.LocalCount])[j] = ld.FlatLayout; + if (m.LocalIsScriptStruct != null) m.LocalIsScriptStruct[j] = false; + } + var atds = m.ArgScriptStructTypeDefs; + if (atds != null) + for (int j = 0; j < m.ArgSTypes.Length && j < atds.Length; j++) + if (atds[j] != 0 && typeDefToType.TryGetValue(atds[j], out var ad) && ad.FlatLayout != null) + { + m.ArgSTypes[j] = SType.Vt; + (m.ArgStructLayouts ??= new HostBinding.StructLayout?[m.ArgSTypes.Length])[j] = ad.FlatLayout; + } + if (m.ReturnScriptStructTypeDef != 0 + && typeDefToType.TryGetValue(m.ReturnScriptStructTypeDef, out var rd) && rd.FlatLayout != null) + { + m.ReturnSType = SType.Vt; + m.ReturnStructLayout = rd.FlatLayout; + } + if (!m.IsStatic && m.DeclaringTypeDef != 0 + && typeDefToType.TryGetValue(m.DeclaringTypeDef, out var dd) && dd.FlatLayout != null) + m.ThisStructLayout = dd.FlatLayout; + } + } + + // --- Host calls: resolve MemberRef tokens --- + var hostCalls = new Dictionary(); + var hostCtors = new Dictionary(); + var hostFields = new Dictionary(); + var hostFieldDeclTypeTok = new Dictionary(); + var tokenNames = new Dictionary(); + var unboundHostMembers = new List(); + + foreach (var memberRefHandle in reader.MemberReferences) + { + var memberRef = reader.GetMemberReference(memberRefHandle); + var memberName = reader.GetString(memberRef.Name); + int token = MetadataTokens.GetToken(memberRefHandle); + + string typeName2 = ""; + string typeNs2 = ""; + if (memberRef.Parent.Kind == HandleKind.TypeReference) + { + var typeRef = reader.GetTypeReference((TypeReferenceHandle)memberRef.Parent); + typeName2 = reader.GetString(typeRef.Name); + typeNs2 = reader.GetString(typeRef.Namespace); + } + else if (memberRef.Parent.Kind == HandleKind.TypeSpecification) + { + typeName2 = ResolveTypeSpecName(reader, (TypeSpecificationHandle)memberRef.Parent); + } + + // Field refs have signature byte 0x06 (FIELD calling convention) + var sigBytes = reader.GetBlobBytes(memberRef.Signature); + if (sigBytes.Length > 0 && sigBytes[0] == 0x06) + { + if (binding != null && binding.TryGetField($"{typeName2}.{memberName}", out var fe)) + { + hostFields[token] = fe!; + if (memberRef.Parent.Kind == HandleKind.TypeReference) + hostFieldDeclTypeTok[token] = MetadataTokens.GetToken(memberRef.Parent); + // Classify the field type so the IR lowerer can emit ldfld_i4/ldfld_r4. Prefer the + // binding's FieldSt (derived from the CLR field type, so it knows an enum is I4); the + // signature-byte guess below can't distinguish an enum (0x11 VALUETYPE) from a struct + // and would mis-type it O. Fall back to the sig guess only when FieldSt is unset (O). + if (fe!.FieldSt != SType.O) + fieldSTypes[token] = fe.FieldSt; + else if (sigBytes.Length >= 2) + fieldSTypes[token] = sigBytes[1] switch + { + // nint/nuint (0x18/0x19) stay O: boxed IntPtr, no 64-bit truncation + 0x02 or 0x04 or 0x05 or 0x06 or 0x07 or 0x08 or 0x09 => SType.I4, + 0x0C => SType.R4, + _ => SType.O, + }; + } + else if (binding != null && memberRef.Parent.Kind == HandleKind.TypeSpecification + && ResolveClosedSpecType(reader, (TypeSpecificationHandle)memberRef.Parent, binding) is { } fldDecl + && fldDecl.GetField(memberName) is { } specFi) + { + // Field reached through a closed generic instantiation (ValueTuple`2.Item1): + // synthesize per token — each instantiation's MemberRef row carries its own + // FieldInfo. Reads only on value types: writing through the boxed receiver + // would alias every copy of the struct (silent value-semantics break). + var specFe = HostBinding.BuildFieldEntry(specFi); + if (fldDecl.IsValueType) + { + var fname = $"{typeName2}.{memberName}"; + specFe.Set = (_, _2) => throw new ScriptRuntimeException( + $"assigning {fname} through a boxed struct is not supported — construct a new value instead"); + } + hostFields[token] = specFe; + if (specFe.FieldSt != SType.O) + fieldSTypes[token] = specFe.FieldSt; + } + else if (binding != null) + unboundHostMembers.Add($"{typeName2}.{memberName} (field)"); + continue; + } + + // Constructor — registered ones become host ctors; others are no-op base inits. + // System.Object::.ctor() is always the canonical base ctor (script chains to it + // via `ldarg.0; call .ctor`); force it to noop even if a name-only collision + // (e.g. UnityEngine.Object also being registered) would otherwise route it to + // hostCtors. Lookups in `_entries` are unqualified `TypeName..ctor/N`. + if (memberName == ".ctor") + { + int memberParamCount0 = DecompressInt(sigBytes, 1); + // new Nullable(v) — including the implicit T→T? conversion and `T? x = v;` local + // inits (ldloca + call .ctor, routed through the Call lowering's hostCtor pattern). + // The interpreter stores nullables the way CLR boxing does — as the boxed T, or + // null — so construction is the identity on the single argument. + if (memberParamCount0 == 1 && typeName2 == "Nullable`1" + && memberRef.Parent.Kind == HandleKind.TypeSpecification) + { + var nullableCtor = new HostBinding.Entry + { + Delegate = (_, args) => args[0], + ParamCount = 1, + HasThis = false, + }; + hostCtors[token] = new HostEntry { Binding = nullableCtor, IsVoid = true }; + continue; + } + // In-script `new List()` / Dictionary / HashSet / Queue / Stack: the shimmed + // collections dispatch every member on the receiver's runtime type, so construction + // was the only missing piece. Resolve the TypeSpec to its closed type and bind the + // ctor whose params decode concretely — the 0-arg and int-capacity overloads; a + // VAR-typed param (e.g. IEnumerable) fails the decode and stays loud-unsupported. + if (memberRef.Parent.Kind == HandleKind.TypeSpecification && binding != null + && (typeName2 is "List`1" or "Dictionary`2" or "HashSet`1" or "Queue`1" or "Stack`1" + || typeName2.StartsWith("ValueTuple`", StringComparison.Ordinal))) + { + var closedType = ResolveClosedSpecType(reader, (TypeSpecificationHandle)memberRef.Parent, binding); + ConstructorInfo? ci = null; + if (closedType != null) + { + if (memberParamCount0 == 0) + ci = closedType.GetConstructor(Type.EmptyTypes); + else if (DecodeMethodSigParamTypes(reader, sigBytes, binding) is { } ctorParams) + ci = closedType.GetConstructor(ctorParams); + // Tuple ctor params are VARs (!0, !1) — the sig decode can't name them, but + // for a CLOSED spec they are exactly the instantiation's type args. + if (ci == null && closedType.IsGenericType + && closedType.GetGenericArguments() is { } ga && ga.Length == memberParamCount0) + ci = closedType.GetConstructor(ga); + } + if (ci != null) + { + var ciLocal = ci; + var ctorParamTypes = Array.ConvertAll(ci.GetParameters(), p => p.ParameterType); + hostCtors[token] = new HostEntry + { + Binding = new HostBinding.Entry + { + // I4-slot identity erasure: a char/bool/enum arg arrives boxed as + // int; Invoke is strict, so coerce to the declared param type. + Delegate = (_, args) => + { + for (int ai = 0; ai < ctorParamTypes.Length; ai++) + { + var pt = ctorParamTypes[ai]; + if (args[ai] is int iv && pt != typeof(int) && pt != typeof(object)) + { + if (pt == typeof(char)) args[ai] = (char)iv; + else if (pt == typeof(bool)) args[ai] = iv != 0; + else if (pt.IsEnum) args[ai] = Enum.ToObject(pt, iv); + else if (pt == typeof(float)) args[ai] = (float)iv; + else args[ai] = HostBinding.ToFieldIntegral(iv, pt); + } + } + return ciLocal.Invoke(args); + }, + ParamCount = memberParamCount0, + HasThis = false, + }, + IsVoid = true, + }; + continue; + } + } + bool isSystemObjectCtor = typeNs2 == "System" && typeName2 == "Object" && memberParamCount0 == 0; + if (!isSystemObjectCtor && binding != null && binding.TryGet($"{typeName2}..ctor", memberParamCount0, out var ctorEntry)) + hostCtors[token] = new HostEntry { Binding = ctorEntry!, IsVoid = true }; + else + { + var noop = new HostBinding.Entry { Delegate = (_, _) => null, ParamCount = 0, HasThis = true }; + hostCalls[token] = new HostEntry { Binding = noop, IsVoid = true }; + } + continue; + } + + int memberParamCount = DecompressInt(sigBytes, 1); + var (sigIsVoid, sigRetSType, _) = SigReturn(sigBytes); + + tokenNames[token] = $"{typeName2}.{memberName}/{memberParamCount}"; + + // System.Object's members are intrinsics dispatched virtually on the receiver. + // Resolving them through the binding by SHORT name is wrong: "Object" collides with + // UnityEngine.Object in the standard surface, so a `constrained.` callvirt (e.g. + // `"impact" + quaternion` → Object.ToString on the boxed struct) invoked + // UnityEngine.Object.ToString with a foreign receiver — a TargetException the call + // site remapped to a misleading "called Object.ToString/0 on a null object". + // The namespace check mirrors the System.Object ctor special case above. + if (typeNs2 == "System" && typeName2 == "Object" + && memberRef.Parent.Kind == HandleKind.TypeReference) + { + bool objHasThis = sigBytes.Length > 0 && (sigBytes[0] & 0x20) != 0; + HostBinding.Entry objIntrinsic = memberName switch + { + "ToString" when objHasThis && memberParamCount == 0 => new HostBinding.Entry + { + Delegate = (recv, _) => recv != null ? recv.ToString() + : throw new ScriptRuntimeException("NullReferenceException: called Object.ToString on a null object"), + ParamCount = 0, HasThis = true, + }, + "GetHashCode" when objHasThis && memberParamCount == 0 => new HostBinding.Entry + { + Delegate = (recv, _) => recv != null ? recv.GetHashCode() + : throw new ScriptRuntimeException("NullReferenceException: called Object.GetHashCode on a null object"), + ParamCount = 0, HasThis = true, + }, + "GetType" when objHasThis && memberParamCount == 0 => new HostBinding.Entry + { + Delegate = (recv, _) => recv != null ? recv.GetType() + : throw new ScriptRuntimeException("NullReferenceException: called Object.GetType on a null object"), + ParamCount = 0, HasThis = true, + }, + "Equals" when objHasThis && memberParamCount == 1 => new HostBinding.Entry + { + Delegate = (recv, args) => recv != null ? recv.Equals(args![0]) + : throw new ScriptRuntimeException("NullReferenceException: called Object.Equals on a null object"), + ParamCount = 1, HasThis = true, + }, + "Equals" when !objHasThis && memberParamCount == 2 => new HostBinding.Entry + { Delegate = (_, args) => Equals(args![0], args[1]), ParamCount = 2, HasThis = false }, + "ReferenceEquals" when !objHasThis && memberParamCount == 2 => new HostBinding.Entry + { Delegate = (_, args) => ReferenceEquals(args![0], args[1]), ParamCount = 2, HasThis = false }, + _ => null!, + }; + if (objIntrinsic != null) + { + hostCalls[token] = new HostEntry + { Binding = objIntrinsic, IsVoid = false, SigRetSType = sigRetSType }; + continue; + } + } + + // VM intrinsic: IlInterpreter.Vm.Log → route to per-VM logSink. + if (typeNs2 == "IlInterpreter" && typeName2 == "Vm" && memberName == "Log" && memberParamCount == 1) + { + var entry = new HostBinding.Entry + { + Delegate = (_, args) => { logSink((string)args[0]!); return null; }, + ParamCount = 1, + HasThis = false, + }; + hostCalls[token] = new HostEntry { Binding = entry, IsVoid = true }; + continue; + } + + // System.Nullable members are intrinsics. The interpreter stores nullables the way + // CLR boxing does — as the boxed T, or null — so HasValue/Value/GetValueOrDefault + // reduce to null checks on the receiver slot's boxed value (the ldloca/ldflda receiver + // phantom resolves to that boxed value before the call). + if (typeName2 == "Nullable`1" && memberRef.Parent.Kind == HandleKind.TypeSpecification) + { + var (_, nullableArg) = DecodeGenericInstHeader(reader, (TypeSpecificationHandle)memberRef.Parent); + var nullableEntry = MakeNullableIntrinsic(memberName, memberParamCount, nullableArg, binding); + if (nullableEntry != null) + { + // Type the result slot from the RESOLVED type arg (not the open sig, which says + // bool for HasValue but generic T for Value/GetValueOrDefault -> O). get_HasValue + // -> I4 (bool); Value/GetValueOrDefault -> the type arg's SType. Without this the + // slot defaulted to O (boxed) and numeric ops on the result used object compares + // (found by fuzzing: `q != null` boxes, and `0 != q.GetValueOrDefault()` too). + hostCalls[token] = new HostEntry + { + Binding = nullableEntry, + IsVoid = false, + SigRetSType = NullableIntrinsicResultSType(memberName, nullableArg), + }; + continue; + } + // Unmodeled members (ToString, GetHashCode, Equals) fall through to the normal + // resolution/stub path. + } + + // TypeSpec: attempt MethodHandle-based resolution for generic types + if (memberRef.Parent.Kind == HandleKind.TypeSpecification && binding != null) + { + var (outerName, arg0Name) = DecodeGenericInstHeader( + reader, (TypeSpecificationHandle)memberRef.Parent); + if (outerName != "" && arg0Name != "" && + (binding.TryGetGenericType(outerName, arg0Name, out var genType) + || binding.TryMakeClosedGenericType(outerName, arg0Name, out genType))) + { + var mi = FindMethod(genType!, memberName, memberParamCount); + if (mi != null && binding.TryGetByHandle(mi.MethodHandle.Value, out var he)) + { + hostCalls[token] = new HostEntry { Binding = he!, IsVoid = sigIsVoid, ResolvedMethod = mi }; + continue; + } + // Mono: MethodHandle.Value for closed generic instantiations may differ + // between registration time and load time, causing TryGetByHandle to miss. + // Synthesize an Entry directly from the MethodInfo so the call still works. + if (mi != null) + { + hostCalls[token] = FallbackEntry(mi, sigIsVoid, + $"[IlInterpreter] TypeSpec handle fallback: {typeName2}.{memberName}/{memberParamCount}", logSink); + continue; + } + } + } + + // Signature-based resolution: TypeRef parent + registered type → decode full param types → GetMethod + if (memberRef.Parent.Kind == HandleKind.TypeReference && binding != null && + TryResolveReceiverTypeRef(reader, (TypeReferenceHandle)memberRef.Parent, typeName2, + binding, out var hostType2) && hostType2 != null) + { + var paramTypes = DecodeMethodSigParamTypes(reader, sigBytes, binding); + MethodInfo? mi2 = null; + if (paramTypes != null) + { + // Manual exact-signature scan rather than GetMethod: DefaultBinder ignores + // generic-ness, so a generic twin with the same parameter list (Go(string, + // object[]) vs Go(string, object[])) throws AmbiguousMatchException, and + // `new`-hiding across the hierarchy under Public|NonPublic does too. A plain + // MemberRef never targets a generic method definition (those calls arrive via + // MethodSpec), so skip them outright; GetMethods lists most-derived first, so + // a `new`-hidden pair resolves to the hiding member like a normal call would. + foreach (var m in hostType2.GetMethods( + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance)) + { + if (m.Name != memberName || m.IsGenericMethodDefinition) continue; + var ps = m.GetParameters(); + if (ps.Length != paramTypes.Length) continue; + bool exact = true; + for (int i = 0; i < ps.Length; i++) + if (ps[i].ParameterType != paramTypes[i]) { exact = false; break; } + if (exact) { mi2 = m; break; } + } + } + // Fallback: if sig decode failed (e.g. unregistered VALUETYPE param) and EXACTLY ONE + // non-generic method with this name+arity exists on the registered type, use it + // unambiguously. Multiple candidates → bail; the string-based fallback or a runtime + // error is safer than a silent mispick. Generic method definitions never count: + // a plain MemberRef row can't be their call site (those go through MethodSpec). + if (mi2 == null) + { + MethodInfo? unique = null; + foreach (var m in hostType2.GetMethods( + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance)) + { + if (m.Name != memberName || m.IsGenericMethodDefinition || + m.GetParameters().Length != memberParamCount) continue; + if (unique != null) { unique = null; break; } // ambiguous + unique = m; + } + mi2 = unique; + } + if (mi2 != null && binding.TryGetByHandle(mi2.MethodHandle.Value, out var he2)) + { + hostCalls[token] = new HostEntry { Binding = he2!, IsVoid = sigIsVoid, ResolvedMethod = mi2, ReceiverBox = ReceiverBoxFor(typeName2) }; + continue; + } + // Mono/IL2CPP: MethodHandle.Value may differ between registration and load time. + // When TryGetByHandle misses but the MethodInfo is unambiguous, synthesize an + // Entry directly — the string-keyed fallback only covers properties/operators. + if (mi2 != null) + { + hostCalls[token] = FallbackEntry(mi2, sigIsVoid, + $"[IlInterpreter] TypeRef handle fallback: {typeName2}.{memberName}/{memberParamCount}", logSink); + continue; + } + } + + // String-based fallback (properties, operators, AllowBcl, hand-wired Allow/AllowStatic) + if (binding != null && binding.TryGet($"{typeName2}.{memberName}", memberParamCount, out var entry2)) + { + // A TypeSpec member returning the generic VAR `!n` (Func`N.Invoke's TResult, + // List.get_Item, Enumerator.get_Current, KeyValuePair Key/Value, …) types O + // from the open signature — but `weights[0] + weights[2]` on a List then + // lowered add_i4 over boxed floats (sum 0), and `switch (s)` over a List + // element lowered brfalse_o on a boxed 0 (case silently missed). Recover the + // CLOSED return SType from the instantiation's n-th type argument — enums + // included (their values ride I4 like everywhere else). + var invRetSt = sigRetSType; + if (memberRef.Parent.Kind == HandleKind.TypeSpecification && invRetSt == SType.O) + { + var d = GenericVarReturnSType(reader, + (TypeSpecificationHandle)memberRef.Parent, sigBytes, binding); + if (d != SType.O) invRetSt = d; + } + hostCalls[token] = new HostEntry { Binding = entry2!, IsVoid = sigIsVoid, SigRetSType = invRetSt, ReceiverBox = ReceiverBoxFor(typeName2) }; + } + else + { + // Unregistered external call: stub that throws at runtime, so the method still + // lowers and the gap is reported in UnboundHostMembers at load time. + // + // EXCEPT open generic rows (GENERIC bit set on the calling convention): IL calls + // generic methods through MethodSpec tokens, which resolve — and report real gaps + // as 'Type.Name/N' — in the pass below. The open MemberRef row is only their + // metadata parent; reporting it too flagged every generic call as unbound + // ("Component.GetComponent/1") even when all instantiations resolved fine. + string msgKey = $"{typeName2}.{memberName}"; + bool isOpenGenericRow = sigBytes.Length > 0 && (sigBytes[0] & 0x10) != 0; + if (!isOpenGenericRow) + unboundHostMembers.Add($"{msgKey}/{memberParamCount}"); + var stub = new HostBinding.Entry + { + Delegate = (_, _) => throw new ScriptRuntimeException($"Host method '{msgKey}' is not registered in the binding"), + ParamCount = memberParamCount, + HasThis = sigBytes.Length > 0 && (sigBytes[0] & 0x20) != 0, + }; + hostCalls[token] = new HostEntry { Binding = stub, IsVoid = sigIsVoid }; + } + } + + // --- MethodSpec resolution: closed generic method calls (e.g. AddComponent) --- + // For each MethodSpec token, decode (open def, type args), instantiate via MakeGenericMethod, + // and register the resulting closed method under the methodspec token. + int msCount = reader.GetTableRowCount(TableIndex.MethodSpec); + for (int msRow = 1; msRow <= msCount; msRow++) + { + var msHandle = MetadataTokens.MethodSpecificationHandle(msRow); + var ms = reader.GetMethodSpecification(msHandle); + int token = MetadataTokens.GetToken(msHandle); + + // Parent for host generic methods is always a MemberRef (script-defined open generics + // are banned by the validator). + if (ms.Method.Kind != HandleKind.MemberReference) continue; + var parentRef = reader.GetMemberReference((MemberReferenceHandle)ms.Method); + if (parentRef.Parent.Kind != HandleKind.TypeReference) continue; + + var parentTypeRef = reader.GetTypeReference((TypeReferenceHandle)parentRef.Parent); + var parentType = reader.GetString(parentTypeRef.Name); + var parentName = reader.GetString(parentRef.Name); + + // Generic method signature: [conv-byte][genParamCount][paramCount]... + // The GENERIC bit (0x10) must be set on the calling-convention byte. + var parentSig = reader.GetBlobBytes(parentRef.Signature); + if (parentSig.Length < 3) continue; + int sigIdx = 0; + byte conv = parentSig[sigIdx++]; + if ((conv & 0x10) == 0) continue; + DecompressIntAdv(parentSig, ref sigIdx); // skip genParamCount + int paramCount = DecompressIntAdv(parentSig, ref sigIdx); + + if (binding == null) continue; + if (!binding.TryGetOpenGenerics(parentType, parentName, paramCount, out var openDefs)) + { + // Unregistered open generic: insert a runtime stub so the lowerer can still lower + // the method. The stub throws at runtime if the call is actually reached. + string stubKey = $"{parentType}.{parentName}/{paramCount}"; + unboundHostMembers.Add(stubKey); + bool hasThisStub = (conv & 0x20) != 0; + var stub2 = new HostBinding.Entry + { + Delegate = (_, _) => throw new ScriptRuntimeException($"Host generic method '{stubKey}' is not in the binding allowlist"), + ParamCount = paramCount, + HasThis = hasThisStub, + }; + hostCalls[token] = new HostEntry { Binding = stub2, IsVoid = false }; + continue; + } + + var typeArgs = DecodeMethodSpecArgs(reader, ms.Signature, binding, token); + // Several open overloads can share (type, name, arity) — Object.Instantiate has both + // (T, Transform, bool) and (T, Vector3, Quaternion). Pick by matching the MemberRef's + // parameter signature (sigIdx points at the return type here); a mispick invokes the + // wrong host method with type-mismatched args. + var openDef = openDefs!.Count == 1 + ? openDefs[0] + : SelectOpenGenericOverload(reader, openDefs!, parentSig, sigIdx, typeArgs); + if (openDef == null) + { + string stubKey = $"{parentType}.{parentName}/{paramCount}"; + unboundHostMembers.Add(stubKey + " (ambiguous overloads)"); + bool hasThisStub2 = (conv & 0x20) != 0; + var stub3 = new HostBinding.Entry + { + Delegate = (_, _) => throw new ScriptRuntimeException($"Host generic method '{stubKey}' has multiple overloads and none matched the call signature"), + ParamCount = paramCount, + HasThis = hasThisStub2, + }; + hostCalls[token] = new HostEntry { Binding = stub3, IsVoid = false }; + continue; + } + var closed = binding.GetOrMakeClosedMethod(openDef!, typeArgs); + bool hasThis = !openDef!.IsStatic; + var ps = closed.GetParameters(); + var msEntry = new HostBinding.Entry + { + Delegate = (recv, args) => closed.Invoke(recv, args), + ParamCount = ps.Length, + HasThis = hasThis, + Params = ps, + }; + // ResolvedMethod = the CLOSED generic method (e.g. Echo): its ReturnType is the + // concrete instantiation (int), so the call-site lowering types the result slot I4/R4 + // instead of defaulting to O. Without it a generic call returning int/float/bool boxed + // its result, and a numeric use (e.g. `Echo(x) != Echo(x)`) reference-compared + // two boxes (found by fuzzing the MethodSpec path). + hostCalls[token] = new HostEntry + { + Binding = msEntry, + IsVoid = closed.ReturnType == typeof(void), + ResolvedMethod = closed as MethodInfo, + }; + } + + // --- Token → Type map: resolve TypeRef/TypeSpec tokens for castclass/isinst/ldtoken --- + var tokenTypes = new Dictionary(); + if (binding != null) + { + foreach (var trHandle in reader.TypeReferences) + { + var tr = reader.GetTypeReference(trHandle); + var name = reader.GetString(tr.Name); + int tok = MetadataTokens.GetToken(trHandle); + // System primitives, so unbox.any is type-exact (a boxed char can't unbox to int), + // and isinst/castclass/typeof work on boxed primitives (box_prim gives them the real + // runtime type). The binding doesn't register these as host types. + Type? primType = reader.GetString(tr.Namespace) == "System" ? name switch + { + "Int32" => typeof(int), "Boolean" => typeof(bool), "Char" => typeof(char), + "Byte" => typeof(byte), "SByte" => typeof(sbyte), "Int16" => typeof(short), + "UInt16" => typeof(ushort), "UInt32" => typeof(uint), "Int64" => typeof(long), + "UInt64" => typeof(ulong), "Single" => typeof(float), "Double" => typeof(double), + _ => null, + } : null; + if (primType != null) + tokenTypes[tok] = primType; + else if (binding.TryGetTypeByName(name, out var t) && t != null) + tokenTypes[tok] = t; + } + int typeSpecCount = reader.GetTableRowCount(TableIndex.TypeSpec); + for (int tsRow = 1; tsRow <= typeSpecCount; tsRow++) + { + var tsHandle = MetadataTokens.TypeSpecificationHandle(tsRow); + int tok = MetadataTokens.GetToken(tsHandle); + var name = ResolveTypeSpecName(reader, tsHandle); + if (name != "" && binding.TryGetTypeByName(name, out var t) && t != null) + tokenTypes[tok] = t; + } + + // `new S { x = 1 }` / `default(S)` on a BOXED host struct local (AllowType, the + // auto-bind default) lowers to `ldloca; initobj S; ldloca; stfld x`. The O slot has + // no box yet, and stfld on null threw "Non-static field requires a target" (found + // live in CubeFlipr's Update). Give initobj a 0-arg "ctor" keyed by the TYPE token + // — disjoint from the MemberRef tokens real ctors use — so the lowerer can emit + // newobj_host to produce the default box for the following stores to mutate in + // place. Nullable keeps the ldnull path (null IS its representation here); + // primitives/enums live in numeric slots; flat structs never reach the O-slot path. + foreach (var kv in tokenTypes) + { + var vt = kv.Value; + if (!vt.IsValueType || vt.IsPrimitive || vt.IsEnum || Nullable.GetUnderlyingType(vt) != null) + continue; + if (hostCtors.ContainsKey(kv.Key)) continue; + var vtLocal = vt; + hostCtors[kv.Key] = new HostEntry + { + Binding = new HostBinding.Entry + { + Delegate = (_, _) => Activator.CreateInstance(vtLocal), + ParamCount = 0, HasThis = false, + }, + IsVoid = true, + }; + } + } + + // --- Embedded PDB: read sequence points for source-mapped errors --- + MetadataReaderProvider? pdbProvider = null; + foreach (var entry in pe.ReadDebugDirectory()) + { + if (entry.Type == DebugDirectoryEntryType.EmbeddedPortablePdb) + { + pdbProvider = pe.ReadEmbeddedPortablePdbDebugDirectoryData(entry); + break; + } + } + if (pdbProvider != null) + { + var pdbReader = pdbProvider.GetMetadataReader(); + // Document handle → short file name, resolved once per document. With #line directives + // in the compiled source (the code-reload transform emits them), documents are the USER's + // files, so the name makes error locations self-locating: " at line 394 (TankAI.cs)". + var docNames = new Dictionary(); + foreach (var handle in reader.MethodDefinitions) + { + int token = MetadataTokens.GetToken(handle); + if (!byToken.TryGetValue(token, out var pm)) continue; + int row = MetadataTokens.GetRowNumber(handle); + var debugInfo = pdbReader.GetMethodDebugInformation(MetadataTokens.MethodDebugInformationHandle(row)); + if (debugInfo.SequencePointsBlob.IsNil) continue; + var points = new List<(int, int, string)>(); + foreach (var sp in debugInfo.GetSequencePoints()) + { + if (sp.IsHidden) continue; + if (!docNames.TryGetValue(sp.Document, out var doc)) + { + var fullName = sp.Document.IsNil ? "" : pdbReader.GetString(pdbReader.GetDocument(sp.Document).Name); + doc = Path.GetFileName(fullName); + docNames[sp.Document] = doc; + } + points.Add((sp.Offset, sp.StartLine, doc)); + } + if (points.Count > 0) + pm.SeqPoints = points.ToArray(); + } + } + + // Resolve flat-struct (Vt) layouts for every host call / host ctor whose params, + // return, or receiver are registered struct types. Done in one sweep at the end + // so the per-site HostEntry construction code stays unchanged. + foreach (var he in hostCalls.Values) FillStructInfo(he, binding, isCtor: false); + foreach (var he in hostCtors.Values) FillStructInfo(he, binding, isCtor: true); + + return new ParsedAssembly + { + ByToken = byToken, + ByName = byName, + HostCalls = hostCalls, + HostCtors = hostCtors, + HostFieldDeclTypeTok = hostFieldDeclTypeTok, + HostFields = hostFields, + TokenNames = tokenNames, + FieldSlots = fieldSlots, + FieldSTypes = fieldSTypes, + FieldIsScriptStruct = fieldIsScStruct, + FieldToTypeDef = fieldToTypeDef, + CtorToType = ctorToType, + TypeDefToCtorTok = typeDefToCtorTok, + TypeDefToType = typeDefToType, + TypesByName = typesByName, + EnumeratorTypes = enumeratorTypes, + TokenTypes = tokenTypes, + Reader = reader, + Pe = pe, + PdbProvider = pdbProvider, + UnboundHostMembers = unboundHostMembers, + HostSurface = binding, + }; + } + + // Build an intrinsic Entry for a System.Nullable member. The receiver arrives as the slot's + // boxed value — boxed T or null, the CLR boxed representation of a nullable — so the semantics + // are plain null checks. Returns null for members that aren't modeled (ToString, GetHashCode, + // Equals), which then resolve or stub through the normal path. + static HostBinding.Entry? MakeNullableIntrinsic(string memberName, int paramCount, string typeArgName, HostBinding? binding) + { + switch (memberName) + { + case "get_HasValue" when paramCount == 0: + return new HostBinding.Entry + { Delegate = (recv, _) => recv != null, ParamCount = 0, HasThis = true }; + + case "get_Value" when paramCount == 0: + return new HostBinding.Entry + { + Delegate = (recv, _) => recv ?? throw new ScriptRuntimeException( + "InvalidOperationException: Nullable object must have a value"), + ParamCount = 0, + HasThis = true, + }; + + case "GetValueOrDefault" when paramCount == 0: + { + // default(T), boxed once at load time. Stays null when T can't be resolved — safe + // for the compiler-generated uses (`x ?? y`, `x?.M()` evaluate GetValueOrDefault + // only alongside a HasValue guard); a hand-written call on an unresolved T yields + // null, which downstream O-slot ops treat as default anyway. + object? boxedDefault = null; + var t = ResolveNullableTypeArg(typeArgName, binding); + if (t != null && t.IsValueType) + try { boxedDefault = HostBinding.NormalizeIntegralReturn(Activator.CreateInstance(t)); } catch { /* keep null */ } + return new HostBinding.Entry + { Delegate = (recv, _) => recv ?? boxedDefault, ParamCount = 0, HasThis = true }; + } + + case "GetValueOrDefault" when paramCount == 1: + return new HostBinding.Entry + { Delegate = (recv, args) => recv ?? args[0], ParamCount = 1, HasThis = true }; + + default: + return null; + } + } + + // Result SType for a Nullable intrinsic. get_HasValue returns bool (I4); get_Value and + // GetValueOrDefault return T, whose SType comes from the RESOLVED type arg — the open signature + // says T (which SigReturn can only classify as O), so without this the result lands in a boxed + // O slot and a numeric comparison like `0 != n.GetValueOrDefault()` lowers to an OBJECT compare + // (reference-unequal) instead of an int compare (found by fuzzing). + static SType NullableIntrinsicResultSType(string memberName, string typeArgName) + { + if (memberName == "get_HasValue") return SType.I4; // bool + switch (typeArgName) + { + case "Boolean": case "Char": case "SByte": case "Byte": + case "Int16": case "UInt16": case "Int32": case "UInt32": + return SType.I4; + case "Single": case "Double": + return SType.R4; + default: + return SType.O; // long/ulong/enums/ref types stay boxed + } + } + + // Resolve a Nullable type-arg name (as produced by DecodeGenericInstHeader) to a Type: + // CLR primitive names first, then any binding-registered type. + static Type? ResolveNullableTypeArg(string name, HostBinding? binding) + { + switch (name) + { + case "Boolean": return typeof(bool); + case "Char": return typeof(char); + case "SByte": return typeof(sbyte); + case "Byte": return typeof(byte); + case "Int16": return typeof(short); + case "UInt16": return typeof(ushort); + case "Int32": return typeof(int); + case "UInt32": return typeof(uint); + case "Int64": return typeof(long); + case "UInt64": return typeof(ulong); + case "Single": return typeof(float); + case "Double": return typeof(double); + } + return binding != null && binding.TryGetTypeByName(name, out var t) ? t : null; + } + + // Build a HostEntry from a MethodInfo that slipped through TryGetByHandle (Mono/IL2CPP handle instability). + static HostEntry FallbackEntry(MethodInfo mi, bool isVoid, string label, Action logSink) + { + logSink(label); + var captured = mi; + var mp = mi.GetParameters(); + var entry = new HostBinding.Entry + { + Delegate = mi.IsStatic + ? (_, args) => captured.Invoke(null, args) + : (recv, args) => captured.Invoke(recv, args), + ParamCount = mp.Length, + HasThis = !mi.IsStatic, + Params = mp, + }; + return new HostEntry { Binding = entry, IsVoid = isVoid }; + } + + // Create one instance of the script's "Script" class and run its default .ctor. + // The ctor runs on the Vm (the sole engine) via _parsed, which Load() has already set. + ScriptObject? MakeInstance(ParsedAssembly asm) + { + if (!asm.TypesByName.TryGetValue("Script", out var desc)) return null; + var obj = ScriptObject.Create(desc); + // Find the default .ctor (ArgCount == 1 means just 'this') + foreach (var (tok, type) in asm.CtorToType) + { + if (type == desc && asm.ByToken.TryGetValue(tok, out var ctor) && ctor.ArgCount == 1) + { + (_vm ??= new Vm(this)).Invoke(ctor, new object?[] { obj }); // result discarded (ctor) + break; + } + } + return obj; + } + + // Recursive flat classification for script-defined structs (see the Parse call site). + // Relayouts a type in place when nested blittable struct fields move inline, updates the + // assembly-level per-field-token maps, and synthesizes FlatLayout for blittable structs + // (Size = PrimByteSize; box form = a ScriptObject whose PrimBytes IS the flat image). + static unsafe void ResolveFlatScriptStruct(ScriptTypeDescriptor desc, + HashSet visited, + Dictionary fieldSTypes, HashSet fieldIsScStruct) + { + if (!visited.Add(desc)) return; + var nested = desc.FieldStructDescriptors; + if (nested != null) + foreach (var nd in nested) + if (nd != null) ResolveFlatScriptStruct(nd, visited, fieldSTypes, fieldIsScStruct); + + bool anyInline = false; + if (desc.FieldIsScriptStruct != null && nested != null) + for (int i = 0; i < desc.FieldCount; i++) + if (desc.FieldIsScriptStruct[i] && i < nested.Length && nested[i]?.FlatLayout != null) + { anyInline = true; break; } + + if (anyInline) + { + int prim = 0, refs = 0; + for (int i = 0; i < desc.FieldCount; i++) + { + bool inline = desc.FieldIsScriptStruct != null && desc.FieldIsScriptStruct[i] + && nested != null && i < nested.Length && nested[i]?.FlatLayout != null; + var ft = desc.FieldTypes[i]; + if (inline) + { + var flay = nested![i]!.FlatLayout!; + prim = (prim + 3) & ~3; + desc.FieldOffsets[i] = prim; + prim += (flay.Size + 3) & ~3; + desc.FieldTypes[i] = SType.Vt; + (desc.VtFieldLayouts ??= new HostBinding.StructLayout?[desc.FieldCount])[i] = flay; + desc.FieldIsScriptStruct![i] = false; + nested![i] = null; + } + else if (ft == SType.I4 || ft == SType.R4) + { + desc.FieldOffsets[i] = prim; prim += 4; + } + else if (ft == SType.Vt) + { + var lay = desc.VtFieldLayouts![i]!; + prim = (prim + 3) & ~3; + desc.FieldOffsets[i] = prim; + prim += (lay.Size + 3) & ~3; + } + else + { + desc.FieldOffsets[i] = refs++; + } + } + desc.PrimByteSize = prim; + desc.RefSlotCount = refs; + foreach (var kv in desc.FieldSlots) + { + fieldSTypes[kv.Key] = desc.FieldTypes[kv.Value]; + if (desc.FieldTypes[kv.Value] == SType.Vt) fieldIsScStruct.Remove(kv.Key); + } + } + + if (desc.IsScriptStructValue && desc.RefSlotCount == 0 && desc.FlatLayout == null + // A local function's captured environment is a display STRUCT the caller mutates + // in place and passes BYREF (`call Scale(x, ref V_0)`). Flattening it splits the + // representation — caller writes Vt frame bytes, callee reads a ScriptObject — + // so the environment must stay ScriptObject-backed and shared by reference. + && !desc.Name.StartsWith("<>c__DisplayClass", StringComparison.Ordinal)) + { + int copyLen = desc.PrimByteSize; + int size = copyLen == 0 ? 4 : copyLen; // empty struct still occupies one slot + var d = desc; + HostBinding.BoxFromPtrDelegate box = src => + { + var so = ScriptObject.Create(d); + if (copyLen > 0) Marshal.Copy((IntPtr)src, so.PrimBytes, 0, copyLen); + return so; + }; + HostBinding.CopyToPtrDelegate copy = (dst, boxed) => + { + var so = (ScriptObject)boxed; + int n = so.PrimBytes.Length < copyLen ? so.PrimBytes.Length : copyLen; + if (n > 0) Marshal.Copy(so.PrimBytes, 0, (IntPtr)dst, n); + }; + // Fields is scanned BY OFFSET (host-call receiver materialization for primitives + // inside flat struct slots — `v.f0.ToString()`); metadata field names aren't retained + // on the descriptor, so keys are synthetic. Nested flat structs contribute their + // primitives at composed offsets (their own layouts were built first, bottom-up). + var flatFields = new Dictionary(desc.FieldCount); + for (int i = 0; i < desc.FieldCount; i++) + { + if (desc.FieldTypes[i] is SType.I4 or SType.R4) + flatFields["#" + i] = (desc.FieldOffsets[i], desc.FieldTypes[i]); + else if (desc.FieldTypes[i] == SType.Vt && desc.VtFieldLayouts?[i] is { } nlay) + foreach (var kv in nlay.Fields) + flatFields[$"#{i}.{kv.Key}"] = (desc.FieldOffsets[i] + kv.Value.Offset, kv.Value.St); + } + desc.FlatLayout = new HostBinding.StructLayout + { + Type = typeof(ScriptObject), + Size = size, + TypeName = desc.Name, + Fields = flatFields, + BoxFromPtr = box, + CopyToPtr = copy, + }; + } + } + + static int ReadLocalCount(MetadataReader reader, StandaloneSignatureHandle sig) + { + if (sig.IsNil) return 0; + var blob = reader.GetBlobBytes(reader.GetStandaloneSignature(sig).Signature); + if (blob.Length < 2 || blob[0] != 0x07) return 0; // 0x07 = LOCAL_SIG marker + int count = DecompressInt(blob, 1); + // Every local needs at least one byte of type signature, so a well-formed LOCAL_SIG can't + // declare more locals than the blob has bytes. A larger count is a lying/hostile signature + // that would otherwise size a per-local array from it and OOM in Parse. + if ((uint)count > (uint)blob.Length) + throw new ScriptValidationException( + $"LOCAL_SIG declares {count} locals but the signature blob is only {blob.Length} bytes — malformed metadata"); + return count; + } + + // Decode each local's struct layout from the LOCAL_SIG blob. Returns null when + // none are structs registered with the binding (saves an array allocation per method). + // LOCAL_SIG = 0x07 [count] (type)*. Per-local: optional CMOD/PINNED/BYREF prefixes, + // then ELEMENT_TYPE_VALUETYPE (0x11) + coded TypeDefOrRef → look up via TypeRef name. + static HostBinding.StructLayout?[]? ReadLocalStructLayouts( + MetadataReader reader, StandaloneSignatureHandle sig, int localCount, HostBinding? binding) + { + if (sig.IsNil || binding == null || localCount == 0) return null; + var blob = reader.GetBlobBytes(reader.GetStandaloneSignature(sig).Signature); + if (blob.Length < 2 || blob[0] != 0x07) return null; + int idx = 1; + DecompressIntAdv(blob, ref idx); // count (already known) + var result = new HostBinding.StructLayout?[localCount]; + bool any = false; + for (int i = 0; i < localCount && idx < blob.Length; i++) + { + // Skip CMOD_REQD (0x1F), CMOD_OPT (0x20), PINNED (0x45), BYREF (0x10) + while (idx < blob.Length && (blob[idx] == 0x1F || blob[idx] == 0x20 || blob[idx] == 0x45 || blob[idx] == 0x10)) + { + byte tag = blob[idx++]; + if (tag == 0x1F || tag == 0x20) DecompressIntAdv(blob, ref idx); + } + if (idx >= blob.Length) break; + byte t = blob[idx++]; + if (t == 0x11) // VALUETYPE + { + int coded = DecompressIntAdv(blob, ref idx); + int table = coded & 0x03; int row = coded >> 2; + if (table == 1) // TypeRef + { + var name = reader.GetString(reader.GetTypeReference(MetadataTokens.TypeReferenceHandle(row)).Name); + if (binding.TryGetStructLayout(name, out var lay)) { result[i] = lay; any = true; } + } + } + else + { + // Skip nested types (SZARRAY 0x1D, GENERICINST 0x15) — none are structs we track. + // Primitive types (I4/R4/...) — just consume the single tag byte (already done). + if (t == 0x12) DecompressIntAdv(blob, ref idx); // CLASS — also consumes coded index + else if (t == 0x1D) SkipSigType(blob, ref idx); // SZARRAY → recurse + else if (t == 0x15) + { + // GENERICINST: 0x11/0x12, coded index, arity, args. Skip conservatively. + if (idx < blob.Length) idx++; // value/class flag + if (idx < blob.Length) DecompressIntAdv(blob, ref idx); + if (idx < blob.Length) + { + int n = DecompressIntAdv(blob, ref idx); + for (int j = 0; j < n; j++) SkipSigType(blob, ref idx); + } + } + } + } + return any ? result : null; + } + + // Per-local DECLARED SType from the LocalVarSig (see ParsedMethod.LocalSTypes). Walks the blob + // exactly like ReadLocalStructLayouts to stay byte-aligned, but classifies each local into the + // FROZEN set — only the unambiguous, VM-consistent declared types. Anything else (valuetype/enum, + // long/ulong, double, nint/nuint, byref/pinned locals) is left null to fall back to inference, + // so this can only make typing MORE stable, never change a type the fuzzer hasn't validated. + static SType?[]? ReadLocalSTypes(MetadataReader reader, StandaloneSignatureHandle sig, int localCount) + { + if (sig.IsNil || localCount == 0) return null; + var blob = reader.GetBlobBytes(reader.GetStandaloneSignature(sig).Signature); + if (blob.Length < 2 || blob[0] != 0x07) return null; + int idx = 1; + DecompressIntAdv(blob, ref idx); // count (already known) + var result = new SType?[localCount]; + bool any = false; + for (int i = 0; i < localCount && idx < blob.Length; i++) + { + bool byRef = false; + while (idx < blob.Length && (blob[idx] == 0x1F || blob[idx] == 0x20 || blob[idx] == 0x45 || blob[idx] == 0x10)) + { + byte tag = blob[idx++]; + if (tag == 0x10) byRef = true; // BYREF local — not a plain value; fall back + else if (tag == 0x1F || tag == 0x20) DecompressIntAdv(blob, ref idx); // CMOD token + } + if (idx >= blob.Length) break; + byte t = blob[idx++]; + SType? st; + if (t == 0x11 || t == 0x12) + { + DecompressIntAdv(blob, ref idx); // TypeDefOrRef token (also the alignment skip) + // CLASS (0x12) is a reference -> O. VALUETYPE (0x11) is left to inference: a host + // struct is Vt / a script struct is O (classified elsewhere), and an ENUM is NOT + // safely I4 here — an enum local zero-inited via `initobj En` takes the script-object + // path, so freezing it I4 regressed real fuzzed programs (oracle [False] vs interp []). + st = t == 0x12 ? SType.O : (SType?)null; + } + else + { + st = t switch + { + 0x02 or 0x03 or 0x04 or 0x05 or 0x06 or 0x07 or 0x08 or 0x09 => SType.I4, // bool,char,i1,u1,i2,u2,i4,u4 + 0x0C => SType.R4, // float + 0x0A or 0x0B => SType.I8, // long/ulong — wide slot + 0x0D => SType.R8, // double — wide slot + 0x0E or 0x1C or 0x1D or 0x15 => SType.O, // string,object,array,generic + _ => (SType?)null, // nint/… left to inference (rare or validator-rejected) + }; + // Keep idx aligned for the next local (mirror ReadLocalStructLayouts's skips). + if (t == 0x1D) SkipSigType(blob, ref idx); + else if (t == 0x15) + { + if (idx < blob.Length) idx++; // value/class flag + if (idx < blob.Length) DecompressIntAdv(blob, ref idx); + if (idx < blob.Length) { int n = DecompressIntAdv(blob, ref idx); for (int j = 0; j < n; j++) SkipSigType(blob, ref idx); } + } + } + if (byRef) st = null; + if (st is { }) { result[i] = st; any = true; } + } + return any ? result : null; + } + + // True when TypeDef row `row` in this assembly is an enum (base type System.Enum). Enum values + // are I4 ints, not nested script structs — the distinction matters wherever a VALUETYPE TypeDef + // is classified (fields, locals): misclassifying an enum as a struct gives it object identity + // and, through its own static literal members, a self-referential descriptor. + static bool IsEnumTypeDef(MetadataReader reader, int row) + { + try + { + var bt = reader.GetTypeDefinition(MetadataTokens.TypeDefinitionHandle(row)).BaseType; + return bt.Kind switch + { + HandleKind.TypeReference => reader.GetString(reader.GetTypeReference((TypeReferenceHandle)bt).Name) == "Enum", + HandleKind.TypeDefinition => reader.GetString(reader.GetTypeDefinition((TypeDefinitionHandle)bt).Name) == "Enum", + _ => false, + }; + } + catch { return false; } + } + + // Decode which locals are SCRIPT-defined structs: ELEMENT_TYPE_VALUETYPE (0x11) whose + // TypeDefOrRef coded token resolves to a TypeDef (table 0 — defined in THIS assembly), as opposed + // to a TypeRef (table 1 — a host struct, handled by ReadLocalStructLayouts). Such locals are stored + // as O ScriptObject references, so a value load must clone them. Returns null when none qualify. + static bool[]? ReadLocalIsScriptStruct( + MetadataReader reader, StandaloneSignatureHandle sig, int localCount, out int[]? typeDefs) + { + typeDefs = null; + if (sig.IsNil || localCount == 0) return null; + var blob = reader.GetBlobBytes(reader.GetStandaloneSignature(sig).Signature); + if (blob.Length < 2 || blob[0] != 0x07) return null; + int idx = 1; + DecompressIntAdv(blob, ref idx); // count (already known) + var result = new bool[localCount]; + bool any = false; + for (int i = 0; i < localCount && idx < blob.Length; i++) + { + // Skip CMOD_REQD (0x1F), CMOD_OPT (0x20), PINNED (0x45), BYREF (0x10) + while (idx < blob.Length && (blob[idx] == 0x1F || blob[idx] == 0x20 || blob[idx] == 0x45 || blob[idx] == 0x10)) + { + byte tag = blob[idx++]; + if (tag == 0x1F || tag == 0x20) DecompressIntAdv(blob, ref idx); + } + if (idx >= blob.Length) break; + byte t = blob[idx++]; + if (t == 0x11) // VALUETYPE + { + int coded = DecompressIntAdv(blob, ref idx); + if ((coded & 0x03) == 0) // table 0 == TypeDef + { + result[i] = true; any = true; + (typeDefs ??= new int[localCount])[i] = + MetadataTokens.GetToken(MetadataTokens.TypeDefinitionHandle(coded >> 2)); + } + } + else if (t == 0x12) DecompressIntAdv(blob, ref idx); // CLASS: consume coded index + else if (t == 0x1D) SkipSigType(blob, ref idx); // SZARRAY: recurse + else if (t == 0x15) // GENERICINST: skip + { + if (idx < blob.Length) idx++; + if (idx < blob.Length) DecompressIntAdv(blob, ref idx); + if (idx < blob.Length) + { + int n = DecompressIntAdv(blob, ref idx); + for (int j = 0; j < n; j++) SkipSigType(blob, ref idx); + } + } + } + return any ? result : null; + } + + // Decode a TypeSpec signature to extract the simple type name. + // TypeSpec for a generic instantiation: 0x15 (CLASS|VALUETYPE) coded-index arg-count args... + static string ResolveTypeSpecName(MetadataReader reader, TypeSpecificationHandle handle) + { + var blob = reader.GetBlobBytes(reader.GetTypeSpecification(handle).Signature); + if (blob.Length < 3 || blob[0] != 0x15) return ""; + int codedIndex = DecompressInt(blob, 2); + int table = codedIndex & 0x03; + int row = codedIndex >> 2; + if (table == 1) // TypeRef + return reader.GetString(reader.GetTypeReference(MetadataTokens.TypeReferenceHandle(row)).Name); + if (table == 0) // TypeDef + return reader.GetString(reader.GetTypeDefinition(MetadataTokens.TypeDefinitionHandle(row)).Name); + return ""; + } + + // Parses the return info from a method signature blob. + // Sig layout: [callconv (1 byte)] [paramCount (compressed)] [CMOD_REQD/OPT*] [returnType] ... + // How an I4-slot receiver of an instance host call on this type must be boxed (see ReceiverBox). + static ReceiverBoxKind ReceiverBoxFor(string typeName) => typeName switch + { + "Char" => ReceiverBoxKind.Char, + "Boolean" => ReceiverBoxKind.Bool, + _ => ReceiverBoxKind.None, + }; + + // Returns (isVoid, retSType, isBool): retSType is O when isVoid is true. isBool is true only for + // ELEMENT_TYPE_BOOLEAN — bool collapses to I4 for storage, but the method-return boxing must + // still hand back a boxed bool (not int), so callers casting the result to bool don't fault. + static (bool isVoid, SType retSType, bool isBool) SigReturn(byte[] sig) + { + if (sig.Length < 3) return (false, SType.O, false); + int idx = 1; // skip calling convention byte + DecompressIntAdv(sig, ref idx); // skip paramCount + // skip custom modifiers (CMOD_REQD=0x1F, CMOD_OPT=0x20) each followed by a compressed type ref + while (idx < sig.Length && (sig[idx] == 0x1F || sig[idx] == 0x20)) + { + idx++; // skip modifier tag + DecompressIntAdv(sig, ref idx); // skip encoded type reference + } + if (idx >= sig.Length) return (false, SType.O, false); + byte tb = sig[idx]; + if (tb == 0x01) return (true, SType.O, false); // ELEMENT_TYPE_VOID + SType st = tb switch + { + // 0x03 = ELEMENT_TYPE_CHAR: char is I4-typed in the VM; omitting it left a char return + // (e.g. String.get_Chars) boxed in an O slot, read back as 0. (found by fuzzing.) + // nint/nuint (0x18/0x19) stay O: boxed IntPtr, no 64-bit truncation. + 0x02 or 0x03 or 0x04 or 0x05 or 0x06 or 0x07 or 0x08 or 0x09 => SType.I4, + 0x0C => SType.R4, + 0x0A or 0x0B => SType.I8, // long/ulong — wide slot + 0x0D => SType.R8, // double — wide slot + _ => SType.O, + }; + return (false, st, tb == 0x02); // 0x02 = ELEMENT_TYPE_BOOLEAN + } + + // Parse explicit parameter types from a method signature blob. + // Returns SType[] of length = explicit param count (not counting implicit `this`). + static SType[] SigParamSTypes(byte[] sig) + { + if (sig.Length < 2) return Array.Empty(); + int idx = 1; // skip calling convention + int paramCount = DecompressIntAdv(sig, ref idx); + if (paramCount == 0) return Array.Empty(); + // skip return type (with optional modopt/modreq then the whole type) + while (idx < sig.Length && (sig[idx] == 0x1F || sig[idx] == 0x20)) + { idx++; DecompressIntAdv(sig, ref idx); } + // Skip the ENTIRE return type via SkipSigType. Consuming only the leading tag left a + // compound return's inner tag (SZARRAY/GENERICINST) to be read as the first parameter's + // type, desyncing every following param by one signature byte. + if (idx < sig.Length) SkipSigType(sig, ref idx); + var result = new SType[paramCount]; + for (int p = 0; p < paramCount && idx < sig.Length; p++) + { + // skip any modopt/modreq + while (idx < sig.Length && (sig[idx] == 0x1F || sig[idx] == 0x20)) + { idx++; DecompressIntAdv(sig, ref idx); } + if (idx >= sig.Length) break; + byte tb = sig[idx++]; + result[p] = tb switch + { + // 0x03 = ELEMENT_TYPE_CHAR — I4-typed in the VM (see SigReturn). + // nint/nuint (0x18/0x19) stay O: boxed IntPtr, no 64-bit truncation. + 0x02 or 0x03 or 0x04 or 0x05 or 0x06 or 0x07 or 0x08 or 0x09 => SType.I4, + 0x0C => SType.R4, + 0x0A or 0x0B => SType.I8, // long/ulong — wide slot + 0x0D => SType.R8, // double — wide slot + _ => SType.O, + }; + // VALUETYPE (0x11) and CLASS (0x12) are followed by a compressed type token — skip it. + if (tb == 0x11 || tb == 0x12) DecompressIntAdv(sig, ref idx); + // Array/generic params carry a nested type — skip it so the next param's tag is read + // from the right position (e.g. `(int[] a, MyStruct s)` would otherwise desync). + else if (tb == 0x1D || tb == 0x15) SkipSigType(sig, ref idx); + } + return result; + } + + // Walks a method signature like SigReturn/SigParamSTypes but captures the TypeDef token of + // every VALUETYPE (0x11, coded table 0) return/param — script-defined struct types. Returns + // (returnTypeDefTok, perParamTypeDefToks); 0 / null when not script structs. + static (int retTok, int[]? paramToks) ReadSigScriptStructTokens(byte[] sig) + { + if (sig.Length < 3) return (0, null); + int idx = 1; + int paramCount = DecompressIntAdv(sig, ref idx); + while (idx < sig.Length && (sig[idx] == 0x1F || sig[idx] == 0x20)) + { idx++; DecompressIntAdv(sig, ref idx); } + if (idx >= sig.Length) return (0, null); + + int retTok = 0; + byte retTb = sig[idx++]; + if (retTb == 0x11 || retTb == 0x12) + { + int coded = DecompressIntAdv(sig, ref idx); + if (retTb == 0x11 && (coded & 0x03) == 0) + retTok = MetadataTokens.GetToken(MetadataTokens.TypeDefinitionHandle(coded >> 2)); + } + else if (retTb == 0x1D) SkipSigType(sig, ref idx); // SZARRAY return + + int[]? paramToks = null; + for (int pi = 0; pi < paramCount && idx < sig.Length; pi++) + { + while (idx < sig.Length && (sig[idx] == 0x1F || sig[idx] == 0x20)) + { idx++; DecompressIntAdv(sig, ref idx); } + if (idx >= sig.Length) break; + byte tb = sig[idx++]; + if (tb == 0x11 || tb == 0x12) + { + int coded = DecompressIntAdv(sig, ref idx); + if (tb == 0x11 && (coded & 0x03) == 0) + (paramToks ??= new int[paramCount])[pi] = + MetadataTokens.GetToken(MetadataTokens.TypeDefinitionHandle(coded >> 2)); + } + else if (tb == 0x1D) SkipSigType(sig, ref idx); // SZARRAY param + else if (tb == 0x15) SkipSigType(sig, ref idx); // GENERICINST — conservative skip + } + return (retTok, paramToks); + } + + static int DecompressInt(byte[] b, int i) + { + if ((b[i] & 0x80) == 0) return b[i]; + if ((b[i] & 0xC0) == 0x80) return ((b[i] & 0x3F) << 8) | b[i + 1]; + return ((b[i] & 0x1F) << 24) | (b[i + 1] << 16) | (b[i + 2] << 8) | b[i + 3]; + } + + // DecompressInt variant that advances the index past the compressed integer. + static int DecompressIntAdv(byte[] b, ref int idx) + { + byte first = b[idx]; + if ((first & 0x80) == 0) { idx += 1; return first; } + if ((first & 0xC0) == 0x80) { int v = ((first & 0x3F) << 8) | b[idx + 1]; idx += 2; return v; } + int v4 = ((first & 0x1F) << 24) | (b[idx + 1] << 16) | (b[idx + 2] << 8) | b[idx + 3]; + idx += 4; return v4; + } + + // Decode a TypeSpec GENERICINST blob: returns (outerTypeName, firstArgTypeName). + /// SType of a Func`N TypeSpec's LAST generic arg — its TResult. Func`N is + /// 0x15 (CLASS) coded-outer argCount T1..Tn TResult; the return is the final arg. + /// Skips the leading args, then maps the final arg's element-type tag to I4 (integral/bool/ + /// char) or R4 (Single); anything else (String, object, another generic) stays O so only + /// primitive delegate results get numeric-frame typing. Returns O on any decode failure. + // Closed return SType for a TypeSpec member whose signature returns the generic VAR `!n`: + // decode n from the member sig, then read the instantiation's n-th type argument. + // Primitives map to their slot type; enums (host TypeRef or script TypeDef) map to I4; + // everything else — and any decode wobble — stays O, the pre-existing behavior. + static SType GenericVarReturnSType( + MetadataReader reader, TypeSpecificationHandle spec, byte[] memberSig, HostBinding? binding) + { + try + { + int idx = 0; + byte conv = memberSig[idx++]; + if ((conv & 0x10) != 0) DecompressIntAdv(memberSig, ref idx); // genParamCount + DecompressIntAdv(memberSig, ref idx); // paramCount + if (idx >= memberSig.Length || memberSig[idx] != 0x13) return SType.O; // ELEMENT_TYPE_VAR + idx++; + int varIdx = DecompressIntAdv(memberSig, ref idx); + + var blob = reader.GetBlobBytes(reader.GetTypeSpecification(spec).Signature); + if (blob.Length < 4 || blob[0] != 0x15) return SType.O; // GENERICINST + int b = 2; // skip 0x15 and the CLASS/VALUETYPE tag + DecompressIntAdv(blob, ref b); // generic definition coded index + int argc = DecompressIntAdv(blob, ref b); + for (int i = 0; i < argc && b < blob.Length; i++) + { + if (i != varIdx) { if (!SkipSigType(blob, ref b)) return SType.O; continue; } + byte tag = blob[b]; + switch (tag) + { + case 0x02: case 0x03: case 0x04: case 0x05: + case 0x06: case 0x07: case 0x08: case 0x09: + return SType.I4; + case 0x0C: + return SType.R4; + case 0x11: // VALUETYPE coded index — enum type args ride I4 + { + int c = b + 1; + int coded = DecompressIntAdv(blob, ref c); + if ((coded & 0x03) == 0 && IsEnumTypeDef(reader, coded >> 2)) return SType.I4; + if ((coded & 0x03) == 1 && binding != null + && ResolveSigTypeRef(reader, MetadataTokens.TypeReferenceHandle(coded >> 2), binding) + is { IsEnum: true }) return SType.I4; + return SType.O; + } + default: + return SType.O; + } + } + return SType.O; + } + catch { return SType.O; } + } + + static SType FuncReturnSType(MetadataReader reader, TypeSpecificationHandle handle) + { + try + { + var blob = reader.GetBlobBytes(reader.GetTypeSpecification(handle).Signature); + if (blob.Length < 3 || blob[0] != 0x15) return SType.O; + int idx = 2; // skip 0x15 (GENERICINST) and 0x11/0x12 (CLASS/VALUETYPE) + DecompressIntAdv(blob, ref idx); // coded index of the open type (Func`N) + int argCount = DecompressIntAdv(blob, ref idx); + if (argCount < 1) return SType.O; + for (int i = 0; i < argCount - 1; i++) // skip T1..Tn, leaving TResult + if (!SkipSigType(blob, ref idx)) return SType.O; + if (idx >= blob.Length) return SType.O; + return blob[idx] switch + { + 0x02 or 0x03 or 0x04 or 0x05 or 0x06 or 0x07 or 0x08 or 0x09 => SType.I4, // bool/char/sub-int/int/uint + 0x0C => SType.R4, // Single + _ => SType.O, + }; + } + catch { return SType.O; } + } + + static (string, string) DecodeGenericInstHeader(MetadataReader reader, TypeSpecificationHandle handle) + { + var blob = reader.GetBlobBytes(reader.GetTypeSpecification(handle).Signature); + if (blob.Length < 3 || blob[0] != 0x15) return ("", ""); + + int idx = 2; // skip 0x15 and 0x11/0x12 + int codedIndex = DecompressIntAdv(blob, ref idx); + int table = codedIndex & 0x03; + int row = codedIndex >> 2; + + string outerName; + if (table == 1) + outerName = reader.GetString(reader.GetTypeReference(MetadataTokens.TypeReferenceHandle(row)).Name); + else if (table == 0) + outerName = reader.GetString(reader.GetTypeDefinition(MetadataTokens.TypeDefinitionHandle(row)).Name); + else return ("", ""); + + int argCount = DecompressIntAdv(blob, ref idx); + if (argCount < 1 || idx >= blob.Length) return (outerName, ""); + + byte argTag = blob[idx++]; + string arg0Name = ""; + switch (argTag) + { + case 0x02: arg0Name = "Boolean"; break; + case 0x03: arg0Name = "Char"; break; + case 0x04: arg0Name = "SByte"; break; + case 0x05: arg0Name = "Byte"; break; + case 0x06: arg0Name = "Int16"; break; + case 0x07: arg0Name = "UInt16"; break; + case 0x08: arg0Name = "Int32"; break; + case 0x09: arg0Name = "UInt32"; break; + case 0x0A: arg0Name = "Int64"; break; + case 0x0B: arg0Name = "UInt64"; break; + case 0x0C: arg0Name = "Single"; break; + case 0x0D: arg0Name = "Double"; break; + case 0x0E: arg0Name = "String"; break; + case 0x11: case 0x12: + { + int ac = DecompressIntAdv(blob, ref idx); + int at = ac & 0x03; int ar = ac >> 2; + if (at == 1) arg0Name = reader.GetString(reader.GetTypeReference(MetadataTokens.TypeReferenceHandle(ar)).Name); + else if (at == 0) arg0Name = reader.GetString(reader.GetTypeDefinition(MetadataTokens.TypeDefinitionHandle(ar)).Name); + break; + } + } + return (outerName, arg0Name); + } + + // Resolve a TypeSpecification handle to its closed runtime Type (List`1 → List). + // Null when any piece of the signature is unsupported or unresolved. + static Type? ResolveClosedSpecType(MetadataReader reader, TypeSpecificationHandle handle, HostBinding binding) + { + try + { + var blob = reader.GetBlobBytes(reader.GetTypeSpecification(handle).Signature); + int idx = 0; + return DecodeSigType(reader, blob, ref idx, binding); + } + catch { return null; } + } + + // Decode a MethodSpec signature blob (II.23.2.15) into resolved host Types. + // Format: 0x0A [GenArgCount] [Type signatures...] + // Throws ScriptValidationException for unsupported tags or unresolved type-args — + // the caller should let it propagate so the user sees a friendly load-time error. + static Type[] DecodeMethodSpecArgs(MetadataReader reader, BlobHandle sigHandle, HostBinding binding, int msToken) + { + var blob = reader.GetBlobBytes(sigHandle); + if (blob.Length < 2 || blob[0] != 0x0A) + throw new ScriptValidationException($"MethodSpec at 0x{msToken:X8}: malformed signature"); + int idx = 1; + int argCount = DecompressIntAdv(blob, ref idx); + var result = new Type[argCount]; + for (int i = 0; i < argCount; i++) + result[i] = DecodeMethodSpecArg(reader, blob, ref idx, binding, msToken); + return result; + } + + static Type DecodeMethodSpecArg(MetadataReader reader, byte[] blob, ref int idx, HostBinding binding, int msToken) + { + byte tag = blob[idx++]; + switch (tag) + { + case 0x02: return typeof(bool); + case 0x08: return typeof(int); + case 0x09: return typeof(uint); + case 0x0A: return typeof(long); + case 0x0C: return typeof(float); + case 0x0D: return typeof(double); + case 0x0E: return typeof(string); + case 0x18: return typeof(IntPtr); // ELEMENT_TYPE_I — native int + case 0x19: return typeof(UIntPtr); // ELEMENT_TYPE_U + case 0x1C: return typeof(object); + case 0x11: case 0x12: + { + int coded = DecompressIntAdv(blob, ref idx); + int table = coded & 0x03; + int row = coded >> 2; + if (table != 1) // only TypeRef supported (TypeDef / TypeSpec out of scope) + throw new ScriptValidationException( + $"MethodSpec at 0x{msToken:X8}: unsupported type-arg table {table}"); + var trh = reader.GetTypeReference(MetadataTokens.TypeReferenceHandle(row)); + var name = reader.GetString(trh.Name); + if (binding.TryGetTypeByName(name, out var t)) + return t!; + // Unregistered ENUM type-args resolve by full name (Enum.TryParse): + // an enum carries no callable surface, so it doesn't widen the allowlist. + var full = trh.Namespace.IsNil ? name : reader.GetString(trh.Namespace) + "." + name; + if (FindTypeByFullName(full) is { IsEnum: true } et) + return et; + throw new ScriptValidationException( + $"MethodSpec at 0x{msToken:X8}: type argument '{name}' is not in the host binding allowlist (call AllowType<{name}>())"); + } + default: + throw new ScriptValidationException( + $"MethodSpec at 0x{msToken:X8}: unsupported type-arg signature tag 0x{tag:X2}"); + } + } + + // Decode a standard method signature blob (II.23.2.1) into a param Type[]. + // Format: [conv-byte] [paramCount] [returnType] [paramType * paramCount] + // Returns null if the blob is malformed or contains an unsupported tag — caller falls through. + static Type[]? DecodeMethodSigParamTypes(MetadataReader reader, byte[] blob, HostBinding binding) + { + if (blob.Length < 3) return null; + int idx = 0; + byte conv = blob[idx++]; + if ((conv & 0x10) != 0) return null; // GENERIC — handled via MethodSpec path + int paramCount = DecompressIntAdv(blob, ref idx); + // skip return type + if (!SkipSigType(blob, ref idx)) return null; + var result = new Type[paramCount]; + for (int i = 0; i < paramCount; i++) + { + var t = DecodeSigType(reader, blob, ref idx, binding); + if (t == null) return null; + result[i] = t; + } + return result; + } + + // Decode one type from a signature blob at idx, advancing idx. Returns null on unsupported tag. + static Type? DecodeSigType(MetadataReader reader, byte[] blob, ref int idx, HostBinding binding) + { + if (idx >= blob.Length) return null; + byte tag = blob[idx++]; + switch (tag) + { + case 0x01: return typeof(void); + case 0x02: return typeof(bool); + case 0x03: return typeof(char); + case 0x04: return typeof(sbyte); + case 0x05: return typeof(byte); + case 0x06: return typeof(short); + case 0x07: return typeof(ushort); + case 0x08: return typeof(int); + case 0x09: return typeof(uint); + case 0x0A: return typeof(long); + case 0x0B: return typeof(ulong); + case 0x0C: return typeof(float); + case 0x0D: return typeof(double); + case 0x0E: return typeof(string); + case 0x18: return typeof(IntPtr); // ELEMENT_TYPE_I — native int + case 0x19: return typeof(UIntPtr); // ELEMENT_TYPE_U + case 0x1C: return typeof(object); + case 0x11: case 0x12: // VALUETYPE / CLASS + coded TypeDefOrRef + { + int coded = DecompressIntAdv(blob, ref idx); + int table = coded & 0x03; + int row = coded >> 2; + if (table != 1) return null; // only TypeRef supported + return ResolveSigTypeRef(reader, MetadataTokens.TypeReferenceHandle(row), binding); + } + case 0x10: // BYREF — recurse then MakeByRefType + { + var inner = DecodeSigType(reader, blob, ref idx, binding); + return inner?.MakeByRefType(); + } + case 0x15: // GENERICINST: (CLASS|VALUETYPE) coded-index argCount arg* — e.g. List + { + if (idx >= blob.Length) return null; + idx++; // CLASS or VALUETYPE tag of the generic definition + int gcoded = DecompressIntAdv(blob, ref idx); + Type? def = (gcoded & 0x03) == 1 + ? ResolveSigTypeRef(reader, MetadataTokens.TypeReferenceHandle(gcoded >> 2), binding) + : null; + // A registered CLOSED instantiation (e.g. an AllowType'd List) shares the + // metadata short name "List`1" — normalize to the open definition before re-closing. + if (def is { IsGenericType: true, IsGenericTypeDefinition: false }) + def = def.GetGenericTypeDefinition(); + int argc = DecompressIntAdv(blob, ref idx); + var args = new Type[argc]; + for (int i = 0; i < argc; i++) + { + var a = DecodeSigType(reader, blob, ref idx, binding); + if (a == null) return null; // caller aborts the whole decode; position is moot + args[i] = a; + } + if (def == null || !def.IsGenericTypeDefinition || + def.GetGenericArguments().Length != argc) return null; + try { return def.MakeGenericType(args); } catch { return null; } + } + case 0x1D: // SZARRAY — recurse then MakeArrayType + { + var inner = DecodeSigType(reader, blob, ref idx, binding); + return inner?.MakeArrayType(); + } + default: return null; // unsupported tag — fall through + } + } + + // Resolve the runtime Type a ctor MemberRef constructs — used by delegate-creation lowering, + // where the delegate type is only named by the newobj token's parent. TypeRef parents cover + // custom delegates and System.Action; TypeSpec parents cover generic instantiations + // (Func`2, EventCallback`1) via the full recursive sig decode. + static Type? ResolveCtorParentType(ParsedAssembly asm, int ctorTok) + { + if (asm.HostSurface == null) return null; + try + { + var h = MetadataTokens.EntityHandle(ctorTok); + if (h.Kind != HandleKind.MemberReference) return null; + var mr = asm.Reader.GetMemberReference((MemberReferenceHandle)h); + switch (mr.Parent.Kind) + { + case HandleKind.TypeReference: + return ResolveSigTypeRef(asm.Reader, (TypeReferenceHandle)mr.Parent, asm.HostSurface); + case HandleKind.TypeSpecification: + { + var blob = asm.Reader.GetBlobBytes( + asm.Reader.GetTypeSpecification((TypeSpecificationHandle)mr.Parent).Signature); + int idx = 0; + return DecodeSigType(asm.Reader, blob, ref idx, asm.HostSurface); + } + default: + return null; + } + } + catch { return null; } + } + + // Resolve the receiver type of a MemberRef whose parent is a TypeRef. The namespace-qualified + // name goes through the (policy-gated) auto-bind FIRST: simple names collide across namespaces + // (UnityEngine.Application vs UnityEngine.WSA/Device.Application), and resolving against the + // wrong twin either loses the member (unbound) or — worse — silently binds a same-named member + // of the wrong type. Nested TypeRefs (nil namespace) and names the auto-bind policy declines + // (or bindings without a resolver) keep the registered simple-name behavior unchanged. + static bool TryResolveReceiverTypeRef(MetadataReader reader, TypeReferenceHandle handle, + string simpleName, HostBinding binding, out Type? type) + { + var tr = reader.GetTypeReference(handle); + if (!tr.Namespace.IsNil) + { + var fullName = reader.GetString(tr.Namespace) + "." + simpleName; + if (binding.TryAutoBindType(fullName) && binding.TryGetTypeByFullName(fullName, out type)) + return true; + } + return binding.TryGetTypeByName(simpleName, out type); + } + + // Resolve a sig-blob TypeRef to a host Type for SIGNATURE MATCHING only (no registration + // implied): registered simple names first, then the namespace-qualified name — covering types + // the auto-bind policy deliberately never registers (List`1, System.Uri) and generic + // definitions living outside corelib (InputFeatureUsage`1) — without a Type for them, every + // same-arity overload set that differs only by such a parameter resolves ambiguous and lands + // in UnboundHostMembers. + static Type? ResolveSigTypeRef(MetadataReader reader, TypeReferenceHandle handle, HostBinding binding) + { + var tr = reader.GetTypeReference(handle); + var name = reader.GetString(tr.Name); + if (binding.TryGetTypeByName(name, out var t) && t != null) return t; + return FindTypeByFullName(tr.Namespace.IsNil + ? name : reader.GetString(tr.Namespace) + "." + name); + } + + // Full-name type lookup across corelib and every loaded assembly, for signature matching only. + // Deliberately NOT the auto-bind resolver: no policy applies (registering nothing, we only need + // Type identity to pick the right overload), and results — including misses — are cached for + // the process (a type loaded later than its first sig miss stays unresolved; overload matching + // then degrades to the name+arity fallback exactly as before this lookup existed). + static readonly System.Collections.Concurrent.ConcurrentDictionary _sigTypeByFullName = new(); + + static Type? FindTypeByFullName(string fullName) => + _sigTypeByFullName.GetOrAdd(fullName, static fn => + { + try { var t = Type.GetType(fn, throwOnError: false); if (t != null) return t; } catch { } + // UNITY_6000_5_OR_NEWER: AppDomain.GetAssemblies can return already-unloaded assemblies + // in the editor (UAC0005, an error on 6000.6+); the pure-dotnet builds keep AppDomain. +#if UNITY_6000_5_OR_NEWER + foreach (var asm in UnityEngine.Assemblies.CurrentAssemblies.GetLoadedAssemblies()) +#else + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) +#endif + { + try { var t = asm.GetType(fn, throwOnError: false); if (t != null) return t; } catch { } + } + return null; + }); + + // Advance idx past one type in a sig blob without returning a Type. Returns false on error. + static bool SkipSigType(byte[] blob, ref int idx) + { + if (idx >= blob.Length) return false; + byte tag = blob[idx++]; + switch (tag) + { + case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: + case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: + case 0x0B: case 0x0C: case 0x0D: case 0x0E: case 0x18: + case 0x19: case 0x1C: + return true; // primitives/native int/string/object — no extra bytes + case 0x11: case 0x12: + DecompressIntAdv(blob, ref idx); // coded index + return true; + case 0x10: case 0x1D: + return SkipSigType(blob, ref idx); // wrapper: skip inner type + case 0x13: case 0x1E: // VAR / MVAR: generic parameter reference + index + DecompressIntAdv(blob, ref idx); + return true; + case 0x15: // GENERICINST: (CLASS|VALUETYPE) coded-index argCount arg* + { + // A generic RETURN type (e.g. AsyncOperationHandle) must be skippable + // even though DecodeSigType can't produce it — otherwise param decoding never runs + // and multi-overload members (Addressables.InstantiateAsync/5) resolve ambiguous. + if (idx >= blob.Length) return false; + idx++; // CLASS or VALUETYPE tag + DecompressIntAdv(blob, ref idx); // coded TypeDefOrRef + int n = DecompressIntAdv(blob, ref idx); + for (int i = 0; i < n; i++) + if (!SkipSigType(blob, ref idx)) return false; + return true; + } + default: return false; // unsupported + } + } + + // Pick the open generic overload whose MemberRef parameter signature matches the call. + // sigIdx points at the RETURN type inside the GENERIC-calling-convention MemberRef blob + // (conv byte, genParamCount and paramCount already consumed). Each candidate is closed with + // typeArgs and its parameters compared structurally against the blob. Null = none matched. + static MethodInfo? SelectOpenGenericOverload(MetadataReader reader, List candidates, + byte[] sig, int sigIdx, Type[] typeArgs) + { + foreach (var cand in candidates) + { + MethodInfo closed; + try { closed = cand.MakeGenericMethod(typeArgs); } + catch { continue; } + var ps = closed.GetParameters(); + int idx = sigIdx; + if (!SkipSigType(sig, ref idx)) continue; // return type + bool ok = true; + for (int i = 0; i < ps.Length && ok; i++) + ok = SigTypeMatches(reader, sig, ref idx, ps[i].ParameterType, typeArgs); + if (ok) return cand; + } + return null; + } + + // Structural comparison of one signature-blob type against a resolved CLR type, advancing idx. + // TypeRef comparisons use short names (good enough to split overloads; full-name resolution + // isn't available for unregistered refs). VAR/MVAR compare against the instantiation's args. + static bool SigTypeMatches(MetadataReader reader, byte[] blob, ref int idx, Type expected, Type[] typeArgs) + { + if (idx >= blob.Length) return false; + byte tag = blob[idx++]; + switch (tag) + { + case 0x02: return expected == typeof(bool); + case 0x03: return expected == typeof(char); + case 0x04: return expected == typeof(sbyte); + case 0x05: return expected == typeof(byte); + case 0x06: return expected == typeof(short); + case 0x07: return expected == typeof(ushort); + case 0x08: return expected == typeof(int); + case 0x09: return expected == typeof(uint); + case 0x0A: return expected == typeof(long); + case 0x0B: return expected == typeof(ulong); + case 0x0C: return expected == typeof(float); + case 0x0D: return expected == typeof(double); + case 0x0E: return expected == typeof(string); + case 0x1C: return expected == typeof(object); + case 0x11: case 0x12: // VALUETYPE / CLASS + coded TypeDefOrRef + { + int coded = DecompressIntAdv(blob, ref idx); + if ((coded & 0x03) != 1) return false; // only TypeRef comparable here + var name = reader.GetString(reader.GetTypeReference( + MetadataTokens.TypeReferenceHandle(coded >> 2)).Name); + return expected.Name == name; + } + case 0x13: case 0x1E: // VAR / MVAR n → n-th type argument of this instantiation + { + int n = DecompressIntAdv(blob, ref idx); + return n < typeArgs.Length && expected == typeArgs[n]; + } + case 0x10: // BYREF + return expected.IsByRef && SigTypeMatches(reader, blob, ref idx, expected.GetElementType()!, typeArgs); + case 0x1D: // SZARRAY + return expected.IsArray && SigTypeMatches(reader, blob, ref idx, expected.GetElementType()!, typeArgs); + case 0x15: // GENERICINST: outer definition name + each type arg + { + if (idx >= blob.Length) return false; + idx++; // CLASS|VALUETYPE tag + int coded = DecompressIntAdv(blob, ref idx); + string outer = (coded & 0x03) == 1 + ? reader.GetString(reader.GetTypeReference(MetadataTokens.TypeReferenceHandle(coded >> 2)).Name) + : ""; + int n = DecompressIntAdv(blob, ref idx); + if (!expected.IsGenericType || expected.Name != outer) return false; + var eargs = expected.GetGenericArguments(); + if (eargs.Length != n) return false; + for (int i = 0; i < n; i++) + if (!SigTypeMatches(reader, blob, ref idx, eargs[i], typeArgs)) return false; + return true; + } + default: return false; + } + } + + static MethodInfo? FindMethod(Type type, string name, int paramCount) + { + foreach (var m in type.GetMethods( + BindingFlags.Public | BindingFlags.Instance | + BindingFlags.Static | BindingFlags.DeclaredOnly)) + if (m.Name == name && m.GetParameters().Length == paramCount) + return m; + return null; + } + + // Resolve flat-struct (Vt) layouts for a HostEntry's params/return/receiver, given + // the binding. Called for hostCalls and hostCtors after construction in Parse. + static void FillStructInfo(HostEntry he, HostBinding? binding, bool isCtor) + { + if (binding == null) return; + var ps = he.Binding.Params; + if (ps != null && ps.Length > 0) + { + var arr = new HostBinding.StructLayout?[ps.Length]; + bool any = false; + for (int i = 0; i < ps.Length; i++) + { + var pt = ps[i].ParameterType; + if (pt.IsByRef) pt = pt.GetElementType()!; + if (pt.IsValueType && binding.TryGetStructLayout(pt, out var lay)) + { arr[i] = lay; any = true; } + } + if (any) he.ArgStructs = arr; + } + var m = (MethodBase?)he.ResolvedMethod ?? he.Binding.Method; + if (isCtor) + { + // Ctor's "return" type is its declaring type. + var declT = he.Binding.DeclaringType; + if (declT != null && declT.IsValueType && binding.TryGetStructLayout(declT, out var declLay)) + he.ReturnStruct = declLay; + } + else if (m is MethodInfo mi) + { + var rt = mi.ReturnType; + if (rt.IsValueType && rt != typeof(void) && binding.TryGetStructLayout(rt, out var retLay)) + he.ReturnStruct = retLay; + // Receiver: for a value-type instance method, the receiver is a struct + // (rarely useful in our subset but tracked for completeness). + if (he.Binding.HasThis && mi.DeclaringType != null && mi.DeclaringType.IsValueType + && binding.TryGetStructLayout(mi.DeclaringType, out var recvLay)) + he.ReceiverStruct = recvLay; + } + } + + + // Walks one ParsedMethod's IL, simulates the eval stack symbolically to determine + // operand types, allocates frame slots, and emits uint[] IR. All methods in the + // assembly are lowered at Load time and cached on ParsedMethod.Lowered. + static class IrLowerer + { + // Returns a list of (methodName, reason) for any method that failed to lower. + // Empty list means full success. Load throws when this is non-empty. + // lenient=true demotes EVERY per-method lowering failure to a skipped stub (as cold + // enumerator members already are) instead of failing the whole Load — a method that can't + // lower is left with Lowered==null + a LoweringSkipReason, and the rest load normally. Hot + // reload uses this so one unsupported method (e.g. SetupUI referencing a member missing on + // the running build) doesn't poison every other reloaded method in the same file. Strict + // (default) stays all-or-nothing for the fuzzer/tests, where a failure is a bug to surface. + public static List<(string Name, string Reason)> LowerAll(ParsedAssembly asm, bool lenient = false) + { + var failures = new List<(string, string)>(); + foreach (var m in asm.ByToken.Values) + { + try { m.Lowered = LowerMethod(m, asm); } + catch (NotSupportedException ex) + { + // A cold enumerator member (iterator Reset — body is `throw new + // NotSupportedException()`) becomes a skipped stub instead of failing the + // whole Load: no driver ever calls it. Invoking it anyway throws the reason. + if (m.IsColdEnumeratorMember || lenient) { m.LoweringSkipReason = ex.Message; continue; } + failures.Add((m.Name, ex.Message)); + } + catch (Exception ex) + { + // A lowering crash must still name the METHOD: a raw IndexOutOfRangeException + // escaping Load reads as "Index was outside the bounds of the array" with + // nothing to act on. The stack rides along so a bug report is actionable. + var reason = $"internal error while lowering (an unsupported construct — please report): {ex}"; + if (m.IsColdEnumeratorMember || lenient) { m.LoweringSkipReason = reason; continue; } + failures.Add((m.Name, reason)); + } + } + + // A lowered method whose call sites target a skipped stub would jump through a null + // Lowered at runtime — demote such callers to failures too (cascading; defensive: + // in practice cold members are leaf Reset bodies nothing calls). + bool changed = true; + while (changed) + { + changed = false; + foreach (var m in asm.ByToken.Values) + { + var callees = m.Lowered?.CalleeByTokIdx; + if (callees == null) continue; + foreach (var callee in callees) + { + if (callee == null || callee.Lowered != null) continue; + var reason = $"calls '{callee.Name}', which could not be lowered: {callee.LoweringSkipReason}"; + m.Lowered = null!; + if (m.IsColdEnumeratorMember || lenient) m.LoweringSkipReason = reason; + else failures.Add((m.Name, reason)); + changed = true; + break; + } + } + } + return failures; + } + + // Concatenates every lowered method's IR into ParsedAssembly.IrBlob with branch targets + // rewritten blob-absolute, so the Vm can execute script-to-script calls iteratively (frame + // push + ip jump) under one `fixed` instead of recursing into Run(). Each method's region + // gets a trailing ret_void sentinel: it preserves both the old "fell off the end" return + // (void methods) and the lowerer's past-end fall-through branch targets, and stops + // execution from running into the next method's code. + public static void BuildIrBlob(ParsedAssembly asm) + { + int total = 0; + foreach (var m in asm.ByToken.Values) + if (m.Lowered != null) total += m.Lowered.Ir.Length + 1; + var blob = new uint[total]; + int off = 0; + foreach (var m in asm.ByToken.Values) + { + var lm = m.Lowered; + if (lm == null) continue; // skipped stub (cold enumerator member) + var ir = lm.Ir; + int n = ir.Length; + lm.IrStart = off; + Array.Copy(ir, 0, blob, off, n); + + // PatchInsnBranchTargets computes newTarget = t - shift[t]; a constant -off shift + // relocates every target (including past-end t == n, which lands on the sentinel). + var shift = new int[n + 1]; + for (int i = 0; i <= n; i++) shift[i] = -off; + int pos = 0; + while (pos < n) + { + var op = (Op)ir[pos]; + int w = OpWidthForCoalesce(op, ir, pos); + if (w <= 0) + throw new NotSupportedException($"IR blob: unknown width for op {op} in '{m.Name}'"); + PatchInsnBranchTargets(blob, off + pos, op, shift, ir, pos); + pos += w; + } + blob[off + n] = (uint)Op.ret_void; + off += n + 1; + } + asm.IrBlob = blob; + } + + // Simple (unqualified) type name of a TypeRef/TypeDef token, for matching a + // `constrained.` prefix's type against a flat struct layout's TypeName. Null for + // TypeSpecs (generic instantiations — never a registered flat struct) or bad tokens. + static string TokenSimpleTypeName(ParsedAssembly asm, int token) + { + try + { + var handle = MetadataTokens.Handle(token); + switch (handle.Kind) + { + case HandleKind.TypeReference: + return asm.Reader.GetString( + asm.Reader.GetTypeReference((TypeReferenceHandle)handle).Name); + case HandleKind.TypeDefinition: + return asm.Reader.GetString( + asm.Reader.GetTypeDefinition((TypeDefinitionHandle)handle).Name); + default: + return null!; + } + } + catch (Exception) + { + return null!; + } + } + + public static LoweredMethod LowerMethod(ParsedMethod method, ParsedAssembly asm) + { + var il = method.IlBytes; + var ir = new List(il.Length * 2); + var irToIl = new List(il.Length * 2); + var strings = new List(); + var tokens = new List(); + + // Frame layout: [args (one slot each, 0..ArgCount-1), + // locals (variable slot count — struct locals occupy ceil(size/4) slots), + // eval-stack slots (above)] + int frameSize = method.ArgCount; + // Local slot index → first frame-slot index. Filler slots (struct continuation) are + // not directly addressable but exist in slotTypes/structLayouts to keep AllocSlot monotonic. + var localFrameSlot = new int[method.LocalCount]; + + // Per-slot type table — grows alongside frameSize. + // Arg slots: slot 0 is `this` for instance methods; then explicit params from ArgSTypes. + // A flat-struct arg (Vt) occupies ceil(size/4) slots, so args after it shift — + // argFrameSlot maps arg index → frame slot (identity when no Vt args). + var slotTypes = new List(frameSize + 32); + // Parallel list of per-Vt-slot struct layouts. null for non-Vt slots and filler slots. + var slotStructs = new List(frameSize + 32); + var argFrameSlot = new int[method.ArgCount]; + bool argIndirect = false; + { + int sigParamBase = method.IsStatic ? 0 : 1; // slot 0 is `this` for instance methods + for (int i = 0; i < method.ArgCount; i++) + { + int sigIdx = i - sigParamBase; + SType t = (sigIdx >= 0 && sigIdx < method.ArgSTypes.Length) ? method.ArgSTypes[sigIdx] : SType.O; + // `this` of a flat script struct is ALSO Vt (instance methods on flat structs). + HostBinding.StructLayout? alay = null; + if (sigIdx >= 0 && method.ArgStructLayouts != null && sigIdx < method.ArgStructLayouts.Length) + alay = method.ArgStructLayouts[sigIdx]; + else if (sigIdx < 0 && method.ThisStructLayout != null) { alay = method.ThisStructLayout; t = SType.Vt; } + argFrameSlot[i] = slotTypes.Count; + if (t == SType.Vt && alay != null) + { + int slotsNeeded = (alay.Size + 3) / 4; + slotTypes.Add(SType.Vt); + slotStructs.Add(alay); + for (int k = 1; k < slotsNeeded; k++) { slotTypes.Add(SType.O); slotStructs.Add(null); } + argIndirect = true; + } + else + { + var at = t == SType.Vt ? SType.O : t; // Vt without layout: defensive O + slotTypes.Add(at); + slotStructs.Add(null); + if (at is SType.I8 or SType.R8) + { + // Wide arg: continuation cell, and later args shift — argFrameSlot maps. + slotTypes.Add(SType.O); + slotStructs.Add(null); + argIndirect = true; + } + } + } + frameSize = slotTypes.Count; + } + // Allocate locals — struct locals get Vt + filler slots whenever a layout exists for + // the local's type. Vt-typed operator dispatchers chain through Vt slots without + // boxing; only the crossing into a boxed host API pays a single box_vt. + var localStrs = method.LocalStructLayouts; + // A local with a FROZEN declared type (LocalSTypes) is typed authoritatively and never + // re-inferred/retyped — this restores the "one slot ⇒ one type ⇒ one backing store" + // invariant that last-wins inference broke, so a fast op is never emitted over a slot + // whose value is actually boxed. Null entries fall through to inference as before. + var localDeclared = new bool[method.LocalCount]; + for (int i = 0; i < method.LocalCount; i++) + { + var lay = localStrs?[i]; + bool useVt = lay != null; + localFrameSlot[i] = frameSize; + if (useVt) + { + int slotsNeeded = (lay!.Size + 3) / 4; + slotTypes.Add(SType.Vt); + slotStructs.Add(lay); + for (int k = 1; k < slotsNeeded; k++) + { + slotTypes.Add(SType.O); // filler slot: never addressed directly + slotStructs.Add(null); + } + frameSize += slotsNeeded; + } + else if (method.LocalSTypes?[i] is { } declSt) + { + slotTypes.Add(declSt); // frozen: declared type, not inferred + slotStructs.Add(null); + localDeclared[i] = true; + frameSize++; + if (declSt is SType.I8 or SType.R8) + { + slotTypes.Add(SType.O); // wide local: continuation cell + slotStructs.Add(null); + frameSize++; + } + } + else + { + slotTypes.Add(SType.O); // patched by pre-scan + slotStructs.Add(null); + frameSize++; + } + } + // Pre-scan: determine local types from first stloc in each slot. + // Skips struct-typed and declared-typed locals (already classified above). + PreClassifyLocals(il, method, slotTypes, localFrameSlot, localStrs, localDeclared); + + // Exception clauses: finally is lowered via the push_cont/br_cont continuation chain; + // catch/filter would need real exception dispatch — fail with the reason instead + // of a bare opcode number. (Fault clauses were dropped at Parse: their handlers only + // run under exception dispatch, which the interpreter never does.) + if (method.HasUnsupportedEhClauses) + throw new NotSupportedException( + $"IR lowering: '{method.Name}' contains a try/catch (or filter) clause — " + + "only try/finally is supported by the interpreter"); + + // Pre-scan: collect all IL offsets that are branch targets. + // Used to clear ensuredScriptSlots at basic-block boundaries. + var ilBranchTargets = CollectIlBranchTargets(il); + // Finally handler entries are reached via the lowered leave's br — treat them as + // basic-block boundaries too. + if (method.FinallyRegions != null) + foreach (var r in method.FinallyRegions) + ilBranchTargets.Add(r.HandlerStart); + // Fault handlers are never entered (no exception dispatch) but their bodies still + // lower — mark each entry a basic-block boundary so the linear scan doesn't carry + // stale eval-stack slot state into the dead region. + if (method.FaultHandlerStarts != null) + foreach (var h in method.FaultHandlerStarts) + ilBranchTargets.Add(h); + + // Symbolic eval stack — each entry is (frameSlot, SType) + var evalStack = new (int slot, SType type)[64]; + int sp = 0; + + // Address tracking: indexed by frame slot number (slots are allocated monotonically). + // addrTagBySlot[s]: -2 = normal slot; >= 0 = "frame-slot address" (points to that frame slot); + // -1 = "field address" (use addrFldObjBySlot[s] + addrFldTokBySlot[s]); + // -3 = "array element address" (addrFldObjBySlot[s] = arr slot, addrFldTokBySlot[s] = idx slot). + // Size 512 is a generous upper bound; slots never exceed a few dozen in practice. + var addrTagBySlot = new int[512]; + var addrFldObjBySlot = new int[512]; + var addrFldTokBySlot = new int[512]; + // Byte-offset accumulation for addresses that point INSIDE flat struct bytes: + // tag >= 0 → addrByteOffBySlot = offset within the frame Vt slot (0 = whole slot); + // tag == -1 → addrFldOffBySlot >= 0 = composed byte offset into the parent + // ScriptObject's PrimBytes (-1 = classic token-addressed field phantom). + // Composition happens along INLINE segments (nested blittable structs); at a + // reference boundary (O field / array element) the chain REBASES onto the loaded ref. + var addrByteOffBySlot = new int[512]; + var addrFldOffBySlot = new int[512]; + // For -3 (array element) phantoms whose ARRAY has flat struct elements: the element + // layout (consumers materialize via ldelem_vt + write back via stelem_vt). + var addrElemLayoutBySlot = new HostBinding.StructLayout?[512]; + for (int i = 0; i < 512; i++) { addrTagBySlot[i] = -2; addrFldOffBySlot[i] = -1; } + // newarr_vt element layouts, resolved at lowering (sparse, keyed by tokIdx). + Dictionary? layoutByTokIdx = null; + // Primitive typed-array element types (bool/char/byte/…), resolved at lowering. + Dictionary? primArrayElemTypeByTokIdx = null; + // Delegate-creation sites (ldftn + newobj), resolved at lowering (sparse, by tokIdx). + Dictionary? delegateSiteByTokIdx = null; + + // Per-local and per-arg type tracking (updated on store, read on load) + var localTypes = new SType[method.LocalCount]; // synced from slotTypes + var argTypes = new SType[method.ArgCount]; // synced from slotTypes + + for (int i = 0; i < method.ArgCount; i++) argTypes[i] = slotTypes[argFrameSlot[i]]; + for (int i = 0; i < method.LocalCount; i++) localTypes[i] = slotTypes[localFrameSlot[i]]; + + // A script-defined struct local is always an O ScriptObject. PreClassifyLocals infers a + // local's type from the first value stored into it, and a generic `ldelem ` (from + // `s = arr[i]`) can be mis-inferred as I4 — which would then suppress clone-on-load and + // corrupt struct value semantics. Force these locals back to O. + if (method.LocalIsScriptStruct != null) + for (int i = 0; i < method.LocalCount; i++) + if (method.LocalIsScriptStruct[i]) + { + localTypes[i] = SType.O; + if (localFrameSlot[i] < slotTypes.Count) slotTypes[localFrameSlot[i]] = SType.O; + + // CLR localsinit: a struct local is usable without any initobj — Roslyn + // relies on it for local-function DISPLAY STRUCTS (`V_0.mult = 3` straight + // into the uninitialized local, then `call Scale(ref V_0)`). The O slot + // starts null here, so create the ScriptObject in the prologue. + if (method.LocalScriptStructTypeDefs != null + && method.LocalScriptStructTypeDefs[i] is var lsTok && lsTok != 0) + { + int lsTokIdx = tokens.Count; tokens.Add(lsTok); + ir.Add((uint)Op.initobj_script); irToIl.Add(0); + ir.Add((uint)localFrameSlot[i]); irToIl.Add(0); + ir.Add((uint)lsTokIdx); irToIl.Add(0); + } + } + + // IL offset → IR word index (for branch patching) + var ilToIrIp = new Dictionary(); + // Forward branches that need patching: (ir_word_index_of_target, il_target_offset) + var patchList = new List<(int irIdx, int ilTarget)>(); + // Branch-target → authoritative eval-stack depth delivered by its incoming edge(s). + // Recorded at every FORWARD branch (the delivered depth after the branch's own stack + // effect). In structured IL all edges into a join agree on depth, so when the linear + // walk reaches a target this value is authoritative: it drops any dead carry left on the + // stack after a preceding unconditional branch (e.g. a ternary then-arm result at the + // ELSE label) while preserving values that live *beneath* a short-circuit region (e.g. + // the `==` left operand while its right side is a `&&`/`||` chain). + var branchTargetDepth = new Dictionary(); + // Record a forward branch's delivered depth at its target (backward edges — loop headers — + // are already past in the linear walk, so they never need reconciling here). + void RecordJoinDepth(int src, int target, int depth) + { + if (target > src) branchTargetDepth[target] = depth; + } + // Ternary / short-circuit merge: END offset -> the fresh slot BOTH branches converge into. + // Each branch moves its result into this slot at its own tail; the join reads it. Using a + // fresh slot (never a branch's own value slot) is essential — the value slot may be a real + // local, or the two branches may leave their results in different slots. + var mergeSlotForEnd = new Dictionary(); + + // O slots known to hold a non-null ScriptObject in the current basic block. + // Cleared at branch targets and after any branch/call instruction. + // Allows the Stfld lowerer to skip redundant ensure_script ops. + var ensuredScriptSlots = new HashSet(); + + // Tracks whether the immediately preceding instruction was a `dup`. Roslyn emits + // `dup; brtrue`/`dup; brfalse` only for the null-coalescing / null-conditional idioms + // (`a ?? b`, `a?.b`), where the value left under the popped condition is a genuine + // forward-join carry. A plain conditional branch with no preceding dup (if/while/&&/||) + // leaves only base operands beneath, which must NOT be merged. + bool lastWasDup = false; + + // Type token of a pending `constrained.` prefix, consumed by the next call lowering. + // Disambiguates a Vt receiver: constrained to the slot's OWN struct type → box the + // whole struct; constrained to a primitive → extract the field at the byte offset. + int constrainedTok = 0; + + // Method token of a pending ldftn/ldvirtftn, consumed by the delegate-ctor Newobj that + // C# always emits immediately after (`ldnull|recv[; dup]; ld(virt)ftn M; newobj D`). + // Anything else between them is unsupported IL for this lowerer. + int pendingFtnTok = 0; + + // Byref locals carry an ADDRESS. Roslyn spills a managed pointer (&x.f from ldflda, + // &a[i] from ldelema, &local from ldloca) into a local when control flow sits between + // the address and its use — e.g. `x.f op= (cond switch {...})` or `a[i].Mut((cond) + // switch {...})`, where the switch-expr's branches force the spill. That address is a + // lowering-time PHANTOM (per-slot addr* metadata, no runtime value), so a plain + // stloc/ldloc dropped it and the later stind/call saw a non-address operand. Carry the + // phantom through the local by stashing its metadata ON THE LOCAL'S FRAME SLOT (the + // addr* arrays are per-slot and stable) and restoring a fresh phantom on load. + // (found by fuzzing: switch-expr in a compound-assign RHS / struct-array Mut arg.) + bool TryStoreLocalPhantom(int localIdx) + { + int src = evalStack[sp - 1].Item1; + if (addrTagBySlot[src] == -2) return false; // ordinary value → normal stloc + int dst = localFrameSlot[localIdx]; + addrTagBySlot[dst] = addrTagBySlot[src]; + addrFldObjBySlot[dst] = addrFldObjBySlot[src]; + addrFldTokBySlot[dst] = addrFldTokBySlot[src]; + addrByteOffBySlot[dst] = addrByteOffBySlot[src]; + addrFldOffBySlot[dst] = addrFldOffBySlot[src]; + addrElemLayoutBySlot[dst] = addrElemLayoutBySlot[src]; + sp--; // consume; the phantom is metadata-only, no runtime mov + return true; + } + bool TryLoadLocalPhantom(int localIdx) + { + int srcSlot = localFrameSlot[localIdx]; + if (addrTagBySlot[srcSlot] == -2) return false; + int ph = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + addrTagBySlot[ph] = addrTagBySlot[srcSlot]; + addrFldObjBySlot[ph] = addrFldObjBySlot[srcSlot]; + addrFldTokBySlot[ph] = addrFldTokBySlot[srcSlot]; + addrByteOffBySlot[ph] = addrByteOffBySlot[srcSlot]; + addrFldOffBySlot[ph] = addrFldOffBySlot[srcSlot]; + addrElemLayoutBySlot[ph] = addrElemLayoutBySlot[srcSlot]; + evalStack[sp++] = (ph, SType.O); + return true; + } + + int ip = 0; + while (ip < il.Length) + { + // The addr phantom tables are indexed by frame slot and evalStack by stack depth; + // both start at a size that covers ordinary methods, but generated/pathological + // code can allocate thousands of temp slots (found by fuzzing: IndexOutOfRange on + // addrTagBySlot). Grow here, once per instruction — no single instruction + // allocates anywhere near 256 slots, and the locals are re-read by every helper + // call below, so Array.Resize's new arrays propagate. + if (frameSize + 256 > addrTagBySlot.Length) + { + int oldCap = addrTagBySlot.Length; + int newCap = Math.Max(oldCap * 2, frameSize + 512); + Array.Resize(ref addrTagBySlot, newCap); + Array.Resize(ref addrFldObjBySlot, newCap); + Array.Resize(ref addrFldTokBySlot, newCap); + Array.Resize(ref addrByteOffBySlot, newCap); + Array.Resize(ref addrFldOffBySlot, newCap); + Array.Resize(ref addrElemLayoutBySlot, newCap); + // Same defaults as the initial fill: -2 = normal slot, -1 = token-addressed. + for (int i = oldCap; i < newCap; i++) { addrTagBySlot[i] = -2; addrFldOffBySlot[i] = -1; } + } + if (sp + 8 > evalStack.Length) + Array.Resize(ref evalStack, evalStack.Length * 2); + + int instrStart = ip; + // Basic-block boundary: clear ensuredScriptSlots when the current instruction + // is a branch target (we may have arrived via a backward edge or a jump). + if (ilBranchTargets.Contains(instrStart)) ensuredScriptSlots.Clear(); + // Reconcile the abstract eval-stack depth with the depth the branch edges deliver. + // The base slots are identical on every edge (they were computed before the diamond), + // so the current walk's evalStack entries remain valid — only the depth needs fixing. + if (branchTargetDepth.TryGetValue(instrStart, out var joinDepth)) + sp = joinDepth; + // Ternary/merge join: the second branch's result is on top; move it into the merge + // slot M so both paths converge on M. Done BEFORE recording ilToIrIp[ip] so the first + // branch's `br` (patched to this offset) lands AFTER the mov, not on top of it. + if (mergeSlotForEnd.TryGetValue(instrStart, out var mergeJoin)) + { + if (sp > 0) + { + var (joinTop, _) = evalStack[sp - 1]; + if (joinTop != mergeJoin.slot) + Emit3(ir, irToIl, mergeJoin.type == SType.Vt ? Op.mov_vt : Op.mov, + mergeJoin.slot, joinTop, instrStart); + evalStack[sp - 1] = (mergeJoin.slot, mergeJoin.type); + } + mergeSlotForEnd.Remove(instrStart); + } + // Record the mapping BEFORE emitting IR words + int irIp = ir.Count; + ilToIrIp[ip] = irIp; + + byte b = il[ip++]; + ILOpCode op = b == 0xFE ? (ILOpCode)(0xFE00 | il[ip++]) : (ILOpCode)b; + + // A loaded function pointer is only modeled as the immediate operand of a + // delegate ctor; any other consumer would see a placeholder slot. + if (pendingFtnTok != 0 && op != ILOpCode.Newobj) + throw new NotSupportedException( + $"IR lowering: ldftn in '{method.Name}' at IL+0x{instrStart:X4} is not part of a delegate construction"); + + bool afterDup = lastWasDup; + lastWasDup = false; + + switch (op) + { + case ILOpCode.Nop: break; + + case ILOpCode.Pop: + sp--; + break; + + case ILOpCode.Dup: + { + lastWasDup = true; + var (src, t) = evalStack[sp - 1]; + // Phantom-address slots aren't real values — duplicate by sharing the + // tag without emitting a mov. Required for `arr[i] += v` (ldelema; dup; + // ldind; add; stind) so both ldind and stind see the same array address. + if (addrTagBySlot[src] != -2) + { + int phDup = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + addrTagBySlot[phDup] = addrTagBySlot[src]; + addrFldObjBySlot[phDup] = addrFldObjBySlot[src]; + addrFldTokBySlot[phDup] = addrFldTokBySlot[src]; + addrByteOffBySlot[phDup] = addrByteOffBySlot[src]; + addrFldOffBySlot[phDup] = addrFldOffBySlot[src]; + addrElemLayoutBySlot[phDup] = addrElemLayoutBySlot[src]; + evalStack[sp++] = (phDup, SType.O); + break; + } + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, t, null); + evalStack[sp++] = (dst, t); + Emit3(ir, irToIl, Op.mov, dst, src, instrStart); + break; + } + + // --- Constants --- + case ILOpCode.Ldc_i4_m1: PushConst(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, -1, SType.I4, Op.ldc_i4, instrStart); break; + case ILOpCode.Ldc_i4_0: PushConst(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, 0, SType.I4, Op.ldc_i4, instrStart); break; + case ILOpCode.Ldc_i4_1: PushConst(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, 1, SType.I4, Op.ldc_i4, instrStart); break; + case ILOpCode.Ldc_i4_2: PushConst(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, 2, SType.I4, Op.ldc_i4, instrStart); break; + case ILOpCode.Ldc_i4_3: PushConst(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, 3, SType.I4, Op.ldc_i4, instrStart); break; + case ILOpCode.Ldc_i4_4: PushConst(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, 4, SType.I4, Op.ldc_i4, instrStart); break; + case ILOpCode.Ldc_i4_5: PushConst(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, 5, SType.I4, Op.ldc_i4, instrStart); break; + case ILOpCode.Ldc_i4_6: PushConst(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, 6, SType.I4, Op.ldc_i4, instrStart); break; + case ILOpCode.Ldc_i4_7: PushConst(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, 7, SType.I4, Op.ldc_i4, instrStart); break; + case ILOpCode.Ldc_i4_8: PushConst(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, 8, SType.I4, Op.ldc_i4, instrStart); break; + case ILOpCode.Ldc_i4_s: PushConst(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, (int)(sbyte)il[ip++], SType.I4, Op.ldc_i4, instrStart); break; + case ILOpCode.Ldc_i4: + { + int imm = BitConverter.ToInt32(il, ip); ip += 4; + PushConst(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, imm, SType.I4, Op.ldc_i4, instrStart); + break; + } + case ILOpCode.Ldc_r4: + { + // Store float bits as int (bit-identical, read back with UInt32BitsToSingle in executor) + int imm = (int)BitConverter.ToUInt32(il, ip); ip += 4; + PushConst(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, imm, SType.R4, Op.ldc_r4, instrStart); + break; + } + case ILOpCode.Ldc_r8: + { + // Real double constant into a wide R8 slot (bits split across two IR words). + ulong bits = BitConverter.ToUInt64(il, ip); ip += 8; + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.R8, null); + evalStack[sp++] = (dst, SType.R8); + ir.Add((uint)Op.ldc_r8); irToIl.Add(instrStart); + ir.Add((uint)dst); irToIl.Add(instrStart); + ir.Add((uint)(bits & 0xFFFFFFFF)); irToIl.Add(instrStart); + ir.Add((uint)(bits >> 32)); irToIl.Add(instrStart); + break; + } + case ILOpCode.Ldc_i8: + { + ulong bits = BitConverter.ToUInt64(il, ip); ip += 8; + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.I8, null); + evalStack[sp++] = (dst, SType.I8); + ir.Add((uint)Op.ldc_i8); irToIl.Add(instrStart); + ir.Add((uint)dst); irToIl.Add(instrStart); + ir.Add((uint)(bits & 0xFFFFFFFF)); irToIl.Add(instrStart); + ir.Add((uint)(bits >> 32)); irToIl.Add(instrStart); + break; + } + case ILOpCode.Ldnull: + { + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + evalStack[sp++] = (dst, SType.O); + Emit2(ir, irToIl, Op.ldnull, dst, instrStart); + break; + } + case ILOpCode.Ldstr: + { + int tok = BitConverter.ToInt32(il, ip); ip += 4; + string s = asm.Reader.GetUserString(MetadataTokens.UserStringHandle(tok & 0x00FFFFFF)); + int strIdx = strings.Count; strings.Add(s); + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + evalStack[sp++] = (dst, SType.O); + Emit3(ir, irToIl, Op.ldstr, dst, strIdx, instrStart); + break; + } + + // --- Locals --- + case ILOpCode.Ldloc_0: if (!TryLoadLocalPhantom(0)) PushLocal(ir, irToIl, evalStack, ref sp, ref frameSize, 0, localFrameSlot, localTypes, slotTypes, slotStructs, method.LocalIsScriptStruct, instrStart); break; + case ILOpCode.Ldloc_1: if (!TryLoadLocalPhantom(1)) PushLocal(ir, irToIl, evalStack, ref sp, ref frameSize, 1, localFrameSlot, localTypes, slotTypes, slotStructs, method.LocalIsScriptStruct, instrStart); break; + case ILOpCode.Ldloc_2: if (!TryLoadLocalPhantom(2)) PushLocal(ir, irToIl, evalStack, ref sp, ref frameSize, 2, localFrameSlot, localTypes, slotTypes, slotStructs, method.LocalIsScriptStruct, instrStart); break; + case ILOpCode.Ldloc_3: if (!TryLoadLocalPhantom(3)) PushLocal(ir, irToIl, evalStack, ref sp, ref frameSize, 3, localFrameSlot, localTypes, slotTypes, slotStructs, method.LocalIsScriptStruct, instrStart); break; + case ILOpCode.Ldloc_s: { int li = il[ip++]; if (!TryLoadLocalPhantom(li)) PushLocal(ir, irToIl, evalStack, ref sp, ref frameSize, li, localFrameSlot, localTypes, slotTypes, slotStructs, method.LocalIsScriptStruct, instrStart); break; } + case ILOpCode.Ldloc: { int li = ReadU16(il, ref ip); if (!TryLoadLocalPhantom(li)) PushLocal(ir, irToIl, evalStack, ref sp, ref frameSize, li, localFrameSlot, localTypes, slotTypes, slotStructs, method.LocalIsScriptStruct, instrStart); break; } + case ILOpCode.Stloc_0: if (!TryStoreLocalPhantom(0)) { addrTagBySlot[localFrameSlot[0]] = -2; StoreLocal(ir, irToIl, evalStack, ref sp, 0, localFrameSlot, localTypes, slotTypes, slotStructs, localDeclared, ref frameSize, instrStart); } break; + case ILOpCode.Stloc_1: if (!TryStoreLocalPhantom(1)) { addrTagBySlot[localFrameSlot[1]] = -2; StoreLocal(ir, irToIl, evalStack, ref sp, 1, localFrameSlot, localTypes, slotTypes, slotStructs, localDeclared, ref frameSize, instrStart); } break; + case ILOpCode.Stloc_2: if (!TryStoreLocalPhantom(2)) { addrTagBySlot[localFrameSlot[2]] = -2; StoreLocal(ir, irToIl, evalStack, ref sp, 2, localFrameSlot, localTypes, slotTypes, slotStructs, localDeclared, ref frameSize, instrStart); } break; + case ILOpCode.Stloc_3: if (!TryStoreLocalPhantom(3)) { addrTagBySlot[localFrameSlot[3]] = -2; StoreLocal(ir, irToIl, evalStack, ref sp, 3, localFrameSlot, localTypes, slotTypes, slotStructs, localDeclared, ref frameSize, instrStart); } break; + case ILOpCode.Stloc_s: { int li = il[ip++]; if (!TryStoreLocalPhantom(li)) { addrTagBySlot[localFrameSlot[li]] = -2; StoreLocal(ir, irToIl, evalStack, ref sp, li, localFrameSlot, localTypes, slotTypes, slotStructs, localDeclared, ref frameSize, instrStart); } break; } + case ILOpCode.Stloc: { int li = ReadU16(il, ref ip); if (!TryStoreLocalPhantom(li)) { addrTagBySlot[localFrameSlot[li]] = -2; StoreLocal(ir, irToIl, evalStack, ref sp, li, localFrameSlot, localTypes, slotTypes, slotStructs, localDeclared, ref frameSize, instrStart); } break; } + + // ldloca / ldloca.s — push a phantom address of the local's frame slot. + // The consuming instruction (ldind.*, stind.*, call .ctor) resolves it. + case ILOpCode.Ldloca_s: + case ILOpCode.Ldloca: + { + int localIdx = op == ILOpCode.Ldloca_s ? il[ip++] : ReadU16(il, ref ip); + int frameSlot = localFrameSlot[localIdx]; + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); // phantom O slot + addrTagBySlot[dst] = frameSlot; // frame-slot address + evalStack[sp++] = (dst, SType.O); + break; + } + // ldarga / ldarga.s — push a phantom address of the arg's frame slot. + case ILOpCode.Ldarga_s: + case ILOpCode.Ldarga: + { + int argIdx = op == ILOpCode.Ldarga_s ? il[ip++] : ReadU16(il, ref ip); + int frameSlot = argFrameSlot[argIdx]; + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); // phantom O slot + addrTagBySlot[dst] = frameSlot; // frame-slot address + evalStack[sp++] = (dst, SType.O); + break; + } + + // --- Args --- + case ILOpCode.Ldarg_0: PushArg(evalStack, ref sp, 0, argTypes, argFrameSlot); break; + case ILOpCode.Ldarg_1: PushArg(evalStack, ref sp, 1, argTypes, argFrameSlot); break; + case ILOpCode.Ldarg_2: PushArg(evalStack, ref sp, 2, argTypes, argFrameSlot); break; + case ILOpCode.Ldarg_3: PushArg(evalStack, ref sp, 3, argTypes, argFrameSlot); break; + case ILOpCode.Ldarg_s: PushArg(evalStack, ref sp, il[ip++], argTypes, argFrameSlot); break; + case ILOpCode.Ldarg: PushArg(evalStack, ref sp, ReadU16(il, ref ip), argTypes, argFrameSlot); break; + case ILOpCode.Starg_s: StoreArg(ir, irToIl, evalStack, ref sp, il[ip++], argTypes, argFrameSlot, slotTypes, slotStructs, ref frameSize, instrStart); break; + case ILOpCode.Starg: StoreArg(ir, irToIl, evalStack, ref sp, ReadU16(il, ref ip), argTypes, argFrameSlot, slotTypes, slotStructs, ref frameSize, instrStart); break; + + // --- Arithmetic --- + case ILOpCode.Add: EmitBinop(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, Op.add_i4, Op.add_r4, Op.add_i4_nn, Op.add_r4_nn, instrStart); break; + case ILOpCode.Sub: EmitBinop(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, Op.sub_i4, Op.sub_r4, Op.sub_i4_nn, Op.sub_r4_nn, instrStart); break; + case ILOpCode.Mul: EmitBinop(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, Op.mul_i4, Op.mul_r4, Op.mul_i4_nn, Op.mul_r4_nn, instrStart); break; + case ILOpCode.Div: EmitBinop(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, Op.div_i4, Op.div_r4, Op.div_i4_nn, Op.div_r4_nn, instrStart); break; + case ILOpCode.Rem: EmitBinop(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, Op.rem_i4, Op.rem_r4, Op.rem_i4_nn, Op.rem_r4_nn, instrStart); break; + case ILOpCode.Div_un: EmitBinopI4(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, Op.div_un_i4, Op.div_un_i4_nn, instrStart); break; + case ILOpCode.Rem_un: EmitBinopI4(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, Op.rem_un_i4, Op.rem_un_i4_nn, instrStart); break; + case ILOpCode.Neg: EmitUnop(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, Op.neg_i4, Op.neg_r4, Op.neg_i4_n, Op.neg_r4_n, instrStart); break; + case ILOpCode.And: EmitBinopI4(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, Op.and_i4, Op.and_i4_nn, instrStart); break; + case ILOpCode.Or: EmitBinopI4(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, Op.or_i4, Op.or_i4_nn, instrStart); break; + case ILOpCode.Xor: EmitBinopI4(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, Op.xor_i4, Op.xor_i4_nn, instrStart); break; + case ILOpCode.Not: EmitUnopI4(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, Op.not_i4, Op.not_i4_n, instrStart); break; + case ILOpCode.Shl: EmitBinopI4(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, Op.shl_i4, Op.shl_i4_nn, instrStart); break; + case ILOpCode.Shr: EmitBinopI4(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, Op.shr_i4, Op.shr_i4_nn, instrStart); break; + case ILOpCode.Shr_un: EmitBinopI4(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, Op.shr_un_i4, Op.shr_un_i4_nn, instrStart); break; + + // --- Comparisons --- + case ILOpCode.Ceq: + { + var (s2, t2) = evalStack[--sp]; + var (s1, t1) = evalStack[sp - 1]; + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.I4, null); + Op cop; + if (t1 == SType.R8 || t2 == SType.R8) + cop = Op.ceq_r8; + else if (t1 == SType.I8 || t2 == SType.I8) + cop = Op.ceq_i8; + else if (t1 == SType.R4 || t2 == SType.R4) + cop = (t1 == SType.R4 && t2 == SType.R4 && slotTypes[s1] == SType.R4 && slotTypes[s2] == SType.R4) ? Op.ceq_r4_nn : Op.ceq_r4; + else if (t1 == SType.I4 || t2 == SType.I4) + // ceq_i4 reads each operand from numStack or refStack based on slotT at runtime, + // so it handles mixed O/I4 cases (e.g. boxed int from a non-flat host call vs. ldc.i4). + cop = (slotTypes[s1] == SType.I4 && slotTypes[s2] == SType.I4) ? Op.ceq_i4_nn : Op.ceq_i4; + else + cop = Op.ceq_o; + evalStack[sp - 1] = (dst, SType.I4); + Emit4(ir, irToIl, cop, dst, s1, s2, instrStart); + break; + } + case ILOpCode.Cgt: + { + var (s2, t2) = evalStack[--sp]; + var (s1, t1) = evalStack[sp - 1]; + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.I4, null); + Op cop; + if (t1 == SType.R8 || t2 == SType.R8) + cop = Op.cgt_r8; + else if (t1 == SType.I8 || t2 == SType.I8) + cop = Op.cgt_i8; + else if (t1 == SType.R4 || t2 == SType.R4) + cop = (t1 == SType.R4 && t2 == SType.R4 && slotTypes[s1] == SType.R4 && slotTypes[s2] == SType.R4) ? Op.cgt_r4_nn : Op.cgt_r4; + else + cop = (slotTypes[s1] == SType.I4 && slotTypes[s2] == SType.I4) ? Op.cgt_i4_nn : Op.cgt_i4; + evalStack[sp - 1] = (dst, SType.I4); + Emit4(ir, irToIl, cop, dst, s1, s2, instrStart); + break; + } + case ILOpCode.Cgt_un: + { + var (s2, t2) = evalStack[--sp]; + var (s1, t1) = evalStack[sp - 1]; + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.I4, null); + Op cop; + if (t1 == SType.R8 || t2 == SType.R8) + cop = Op.cgt_un_r8; + else if (t1 == SType.I8 || t2 == SType.I8) + cop = Op.cgt_un_i8; + else if (t1 == SType.R4 || t2 == SType.R4) + cop = Op.cgt_un_r4; // float `<=` lowers to `cgt.un` — unordered greater-than + else if (t1 == SType.O) + cop = Op.cgt_un_o; + else + cop = (slotTypes[s1] == SType.I4 && slotTypes[s2] == SType.I4) ? Op.cgt_un_i4_nn : Op.cgt_un_i4; + evalStack[sp - 1] = (dst, SType.I4); + Emit4(ir, irToIl, cop, dst, s1, s2, instrStart); + break; + } + case ILOpCode.Clt: + { + var (s2, t2) = evalStack[--sp]; + var (s1, t1) = evalStack[sp - 1]; + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.I4, null); + Op cop; + if (t1 == SType.R8 || t2 == SType.R8) + cop = Op.clt_r8; + else if (t1 == SType.I8 || t2 == SType.I8) + cop = Op.clt_i8; + else if (t1 == SType.R4 || t2 == SType.R4) + cop = (t1 == SType.R4 && t2 == SType.R4 && slotTypes[s1] == SType.R4 && slotTypes[s2] == SType.R4) ? Op.clt_r4_nn : Op.clt_r4; + else + cop = (slotTypes[s1] == SType.I4 && slotTypes[s2] == SType.I4) ? Op.clt_i4_nn : Op.clt_i4; + evalStack[sp - 1] = (dst, SType.I4); + Emit4(ir, irToIl, cop, dst, s1, s2, instrStart); + break; + } + case ILOpCode.Clt_un: + { + var (s2, t2) = evalStack[--sp]; + var (s1, t1) = evalStack[sp - 1]; + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.I4, null); + evalStack[sp - 1] = (dst, SType.I4); + if (t1 == SType.R8 || t2 == SType.R8) + { + Emit4(ir, irToIl, Op.clt_un_r8, dst, s1, s2, instrStart); + break; + } + if (t1 == SType.I8 || t2 == SType.I8) + { + Emit4(ir, irToIl, Op.clt_un_i8, dst, s1, s2, instrStart); + break; + } + if (t1 == SType.R4 || t2 == SType.R4) + { + Emit4(ir, irToIl, Op.clt_un_r4, dst, s1, s2, instrStart); // float `>=` lowers to `clt.un` + break; + } + bool both_i4 = t1 == SType.I4 && t2 == SType.I4 && slotTypes[s1] == SType.I4 && slotTypes[s2] == SType.I4; + Emit4(ir, irToIl, both_i4 ? Op.clt_un_i4_nn : Op.clt_un_i4, dst, s1, s2, instrStart); + break; + } + + // Box is a no-op: values already live unboxed in the frame; boxing + // happens at host-call boundaries. + case ILOpCode.Box: + { + int tok = BitConverter.ToInt32(il, ip); ip += 4; + // Materialize a REAL, correctly-typed boxed object for primitive value types. + // Leaving box a no-op kept the value in its I4/R4 slot: the target `object` + // local was then classified I4 (so `object a=5; object b=5; a==b` compared by + // value, not reference) and bool/char boxed as int (Debug.Log(true) -> "1"). + // Reference types are already O (box is identity); flat structs box on store. + int tc = BoxPrimTypeCode(asm, tok); + if (tc >= 0) + { + var (src, _) = evalStack[sp - 1]; + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + evalStack[sp - 1] = (dst, SType.O); + Emit4(ir, irToIl, Op.box_prim, dst, src, tc, instrStart); + } + // HOST enum: box as the real enum type, not the underlying int — + // `$"state={m}"` / Debug.Log(m) must render the member name. Script- + // declared enums (TypeDefs) have no runtime Type and keep the int form. + else if (ResolveHostEnumType(asm, tok) is { } enumType) + { + int tokIdx = tokens.Count; tokens.Add(tok); + asm.TokenTypes[tok] = enumType; // executor resolves through TokenTypes + var (src, _) = evalStack[sp - 1]; + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + evalStack[sp - 1] = (dst, SType.O); + Emit4(ir, irToIl, Op.box_enum, dst, src, tokIdx, instrStart); + } + break; + } + + // --- Castclass / isinst / unbox.any / ldtoken --- + case ILOpCode.Castclass: + { + int tok = BitConverter.ToInt32(il, ip); ip += 4; + int tokIdx = tokens.Count; tokens.Add(tok); + var (src, _) = evalStack[sp - 1]; + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + evalStack[sp - 1] = (dst, SType.O); + Emit4(ir, irToIl, Op.castclass, dst, src, tokIdx, instrStart); + break; + } + case ILOpCode.Isinst: + { + int tok = BitConverter.ToInt32(il, ip); ip += 4; + int tokIdx = tokens.Count; tokens.Add(tok); + var (src, _) = evalStack[sp - 1]; + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + evalStack[sp - 1] = (dst, SType.O); + Emit4(ir, irToIl, Op.isinst, dst, src, tokIdx, instrStart); + break; + } + case ILOpCode.Unbox_any: + { + int tok = BitConverter.ToInt32(il, ip); ip += 4; + int tokIdx = tokens.Count; tokens.Add(tok); + var (src, _) = evalStack[sp - 1]; + // Type the result by the TARGET, not the boxed source: `(int)(object)x` must + // yield an I4 value, not an O. Keeping the source's O tag reclassified the + // destination local as a ref slot (e.g. `int acc2 = (int)(object)k` made acc2 + // O-typed, so later int reads saw 0). Primitives -> I4/R4; ref/struct/enum -> O. + var targetSt = PrimitiveSTypeForTypeToken(asm, tok) ?? SType.O; + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, targetSt, null); + evalStack[sp - 1] = (dst, targetSt); + Emit4(ir, irToIl, Op.unbox_any, dst, src, tokIdx, instrStart); + break; + } + case ILOpCode.Ldtoken: + { + int tok = BitConverter.ToInt32(il, ip); ip += 4; + int tokIdx = tokens.Count; tokens.Add(tok); + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + evalStack[sp++] = (dst, SType.O); + Emit3(ir, irToIl, Op.ldtoken, dst, tokIdx, instrStart); + break; + } + + // --- Conversions --- + case ILOpCode.Conv_i4: + case ILOpCode.Conv_u4: + { + var (src, st) = evalStack[sp - 1]; + if (st == SType.I4) break; // already int + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.I4, null); + evalStack[sp - 1] = (dst, SType.I4); + var cvOp = st == SType.I8 ? Op.conv_i4_i8 + : st == SType.R8 ? Op.conv_i4_r8 + : Op.conv_r4_i4; + Emit3(ir, irToIl, cvOp, dst, src, instrStart); + break; + } + case ILOpCode.Conv_i8: + case ILOpCode.Conv_u8: + { + var (src, st) = evalStack[sp - 1]; + if (st == SType.I8) break; // already 64-bit + // conv.i8 sign-extends an i4; conv.u8 zero-extends it. From float sources + // only the SIGNED form is supported — (ulong)someFloat stays loud. + bool zext = op == ILOpCode.Conv_u8; + Op cvOp; + if (st == SType.R4) { if (zext) goto notSupported; cvOp = Op.conv_i8_r4; } + else if (st == SType.R8) { if (zext) goto notSupported; cvOp = Op.conv_i8_r8; } + else cvOp = zext ? Op.conv_i8_u4 : Op.conv_i8_i4; + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.I8, null); + evalStack[sp - 1] = (dst, SType.I8); + Emit3(ir, irToIl, cvOp, dst, src, instrStart); + break; + } + case ILOpCode.Conv_r_un: + { + // Unsigned int → floating: ulong/uint reinterpreted unsigned, result R8 + // (a following conv.r4 narrows it). + var (src, st) = evalStack[sp - 1]; + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.R8, null); + evalStack[sp - 1] = (dst, SType.R8); + if (st == SType.I8) + Emit3(ir, irToIl, Op.conv_r8_u8, dst, src, instrStart); + else + { + // u4 source: zero-extend to I8 first, then unsigned-convert. + int wide = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.I8, null); + Emit3(ir, irToIl, Op.conv_i8_u4, wide, src, instrStart); + Emit3(ir, irToIl, Op.conv_r8_u8, dst, wide, instrStart); + } + break; + } + case ILOpCode.Conv_i1: + { + var (src2, _) = evalStack[sp - 1]; + int dst2 = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.I4, null); + evalStack[sp - 1] = (dst2, SType.I4); + Emit3(ir, irToIl, Op.conv_i4_i1, dst2, src2, instrStart); + break; + } + case ILOpCode.Conv_u1: + { + var (src2, _) = evalStack[sp - 1]; + int dst2 = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.I4, null); + evalStack[sp - 1] = (dst2, SType.I4); + Emit3(ir, irToIl, Op.conv_i4_u1, dst2, src2, instrStart); + break; + } + case ILOpCode.Conv_i2: + { + var (src2, _) = evalStack[sp - 1]; + int dst2 = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.I4, null); + evalStack[sp - 1] = (dst2, SType.I4); + Emit3(ir, irToIl, Op.conv_i4_i2, dst2, src2, instrStart); + break; + } + case ILOpCode.Conv_u2: + { + var (src2, _) = evalStack[sp - 1]; + int dst2 = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.I4, null); + evalStack[sp - 1] = (dst2, SType.I4); + Emit3(ir, irToIl, Op.conv_i4_u2, dst2, src2, instrStart); + break; + } + case ILOpCode.Conv_r4: + { + var (src, st) = evalStack[sp - 1]; + if (st == SType.R4) break; + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.R4, null); + evalStack[sp - 1] = (dst, SType.R4); + var cvOp = st == SType.I8 ? Op.conv_r4_i8 + : st == SType.R8 ? Op.conv_r4_r8 + : Op.conv_i4_r4; + Emit3(ir, irToIl, cvOp, dst, src, instrStart); + break; + } + case ILOpCode.Conv_r8: + { + // Honest double now that R8 slots exist (this retires the double-as-float + // divergence the analyzer guarded with MS002). + var (src, st) = evalStack[sp - 1]; + if (st == SType.R8) break; + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.R8, null); + evalStack[sp - 1] = (dst, SType.R8); + var cvOp = st == SType.I8 ? Op.conv_r8_i8 + : st == SType.R4 ? Op.conv_r8_r4 + : Op.conv_r8_i4; + Emit3(ir, irToIl, cvOp, dst, src, instrStart); + break; + } + + // --- Branches --- + case ILOpCode.Br_s: + case ILOpCode.Br: + { + int target = ReadBranchTarget(il, ref ip, op == ILOpCode.Br_s); + // Ternary / short-circuit value pattern: a FORWARD br that is the tail of a + // value-producing arm — `; br END; ELSE: ; END:`. The top-of-stack + // is this arm's result; move it into a fresh merge slot M so the other arm can + // converge on the same M at END. + // + // The arm is genuine when the label that follows the br (`ip`) is the ELSE + // label — i.e. an earlier branch already delivered depth `sp-1` there, so ELSE + // drops exactly this one result. When the recorded depth is `sp` instead, the + // value on top is NOT an arm result but a live operand carried beneath a + // short-circuit region (the `v0 == (… || …)` case): merging/dropping it would + // corrupt the stack, so we leave it alone and let RecordJoinDepth carry it. + // + // It is ALSO genuine — regardless of the ELSE-adjacency heuristic above — when + // `target` is already a known merge join (an earlier sibling arm already + // converged there): every further forward edge into an established merge point + // must converge its own top-of-stack into the same slot too. This matters for a + // degenerate zero-displacement `br` (target == ip, e.g. when Roslyn collapses two + // constant-valued ternary arms into one shared tail): such a br still carries a + // value that MUST be merged, but its "label right after it" is the merge point + // itself rather than a distinct ELSE label, so the ELSE-adjacency check alone + // (which additionally requires target > ip) never fires for it. Without this, + // the arm's value is silently dropped and the merge slot keeps a stale/default + // value when that arm is the one actually taken at runtime. + if (target >= ip && sp > 0 && + (mergeSlotForEnd.ContainsKey(target) || + (branchTargetDepth.TryGetValue(ip, out var elseDepth) && elseDepth == sp - 1))) + { + MergeTopIntoJoinSlot(ir, irToIl, evalStack, sp, ref frameSize, slotTypes, slotStructs, mergeSlotForEnd, target, instrStart); + } + RecordJoinDepth(instrStart, target, sp); // br leaves the stack unchanged + int patchIdx = ir.Count + 1; + Emit2(ir, irToIl, Op.br, -1, instrStart); + patchList.Add((patchIdx, target)); + ensuredScriptSlots.Clear(); + break; + } + // leave empties the eval stack, then runs every enclosing finally whose try + // region contains this instruction but not the target (innermost first), + // then continues at the target. Lowered as a continuation chain: push the + // final target and the outer handlers' entries, branch to the innermost + // handler; each handler's endfinally (br_cont) pops the next address. + case ILOpCode.Leave_s: + case ILOpCode.Leave: + { + int target = ReadBranchTarget(il, ref ip, op == ILOpCode.Leave_s); + sp = 0; // leave semantics: the eval stack is emptied + var chain = FinallyChain(method.FinallyRegions, instrStart, target); + RecordJoinDepth(instrStart, target, 0); + if (chain.Count == 0) + { + int patchIdx = ir.Count + 1; + Emit2(ir, irToIl, Op.br, -1, instrStart); + patchList.Add((patchIdx, target)); + } + else + { + // Push order: final target first, then outer→inner-but-one handlers, + // so pops run inner handler → … → outer handler → target. + int pi = ir.Count + 1; + Emit2(ir, irToIl, Op.push_cont, -1, instrStart); + patchList.Add((pi, target)); + for (int k = chain.Count - 1; k >= 1; k--) + { + pi = ir.Count + 1; + Emit2(ir, irToIl, Op.push_cont, -1, instrStart); + patchList.Add((pi, chain[k])); + } + RecordJoinDepth(instrStart, chain[0], 0); + pi = ir.Count + 1; + Emit2(ir, irToIl, Op.br, -1, instrStart); + patchList.Add((pi, chain[0])); + } + ensuredScriptSlots.Clear(); + break; + } + case ILOpCode.Endfinally: // also ends the handler when reached by fall-through + { + ir.Add((uint)Op.br_cont); irToIl.Add(instrStart); + sp = 0; + ensuredScriptSlots.Clear(); + break; + } + + case ILOpCode.Brtrue_s: + case ILOpCode.Brtrue: + { + int target = ReadBranchTarget(il, ref ip, op == ILOpCode.Brtrue_s); + var (cond, ct) = evalStack[--sp]; + // Value left on the stack after the condition is a forward-join carry ONLY in + // the `dup; brtrue L` idiom (`a ?? b`, `a?.b`): converge it with the + // fall-through's value into one slot; the join reconciles the other edge. With + // no preceding dup the remaining top is just a base operand (e.g. the `==` left + // operand under a `&&`/`||` chain) and must be left untouched. + if (afterDup && sp > 0 && target > ip) + MergeTopIntoJoinSlot(ir, irToIl, evalStack, sp, ref frameSize, slotTypes, slotStructs, mergeSlotForEnd, target, instrStart); + RecordJoinDepth(instrStart, target, sp); // condition already popped + var bop = ct == SType.O ? Op.brtrue_o : ct == SType.I8 ? Op.brtrue_i8 : Op.brtrue_i4; + if (ct == SType.R8) goto notSupported; // no IL brtrue on floats + int patchIdx = ir.Count + 2; + Emit3(ir, irToIl, bop, cond, -1, instrStart); + patchList.Add((patchIdx, target)); + ensuredScriptSlots.Clear(); + break; + } + case ILOpCode.Brfalse_s: + case ILOpCode.Brfalse: + { + int target = ReadBranchTarget(il, ref ip, op == ILOpCode.Brfalse_s); + var (cond, ct) = evalStack[--sp]; + if (afterDup && sp > 0 && target > ip) + MergeTopIntoJoinSlot(ir, irToIl, evalStack, sp, ref frameSize, slotTypes, slotStructs, mergeSlotForEnd, target, instrStart); + RecordJoinDepth(instrStart, target, sp); // condition already popped + var bop = ct == SType.O ? Op.brfalse_o : ct == SType.I8 ? Op.brfalse_i8 : Op.brfalse_i4; + if (ct == SType.R8) goto notSupported; + int patchIdx = ir.Count + 2; + Emit3(ir, irToIl, bop, cond, -1, instrStart); + patchList.Add((patchIdx, target)); + ensuredScriptSlots.Clear(); + break; + } + + // Compare-and-branch (lower to ceq+brtrue pattern) + case ILOpCode.Beq_s: case ILOpCode.Beq: + { + int target = ReadBranchTarget(il, ref ip, op == ILOpCode.Beq_s); + EmitCmpBranch(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, Op.ceq_i4, Op.ceq_r4, Op.ceq_o, Op.ceq_i4_nn, Op.ceq_r4_nn, Op.brtrue_i4, patchList, target, instrStart, branchTargetDepth); + ensuredScriptSlots.Clear(); + break; + } + case ILOpCode.Bne_un_s: case ILOpCode.Bne_un: + { + int target = ReadBranchTarget(il, ref ip, op == ILOpCode.Bne_un_s); + EmitCmpBranch(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, Op.ceq_i4, Op.ceq_r4, Op.ceq_o, Op.ceq_i4_nn, Op.ceq_r4_nn, Op.brfalse_i4, patchList, target, instrStart, branchTargetDepth); + ensuredScriptSlots.Clear(); + break; + } + case ILOpCode.Blt_s: case ILOpCode.Blt: + { + int target = ReadBranchTarget(il, ref ip, op == ILOpCode.Blt_s); + EmitCmpBranch(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, Op.clt_i4, Op.clt_r4, Op.clt_i4, Op.clt_i4_nn, Op.clt_r4_nn, Op.brtrue_i4, patchList, target, instrStart, branchTargetDepth); + ensuredScriptSlots.Clear(); + break; + } + case ILOpCode.Blt_un_s: case ILOpCode.Blt_un: + { + int target = ReadBranchTarget(il, ref ip, op == ILOpCode.Blt_un_s); + // Unordered: branch when a < b OR either is NaN, so the float compare must be the + // unordered clt_un_r4 (used for both the typed and _nn slots — it reads operand types itself). + EmitCmpBranch(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, Op.clt_un_i4, Op.clt_un_r4, Op.clt_un_i4, Op.clt_un_i4_nn, Op.clt_un_r4, Op.brtrue_i4, patchList, target, instrStart, branchTargetDepth); + ensuredScriptSlots.Clear(); + break; + } + case ILOpCode.Bgt_s: case ILOpCode.Bgt: + { + int target = ReadBranchTarget(il, ref ip, op == ILOpCode.Bgt_s); + EmitCmpBranch(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, Op.cgt_i4, Op.cgt_r4, Op.cgt_i4, Op.cgt_i4_nn, Op.cgt_r4_nn, Op.brtrue_i4, patchList, target, instrStart, branchTargetDepth); + ensuredScriptSlots.Clear(); + break; + } + case ILOpCode.Bgt_un_s: case ILOpCode.Bgt_un: + { + int target = ReadBranchTarget(il, ref ip, op == ILOpCode.Bgt_un_s); + // Unordered: branch when a > b OR either is NaN, so the float compare must be the + // unordered cgt_un_r4 (used for both the typed and _nn slots — it reads operand types itself). + EmitCmpBranch(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, Op.cgt_un_i4, Op.cgt_un_r4, Op.cgt_un_o, Op.cgt_un_i4_nn, Op.cgt_un_r4, Op.brtrue_i4, patchList, target, instrStart, branchTargetDepth); + ensuredScriptSlots.Clear(); + break; + } + case ILOpCode.Ble_s: case ILOpCode.Ble: + { + int target = ReadBranchTarget(il, ref ip, op == ILOpCode.Ble_s); + // !(a > b) — negating through brfalse swaps ordered/unordered, so the ORDERED ble + // (no branch on NaN) needs the UNORDERED cgt_un_r4: !(a > b OR NaN) is false for NaN. + // (cgt_un_r4 serves both the typed and _nn slots — it reads operand types itself.) + EmitCmpBranch(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, Op.cgt_i4, Op.cgt_un_r4, Op.cgt_i4, Op.cgt_i4_nn, Op.cgt_un_r4, Op.brfalse_i4, patchList, target, instrStart, branchTargetDepth); + ensuredScriptSlots.Clear(); + break; + } + case ILOpCode.Ble_un_s: case ILOpCode.Ble_un: + { + int target = ReadBranchTarget(il, ref ip, op == ILOpCode.Ble_un_s); + EmitCmpBranch(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, Op.cgt_un_i4, Op.cgt_r4, Op.cgt_un_o, Op.cgt_un_i4_nn, Op.cgt_r4_nn, Op.brfalse_i4, patchList, target, instrStart, branchTargetDepth); + ensuredScriptSlots.Clear(); + break; + } + case ILOpCode.Bge_s: case ILOpCode.Bge: + { + int target = ReadBranchTarget(il, ref ip, op == ILOpCode.Bge_s); + // !(a < b) — negating through brfalse swaps ordered/unordered, so the ORDERED bge + // (no branch on NaN) needs the UNORDERED clt_un_r4: !(a < b OR NaN) is false for NaN. + // (clt_un_r4 serves both the typed and _nn slots — it reads operand types itself.) + EmitCmpBranch(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, Op.clt_i4, Op.clt_un_r4, Op.clt_i4, Op.clt_i4_nn, Op.clt_un_r4, Op.brfalse_i4, patchList, target, instrStart, branchTargetDepth); + ensuredScriptSlots.Clear(); + break; + } + case ILOpCode.Bge_un_s: case ILOpCode.Bge_un: + { + int target = ReadBranchTarget(il, ref ip, op == ILOpCode.Bge_un_s); + EmitCmpBranch(ir, irToIl, evalStack, ref sp, ref frameSize, slotTypes, slotStructs, Op.clt_un_i4, Op.clt_r4, Op.clt_un_i4, Op.clt_un_i4_nn, Op.clt_r4_nn, Op.brfalse_i4, patchList, target, instrStart, branchTargetDepth); + ensuredScriptSlots.Clear(); + break; + } + + // --- Switch --- + case ILOpCode.Switch: + { + int n = BitConverter.ToInt32(il, ip); ip += 4; + int tableStart = ip; + ip += 4 * n; // skip offset table + int afterSwitch = ip; // base for relative offsets + + var (valSlot, _) = evalStack[--sp]; + // Emit: [switch_i4, val, n, default_patch_idx, ip0, ip1, ...]; targets patched afterwards. + int irSwitchStart = ir.Count; + ir.Add((uint)Op.switch_i4); + irToIl.Add(instrStart); + ir.Add((uint)valSlot); + irToIl.Add(instrStart); + ir.Add((uint)n); + irToIl.Add(instrStart); + // placeholder for default (fall-through = afterSwitch → patched via patchList) + int defaultPatchIdx = ir.Count; + ir.Add(unchecked((uint)-1)); + irToIl.Add(instrStart); + patchList.Add((defaultPatchIdx, afterSwitch)); + // per-case targets — the switch value is already popped, so every edge + // (cases + default fall-through) delivers the current base depth. + RecordJoinDepth(instrStart, afterSwitch, sp); + for (int ci = 0; ci < n; ci++) + { + int off = BitConverter.ToInt32(il, tableStart + ci * 4); + int target = afterSwitch + off; + int patchIdx2 = ir.Count; + ir.Add(unchecked((uint)-1)); + irToIl.Add(instrStart); + patchList.Add((patchIdx2, target)); + RecordJoinDepth(instrStart, target, sp); + } + ensuredScriptSlots.Clear(); + break; + } + + // --- Ret --- + case ILOpCode.Throw: + { + var (thrSrc, thrSt) = evalStack[--sp]; + if (thrSt != SType.O) goto notSupported; // exceptions are always O refs + Emit2(ir, irToIl, Op.throw_o, thrSrc, instrStart); + // Unreachable code follows until the next branch target; the linear walk's + // join-depth bookkeeping handles it like the code after an unconditional br. + sp = 0; + ensuredScriptSlots.Clear(); + break; + } + + case ILOpCode.Ret: + { + if (sp > 0) + { + var (src, st) = evalStack[--sp]; + if (method.ReturnSType == SType.Vt && method.ReturnStructLayout != null) + { + // Flat-struct return. A boxed (O) value — e.g. from a path the + // lowerer left boxed — is unboxed into a Vt temp first so ret_vt + // always reads real frame bytes. + if (st != SType.Vt) + { + int vtmp = AllocStructSlot(ref frameSize, slotTypes, slotStructs, method.ReturnStructLayout); + Emit3(ir, irToIl, Op.unbox_vt, vtmp, src, instrStart); + src = vtmp; + } + Emit2(ir, irToIl, Op.ret_vt, src, instrStart); + } + else + { + // A Vt value returned through a non-Vt signature (defensive): box it. + if (st == SType.Vt) + { + int boxed = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + Emit3(ir, irToIl, Op.box_vt, boxed, src, instrStart); + src = boxed; + } + var retOp = st == SType.R4 ? Op.ret_r4 : st == SType.I4 ? Op.ret_i4 + : st == SType.I8 ? Op.ret_i8 : st == SType.R8 ? Op.ret_r8 : Op.ret_o; + Emit2(ir, irToIl, retOp, src, instrStart); + } + } + else + { + ir.Add((uint)Op.ret_void); + irToIl.Add(instrStart); + } + ensuredScriptSlots.Clear(); + break; + } + + // --- Method calls --- + // `constrained. T` prefixes a callvirt on a byref receiver. Boxed (O-slot) + // struct receivers already give constrained semantics through plain virtual + // dispatch. FLAT (Vt-slot) receivers need the type token: constrained to the + // slot's own struct type, the whole struct must box before the call — the + // receiver resolution below consumes the remembered token for that. + case ILOpCode.Constrained: + constrainedTok = BitConverter.ToInt32(il, ip); + ip += 4; + break; + + case ILOpCode.Call: + case ILOpCode.Callvirt: + { + int tok = BitConverter.ToInt32(il, ip); ip += 4; + int tokIdx = tokens.Count; tokens.Add(tok); + int ctok = constrainedTok; constrainedTok = 0; // consume the prefix, if any + + if (asm.ByToken.TryGetValue(tok, out var callee)) + { + // Detect ldloca.s + call .ctor (script struct ctor) pattern: + // if this is a .ctor and the first arg slot is a frame-addr phantom, + // emit newobj_script writing into the existing local slot. + int argc = callee.ArgCount; + int spBase = sp - argc; + if (callee.Name == ".ctor" && argc >= 1 && addrTagBySlot[evalStack[spBase].slot] >= 0) + { + int destSlot = addrTagBySlot[evalStack[spBase].slot]; + int destOff = addrByteOffBySlot[evalStack[spBase].slot]; + addrTagBySlot[evalStack[spBase].slot] = -2; // consume the addr tag + int explicitArgc = argc - 1; // exclude `this` + if (slotTypes[destSlot] == SType.Vt && destOff == 0) + { + // FLAT struct ctor: zero the destination and run the ctor body + // with `this` = the Vt slot itself. The VM copies the bytes into + // the callee's Vt arg0 and copies them back on ret (VtThisWb). + Emit2(ir, irToIl, Op.initobj, destSlot, instrStart); + ir.Add((uint)Op.call_script); irToIl.Add(instrStart); + ir.Add(unchecked((uint)-1)); irToIl.Add(instrStart); + ir.Add((uint)tokIdx); irToIl.Add(instrStart); + ir.Add((uint)argc); irToIl.Add(instrStart); + ir.Add((uint)destSlot); irToIl.Add(instrStart); // `this` + for (int k = 0; k < explicitArgc; k++) + { ir.Add((uint)evalStack[spBase + 1 + k].slot); irToIl.Add(instrStart); } + sp = spBase; // ctor is void, no push + ensuredScriptSlots.Clear(); + break; + } + ir.Add((uint)Op.newobj_script); irToIl.Add(instrStart); + ir.Add((uint)destSlot); irToIl.Add(instrStart); + ir.Add((uint)tokIdx); irToIl.Add(instrStart); + ir.Add((uint)explicitArgc); irToIl.Add(instrStart); + for (int k = 0; k < explicitArgc; k++) + { ir.Add((uint)evalStack[spBase + 1 + k].slot); irToIl.Add(instrStart); } + sp = spBase; // ctor is void, no push + } + else + { + // Instance callee: resolve a phantom receiver (ldloca/ldflda/ldelema) + // to a real slot — otherwise `this` arrives null. Flat receivers with + // a composed offset (or field/element receivers) are materialized into + // a temp with a write-back after the call (copy-in/copy-out byref + // semantics). + int wbKind = 0; // 0=none, 1=stfld_vt_vt, 2=stfld_sc_vt + int wbA = 0, wbB = 0, wbTemp = 0; + if (!callee.IsStatic && argc >= 1) + { + var (rSlot, _) = evalStack[spBase]; + int rTag = addrTagBySlot[rSlot]; + if (rTag >= 0) + { + int rOff = addrByteOffBySlot[rSlot]; + addrTagBySlot[rSlot] = -2; + if (rOff == 0 || slotTypes[rTag] != SType.Vt) + { + evalStack[spBase] = (rTag, slotTypes[rTag]); + } + else if (callee.ThisStructLayout != null) + { + int tmp = AllocStructSlot(ref frameSize, slotTypes, slotStructs, callee.ThisStructLayout); + Emit4(ir, irToIl, Op.ldfld_vt_vt, tmp, rTag, rOff, instrStart); + evalStack[spBase] = (tmp, SType.Vt); + wbKind = 1; wbA = rTag; wbB = rOff; wbTemp = tmp; + } + } + else if (rTag == -1 && addrFldOffBySlot[rSlot] >= 0 && callee.ThisStructLayout != null) + { + int parentR = addrFldObjBySlot[rSlot]; + int offR = addrFldOffBySlot[rSlot]; + addrTagBySlot[rSlot] = -2; + int tmp = AllocStructSlot(ref frameSize, slotTypes, slotStructs, callee.ThisStructLayout); + Emit4(ir, irToIl, Op.ldfld_sc_vt, tmp, parentR, offR, instrStart); + evalStack[spBase] = (tmp, SType.Vt); + wbKind = 2; wbA = parentR; wbB = offR; wbTemp = tmp; + } + else if (rTag == -1) + { + // Heap script-struct field receiver: load the ScriptObject + // reference — mutations through it propagate, no write-back. + int parentR = addrFldObjBySlot[rSlot]; + int fTokIdx = addrFldTokBySlot[rSlot]; + int fTok = tokens[fTokIdx]; + addrTagBySlot[rSlot] = -2; + int tmp = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + if (asm.FieldSlots.TryGetValue(fTok, out var rfs)) + Emit4(ir, irToIl, Op.ldfld_sc_o, tmp, parentR, rfs.Item1.FieldOffsets[rfs.Item2], instrStart); + else + Emit4(ir, irToIl, Op.ldfld_o, tmp, parentR, fTokIdx, instrStart); + evalStack[spBase] = (tmp, SType.O); + } + else if (rTag == -3 && addrElemLayoutBySlot[rSlot] != null + && callee.ThisStructLayout != null) + { + // arr[i].Method(): materialize the flat element, call with + // `this` = the temp, memcpy the element back after (wbKind 4). + int arrS = addrFldObjBySlot[rSlot]; + int idxS = addrFldTokBySlot[rSlot]; + addrTagBySlot[rSlot] = -2; + int tmp = AllocStructSlot(ref frameSize, slotTypes, slotStructs, addrElemLayoutBySlot[rSlot]!); + Emit4(ir, irToIl, Op.ldelem_vt, tmp, arrS, idxS, instrStart); + evalStack[spBase] = (tmp, SType.Vt); + wbKind = 4; wbA = arrS; wbB = idxS; wbTemp = tmp; + } + else if (rTag == -3) + { + int arrS = addrFldObjBySlot[rSlot]; + int idxS = addrFldTokBySlot[rSlot]; + addrTagBySlot[rSlot] = -2; + int tmp = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + Emit4(ir, irToIl, Op.ldelem_o, tmp, arrS, idxS, instrStart); + evalStack[spBase] = (tmp, SType.O); + } + } + // Normal script → script call; return type comes from callee's signature + bool isVoid = callee.IsVoid; + SType retSType = callee.ReturnSType; + int dst = isVoid ? -1 + : retSType == SType.Vt && callee.ReturnStructLayout != null + ? AllocStructSlot(ref frameSize, slotTypes, slotStructs, callee.ReturnStructLayout) + : AllocSlot(ref frameSize, slotTypes, slotStructs, retSType == SType.Vt ? SType.O : retSType, null); + // Resolve ldloca-phantom args BEFORE emitting: a local function's + // captured environment arrives as `ref <>c__DisplayClass` — pass the + // ScriptObject reference itself, so callee field writes propagate. + // Any other byref arg shape stays loud (emitting the phantom slot + // raw would read null/garbage at runtime — silent wrong). + for (int k = 0; k < argc; k++) + { + int aSlot = evalStack[spBase + k].slot; + if (aSlot < 0 || addrTagBySlot[aSlot] == -2) continue; + int aTag = addrTagBySlot[aSlot]; + if (aTag >= 0) + { + // Frame-local environment (ldloca in a plain method). + if (slotTypes[aTag] != SType.O || addrByteOffBySlot[aSlot] != 0) + goto notSupported; + addrTagBySlot[aSlot] = -2; + evalStack[spBase + k] = (aTag, SType.O); + } + else if (aTag == -1 && addrFldOffBySlot[aSlot] < 0) + { + // Token mode — the addr names a whole O field; a composed + // byte offset (>= 0) would point INSIDE a nested struct, + // which falls through to the loud path below. + // State-machine-hoisted environment (ldflda in MoveNext): + // load the ScriptObject field — same reference, mutations + // propagate — exactly like the heap receiver path above. + int aParent = addrFldObjBySlot[aSlot]; + int aTokIdx = addrFldTokBySlot[aSlot]; + int aTok = tokens[aTokIdx]; + addrTagBySlot[aSlot] = -2; + int tmp = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + if (asm.FieldSlots.TryGetValue(aTok, out var afs)) + Emit4(ir, irToIl, Op.ldfld_sc_o, tmp, aParent, afs.Item1.FieldOffsets[afs.Item2], instrStart); + else + Emit4(ir, irToIl, Op.ldfld_o, tmp, aParent, aTokIdx, instrStart); + evalStack[spBase + k] = (tmp, SType.O); + } + else + goto notSupported; + } + // [call_script, dst, tok_idx, argc, arg0, arg1, ...] + ir.Add((uint)Op.call_script); irToIl.Add(instrStart); + ir.Add((uint)(isVoid ? -1 : dst)); irToIl.Add(instrStart); + ir.Add((uint)tokIdx); irToIl.Add(instrStart); + ir.Add((uint)argc); irToIl.Add(instrStart); + for (int k = 0; k < argc; k++) + { ir.Add((uint)evalStack[spBase + k].slot); irToIl.Add(instrStart); } + if (wbKind == 1) Emit4(ir, irToIl, Op.stfld_vt_vt, wbA, wbB, wbTemp, instrStart); + else if (wbKind == 2) Emit4(ir, irToIl, Op.stfld_sc_vt, wbA, wbB, wbTemp, instrStart); + else if (wbKind == 4) Emit4(ir, irToIl, Op.stelem_vt, wbA, wbB, wbTemp, instrStart); + sp = spBase; + if (!isVoid) evalStack[sp++] = (dst, retSType); + } + } + else if (asm.HostCalls.TryGetValue(tok, out var hostEntry)) + { + // Detect byref params — these go through the slow boxed path with + // post-call write-back. The Fast / FastFlat shortcuts are bypassed + // (none of the registered Fast templates take byref args today). + var ps = hostEntry.Binding.Params; + int byRefArgCount = 0; + int explicitArgc = hostEntry.Binding.ParamCount; + if (ps != null) + { + int nByref = ps.Length; + if (nByref > explicitArgc) nByref = explicitArgc; + for (int k = 0; k < nByref; k++) + if (ps[k].ParameterType.IsByRef) byRefArgCount++; + } + if (byRefArgCount > 0) + { + EmitCallHostByref(ir, irToIl, evalStack, ref sp, ref frameSize, + slotTypes, slotStructs, addrTagBySlot, addrFldObjBySlot, addrFldTokBySlot, addrByteOffBySlot, + asm, tokens, hostEntry, tokIdx, ps!, instrStart); + break; + } + + int argc = hostEntry.Binding.ParamCount; + bool isVoid2 = hostEntry.IsVoid; + // Dst-slot picker. Three flat paths (all gated on + // Binding.FastIsFlat — when true the entry's Fast closure writes + // results to numFrame, so dst must be a numFrame-resident SType): + // - Vt return: AllocStructSlot, Fast writes struct bytes + // - primitive (R4/I4) return: AllocSlot of that numeric type, Fast + // writes the primitive bytes (no float/int box) + // - everything else: O slot, boxed Fast / Invoke path + // Flat dst whenever the return type HAS a layout — even on the slow + // Invoke path the executor unboxes the boxed return straight into the + // Vt slot (one boundary box), so downstream consumers (field reads, + // operator args, further calls) stay flat instead of re-boxing. + bool useFlatVt = hostEntry.ReturnStruct != null; + SType retSt = SType.O; + if (!isVoid2 && (hostEntry.ResolvedMethod ?? hostEntry.Binding.Method) is MethodInfo mi5) + { + var rt5 = mi5.ReturnType; + if (rt5 == typeof(float)) retSt = SType.R4; + else if (rt5 == typeof(int) || rt5 == typeof(bool) || rt5 == typeof(byte) + || rt5 == typeof(sbyte) || rt5 == typeof(short) || rt5 == typeof(ushort)) retSt = SType.I4; + } + else if (!isVoid2) + { + // String-keyed shim (no MethodInfo): type the result slot from the + // call site's metadata signature. Leaving numeric returns O boxed + // them, so `a.Length != a.Length` reference-compared two boxes. + retSt = hostEntry.SigRetSType; + } + // Optional explicit override (e.g. AllowBcl AttachFlatFloat sets it to R4 + // because Math.Sqrt is C# (double)→double but we narrow to float at the closure). + // default(SType) == SType.O means "unset" — leaves the Method-derived retSt alone. + if (!isVoid2 && hostEntry.Binding.FlatReturnSType != SType.O) + retSt = hostEntry.Binding.FlatReturnSType; + // Numeric returns get a NUMERIC dst even on the slow Invoke path — the + // executor unboxes into it (WrObj), and Entry.Invoke normalizes sub-int + // returns to int boxes. Leaving them O made downstream arithmetic pick + // the int fallback over boxed floats: `r.width + r.height` returned 0. + bool useFlatNum = !useFlatVt && (retSt == SType.R4 || retSt == SType.I4 + || retSt == SType.I8 || retSt == SType.R8); + int dst; + if (isVoid2) dst = -1; + else if (useFlatVt) dst = AllocStructSlot(ref frameSize, slotTypes, slotStructs, hostEntry.ReturnStruct!); + else if (useFlatNum) dst = AllocSlot(ref frameSize, slotTypes, slotStructs, retSt, null); + else dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + // willCallFlat: when true, the executor's Fast closure expects Vt args + // to be flat (no box_vt boundary). Void calls with FastIsFlat also need + // this — their closure unboxes args directly from numFrame. + bool willCallFlat = hostEntry.Binding.FastIsFlat && (useFlatVt || useFlatNum || isVoid2); + int recvSlotRaw = hostEntry.Binding.HasThis ? (int)evalStack[sp - argc - 1].slot : -1; + // Resolve receiver address phantoms to the actual value slot: + // • frame-slot address (addrTagBySlot >= 0): the local slot IS the value + // • field address (addrTagBySlot == -1): emit ldfld to load the field value + int recvSlot = recvSlotRaw; + // Write-back for a mutating value-type instance method called through a field + // address (`h.P.Scale()`): the receiver is materialised into a boxed slot, the + // call mutates that box in place, and we must store it back into the field + // afterwards — otherwise the mutation is lost. Only for value-type receivers. + bool recvWriteBack = false; + int wbFldObj = 0, wbFldToki = 0, wbFldOff = 0; bool wbSc = false; SType wbFldSt = SType.O; + int recvVtOff = 0; // composed byte offset when the receiver address points inside a Vt slot + if (recvSlotRaw >= 0) + { + int addrTag = addrTagBySlot[recvSlotRaw]; + if (addrTag >= 0) + { + // Local address → use actual local slot (value is in numFrame or refFrame) + recvSlot = addrTag; + recvVtOff = addrByteOffBySlot[recvSlotRaw]; + } + else if (addrTag == -3) + { + // Array-element receiver (`a[i].ToString()`): mirror the script-call + // resolution — materialize the element. Flat struct elements load + // into a Vt temp; scalar/ref elements box through ldelem_o (its + // executor dispatches on the array's runtime type). Previously this + // tag was unhandled here and the executor read a never-written O + // phantom slot: null receiver (found by fuzzing). + int arrS2 = addrFldObjBySlot[recvSlotRaw]; + int idxS2 = addrFldTokBySlot[recvSlotRaw]; + addrTagBySlot[recvSlotRaw] = -2; + if (addrElemLayoutBySlot[recvSlotRaw] is { } elay) + { + int tmp2 = AllocStructSlot(ref frameSize, slotTypes, slotStructs, elay); + Emit4(ir, irToIl, Op.ldelem_vt, tmp2, arrS2, idxS2, instrStart); + recvSlot = tmp2; + // a[i].fK: the receiver is a primitive field at a byte offset + // inside the materialized element — extracted below. + recvVtOff = addrByteOffBySlot[recvSlotRaw]; + } + else + { + int tmp2 = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + Emit4(ir, irToIl, Op.ldelem_o, tmp2, arrS2, idxS2, instrStart); + recvSlot = tmp2; + } + } + else if (addrTag == -1) + { + // Field address → emit ldfld to materialise the value into a new slot + int fldObj = addrFldObjBySlot[recvSlotRaw]; + int fldToki = addrFldTokBySlot[recvSlotRaw]; + int fldTok = tokens[fldToki]; + asm.FieldSTypes.TryGetValue(fldTok, out var fldSt); + bool isScField = asm.FieldSlots.TryGetValue(fldTok, out var fldFs); + // A Vt field (a flat HOST struct stored inline in PrimBytes — + // e.g. Roslyn SPILLS a struct receiver into an iterator + // state-machine field around a switch expression's branches) + // needs a layout-carrying struct slot and a byte-range copy; + // the ldfld_sc_o fallback read RefSlots at a PrimBytes offset + // and threw IndexOutOfRange (found by fuzzing). + var fldVtLay = isScField && fldSt == SType.Vt + ? fldFs.Item1.VtFieldLayouts?[fldFs.Item2] : null; + recvSlot = fldVtLay != null + ? AllocStructSlot(ref frameSize, slotTypes, slotStructs, fldVtLay) + : AllocSlot(ref frameSize, slotTypes, slotStructs, fldSt, null); + if (isScField) + { + // Prefer the COMPOSED offset when the phantom accumulated one + // (`o.sf.f1`: sf's base + f1's offset) — recomputing from the + // token alone gives f1's offset within sf, dropping sf's base + // and reading the wrong PrimBytes (found by fuzzing). + int composed = addrFldOffBySlot[recvSlotRaw]; + int fldOff = composed >= 0 ? composed : fldFs.Item1.FieldOffsets[fldFs.Item2]; + var fldOp2 = fldVtLay != null ? Op.ldfld_sc_vt + : fldSt == SType.I4 ? Op.ldfld_sc_i4 : fldSt == SType.R4 ? Op.ldfld_sc_r4 : Op.ldfld_sc_o; + Emit4(ir, irToIl, fldOp2, recvSlot, fldObj, fldOff, instrStart); + wbFldOff = fldOff; + } + else + { + var fldLoadOp = fldSt == SType.I4 ? Op.ldfld_i4 : fldSt == SType.R4 ? Op.ldfld_r4 : Op.ldfld_o; + Emit4(ir, irToIl, fldLoadOp, recvSlot, fldObj, fldToki, instrStart); + } + // A mutating instance method on a boxed value-type receiver needs its + // result written back to the field. Reference-type receivers mutate in + // place; flat (Vt) receivers take a different path and are left as-is. + if (fldSt == SType.O && hostEntry.Binding.HasThis + && hostEntry.Binding.Method?.DeclaringType?.IsValueType == true) + { + recvWriteBack = true; wbFldObj = fldObj; wbFldToki = fldToki; wbSc = isScField; wbFldSt = fldSt; + } + } + } + + // `constrained. ` on an I4-slot receiver — an enum + // local/field calling ToString/GetHashCode/HasFlag. RdObj would box + // the receiver as INT and ToString would render "1", not the member + // name; box as the real enum type (the box_enum op covers explicit + // `box` IL, this is the callvirt-receiver path). Script enums keep + // the int form — no runtime Type exists. + if (ctok != 0 && hostEntry.Binding.HasThis + && recvSlot >= 0 && recvSlot < slotTypes.Count && slotTypes[recvSlot] == SType.I4 + && ResolveHostEnumType(asm, ctok) is { } cEnumType) + { + int ctokIdx = tokens.Count; tokens.Add(ctok); + asm.TokenTypes[ctok] = cEnumType; + int boxedEnumRecv = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + Emit4(ir, irToIl, Op.box_enum, boxedEnumRecv, recvSlot, ctokIdx, instrStart); + recvSlot = boxedEnumRecv; + } + + // Receiver inside a FLAT struct slot with no Vt-aware entry (no + // ReceiverStruct, no AccessorOffset — typically an inherited virtual + // like Object.ToString reached via `constrained.`). RdObj on a Vt slot + // yields null, so the value must be materialized first. Two shapes: + // • constrained to the slot's OWN struct type (`"impact" + quaternion` + // → constrained callvirt Object.ToString when the struct overrides + // it): the receiver is the WHOLE struct — box it (box_vt) and + // dispatch virtually on the box. Without the constrained-type check + // the field extraction below misread the struct's first field as + // the receiver (Quaternion printed as its x component). + // • constrained to a PRIMITIVE field (`v.f0.ToString()`, or a struct + // array element's field): extract the primitive at its byte offset + // into a typed slot (found by fuzzing: ToString returned ""). + if (hostEntry.ReceiverStruct == null && hostEntry.Binding.AccessorOffset < 0 + && recvSlot >= 0 && recvSlot < slotTypes.Count + && slotTypes[recvSlot] == SType.Vt && slotStructs[recvSlot] is { } lay0) + { + if (recvVtOff == 0 && ctok != 0 + && TokenSimpleTypeName(asm, ctok) == lay0.TypeName) + { + int boxedRecv = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + Emit3(ir, irToIl, Op.box_vt, boxedRecv, recvSlot, instrStart); + recvSlot = boxedRecv; + } + else + { + foreach (var fld in lay0.Fields.Values) + { + if (fld.Offset != recvVtOff || fld.St is not (SType.I4 or SType.R4)) continue; + int prim = AllocSlot(ref frameSize, slotTypes, slotStructs, fld.St, null); + Emit4(ir, irToIl, fld.St == SType.I4 ? Op.ldfld_vt_i4 : Op.ldfld_vt_r4, + prim, recvSlot, recvVtOff, instrStart); + recvSlot = prim; + recvVtOff = 0; + break; + } + } + } + int spBase = sp - argc - (hostEntry.Binding.HasThis ? 1 : 0); + + // Verified trivial accessor on a FLAT receiver: `r.width` / `r.width = v` + // becomes a direct byte read/write of the backing field — no host call, + // no receiver box. (The accessor IL was verified at registration.) + if (hostEntry.Binding.AccessorOffset >= 0 && recvSlot >= 0 + && recvSlot < slotTypes.Count && slotTypes[recvSlot] == SType.Vt) + { + int accOff = recvVtOff + hostEntry.Binding.AccessorOffset; + if (argc == 0 && !isVoid2) + { + int accDst; + if (hostEntry.Binding.AccessorSt == SType.Vt) + { + // Struct-typed backing field (Bounds.center → Vector3): + // byte-range copy into a Vt slot sized by the field layout. + accDst = AllocStructSlot(ref frameSize, slotTypes, slotStructs, + hostEntry.Binding.AccessorVtLayout!); + Emit4(ir, irToIl, Op.ldfld_vt_vt, accDst, recvSlot, accOff, instrStart); + } + else + { + accDst = AllocSlot(ref frameSize, slotTypes, slotStructs, hostEntry.Binding.AccessorSt, null); + Emit4(ir, irToIl, + hostEntry.Binding.AccessorSt == SType.I4 ? Op.ldfld_vt_i4 : Op.ldfld_vt_r4, + accDst, recvSlot, accOff, instrStart); + } + sp = spBase; + evalStack[sp++] = (accDst, hostEntry.Binding.AccessorSt); + ensuredScriptSlots.Clear(); + break; + } + if (argc == 1 && isVoid2) + { + int accSrc = evalStack[sp - 1].slot; + if (hostEntry.Binding.AccessorSt == SType.Vt) + { + // Struct value into a struct-typed backing field. A boxed + // source (O slot from a host return that wasn't flattened) + // unboxes into a Vt temp first, so stfld_vt_vt always + // copies real frame bytes at the field layout's size. + if (evalStack[sp - 1].type != SType.Vt) + { + int vtmp = AllocStructSlot(ref frameSize, slotTypes, slotStructs, + hostEntry.Binding.AccessorVtLayout!); + Emit3(ir, irToIl, Op.unbox_vt, vtmp, accSrc, instrStart); + accSrc = vtmp; + } + Emit4(ir, irToIl, Op.stfld_vt_vt, recvSlot, accOff, accSrc, instrStart); + } + else + Emit4(ir, irToIl, + hostEntry.Binding.AccessorSt == SType.I4 ? Op.stfld_vt_i4 : Op.stfld_vt_r4, + recvSlot, accOff, accSrc, instrStart); + sp = spBase; + ensuredScriptSlots.Clear(); + break; + } + } + + // Vt receiver addressed at a NONZERO byte offset — a method call on a + // flat struct nested inside another flat struct (`w.p.Scale(3)` where p + // sits at offset 4 of w): call_host encodes only a slot, so the executor + // would box the WRONG bytes (from the slot start). Materialize the + // sub-struct into its own Vt temp and copy it back after the call (the + // callee may mutate the receiver). + bool recvVtWb = false; int recvVtWbBase = -1; + if (hostEntry.Binding.HasThis && recvSlot >= 0 && recvVtOff != 0 + && recvSlot < slotTypes.Count && slotTypes[recvSlot] == SType.Vt + && hostEntry.ReceiverStruct != null) + { + int rTmp = AllocStructSlot(ref frameSize, slotTypes, slotStructs, hostEntry.ReceiverStruct); + Emit4(ir, irToIl, Op.ldfld_vt_vt, rTmp, recvSlot, recvVtOff, instrStart); + recvVtWb = true; recvVtWbBase = recvSlot; + recvSlot = rTmp; + } + + // The operator-inlining decision must come BEFORE the boundary boxing: + // EmitInlinedOp synthesizes per-field arithmetic over the FLAT arg + // slots, so its args must not be boxed away first. + bool inlineOp = hostEntry.Binding.IsInlineableOp && useFlatVt + && hostEntry.ReturnStruct != null + && CanInlineOp(hostEntry, argc, hostEntry.ReturnStruct, isCtor: false); + + // Boundary box: any Vt-slot arg gets converted to a fresh O slot via + // box_vt before the call — UNLESS we'll dispatch to FastFlat, which + // reads Vt arg bytes directly from numFrame (or the op inlines). + int argBase = sp - argc; + if (!willCallFlat && !inlineOp) + { + for (int k = 0; k < argc; k++) + { + if (evalStack[argBase + k].type == SType.Vt) + { + int boxed = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + Emit3(ir, irToIl, Op.box_vt, boxed, evalStack[argBase + k].slot, instrStart); + evalStack[argBase + k] = (boxed, SType.O); + } + } + } + + // Pure operator returning Vt: synthesize per-field arithmetic instead + // of calling through call_host. + if (inlineOp) + { + EmitInlinedOp(ir, irToIl, evalStack, argBase, argc, dst, + hostEntry.ReturnStruct!, hostEntry, instrStart, isCtor: false); + sp = spBase; + evalStack[sp++] = (dst, SType.Vt); + break; + } + + ir.Add((uint)Op.call_host); irToIl.Add(instrStart); + ir.Add((uint)(isVoid2 ? -1 : dst)); irToIl.Add(instrStart); + ir.Add((uint)(hostEntry.Binding.HasThis ? recvSlot : -1)); irToIl.Add(instrStart); + ir.Add((uint)tokIdx); irToIl.Add(instrStart); + ir.Add((uint)argc); irToIl.Add(instrStart); + for (int k = 0; k < argc; k++) + { + ir.Add((uint)evalStack[argBase + k].slot); irToIl.Add(instrStart); + } + // Nested-offset Vt receiver: copy the (possibly mutated) temp back into + // its byte range of the outer struct. + if (recvVtWb) + { + ir.Add((uint)Op.stfld_vt_vt); irToIl.Add(instrStart); + ir.Add((uint)recvVtWbBase); irToIl.Add(instrStart); + ir.Add((uint)recvVtOff); irToIl.Add(instrStart); + ir.Add((uint)recvSlot); irToIl.Add(instrStart); + } + // Mutating value-type method via field address: store the mutated receiver box + // back into the field (see recvWriteBack above). + if (recvWriteBack) + { + if (wbSc) + { + var wbOp = wbFldSt == SType.I4 ? Op.stfld_sc_i4 : wbFldSt == SType.R4 ? Op.stfld_sc_r4 : Op.stfld_sc_o; + ir.Add((uint)wbOp); irToIl.Add(instrStart); + ir.Add((uint)wbFldObj); irToIl.Add(instrStart); + ir.Add((uint)wbFldOff); irToIl.Add(instrStart); + ir.Add((uint)recvSlot); irToIl.Add(instrStart); + } + else + { + var wbOp = wbFldSt == SType.I4 ? Op.stfld_i4 : wbFldSt == SType.R4 ? Op.stfld_r4 : Op.stfld_o; + ir.Add((uint)wbOp); irToIl.Add(instrStart); + ir.Add((uint)wbFldObj); irToIl.Add(instrStart); + ir.Add((uint)wbFldToki); irToIl.Add(instrStart); + ir.Add((uint)recvSlot); irToIl.Add(instrStart); + } + } + sp = spBase; + if (!isVoid2) evalStack[sp++] = (dst, useFlatVt ? SType.Vt : useFlatNum ? retSt : SType.O); + } + else if (asm.HostCtors.TryGetValue(tok, out var callCtor)) + { + // ldloca.s + call hostCtor pattern: create host object, store into local slot + int callCtorArgc = callCtor.Binding.ParamCount; // explicit params only + int spBase2 = sp - callCtorArgc - 1; // -1 for the this-addr + int thisAddrSlot = evalStack[spBase2].slot; + if (addrTagBySlot[thisAddrSlot] >= 0) + { + int destSlot = addrTagBySlot[thisAddrSlot]; + addrTagBySlot[thisAddrSlot] = -2; // consume addr tag + ir.Add((uint)Op.newobj_host); irToIl.Add(instrStart); + ir.Add((uint)destSlot); irToIl.Add(instrStart); + ir.Add((uint)tokIdx); irToIl.Add(instrStart); + ir.Add((uint)callCtorArgc); irToIl.Add(instrStart); + int argBase2 = sp - callCtorArgc; + for (int k = 0; k < callCtorArgc; k++) + { ir.Add((uint)evalStack[argBase2 + k].slot); irToIl.Add(instrStart); } + sp = spBase2; + } + else + goto notSupported; + } + else + { + // unresolved — treat as not-supported so IL path handles it + goto notSupported; + } + ensuredScriptSlots.Clear(); + break; + } + + // --- Newobj --- + case ILOpCode.Ldftn: + { + pendingFtnTok = BitConverter.ToInt32(il, ip); ip += 4; + // Placeholder for the native fn pointer; the delegate newobj pops it. + evalStack[sp++] = (-1, SType.I4); + break; + } + case ILOpCode.Ldvirtftn: + { + pendingFtnTok = BitConverter.ToInt32(il, ip); ip += 4; + // Pops the dup'd receiver copy, pushes the fn pointer placeholder — the + // original receiver stays beneath for the delegate newobj. + evalStack[sp - 1] = (-1, SType.I4); + break; + } + + case ILOpCode.Newobj: + { + int tok = BitConverter.ToInt32(il, ip); ip += 4; + int tokIdx = tokens.Count; tokens.Add(tok); + + if (pendingFtnTok != 0) + { + // Delegate construction: `recv|null; ftn; newobj D::.ctor(object, IntPtr)`. + int ftnTok = pendingFtnTok; pendingFtnTok = 0; + var delegateType = ResolveCtorParentType(asm, tok); + if (delegateType == null || !typeof(Delegate).IsAssignableFrom(delegateType)) + throw new NotSupportedException( + $"IR lowering: delegate construction in '{method.Name}' at IL+0x{instrStart:X4}" + + $" over an unresolvable delegate type (token 0x{tok:X8})"); + var site = new DelegateSite { DelegateType = delegateType }; + if (asm.ByToken.TryGetValue(ftnTok, out var scriptTarget)) + site.ScriptMethod = scriptTarget; + else if (asm.HostCalls.TryGetValue(ftnTok, out var hostTarget) + && (hostTarget.ResolvedMethod ?? hostTarget.Binding.Method as MethodInfo) is { } mi) + site.HostMethod = mi; + else + { + asm.TokenNames.TryGetValue(ftnTok, out var ftnName); + throw new NotSupportedException( + $"IR lowering: method group '{ftnName ?? $"token 0x{ftnTok:X8}"}' in " + + $"'{method.Name}' at IL+0x{instrStart:X4} did not resolve to a host or script method"); + } + (delegateSiteByTokIdx ??= new Dictionary())[tokIdx] = site; + + int recvSlot = evalStack[sp - 2].slot; + if (recvSlot < 0 || addrTagBySlot[recvSlot] != -2) + goto notSupported; // phantom/placeholder receiver — not a plain O value + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + ir.Add((uint)Op.new_delegate); irToIl.Add(instrStart); + ir.Add((uint)dst); irToIl.Add(instrStart); + ir.Add((uint)tokIdx); irToIl.Add(instrStart); + ir.Add((uint)recvSlot); irToIl.Add(instrStart); + sp -= 2; + evalStack[sp++] = (dst, SType.O); + ensuredScriptSlots.Clear(); + break; + } + + if (asm.CtorToType.TryGetValue(tok, out var newObjDesc)) + { + // Script-defined type + int argc = asm.ByToken.TryGetValue(tok, out var ctorM) ? ctorM.ArgCount - 1 : 0; + if (newObjDesc.FlatLayout != null) + { + // FLAT struct `new S(...)` as an expression: zeroed Vt temp + + // ctor call with `this` = the temp (VtThisWb copies mutations back). + int vdst = AllocStructSlot(ref frameSize, slotTypes, slotStructs, newObjDesc.FlatLayout); + Emit2(ir, irToIl, Op.initobj, vdst, instrStart); + int argBaseF = sp - argc; + ir.Add((uint)Op.call_script); irToIl.Add(instrStart); + ir.Add(unchecked((uint)-1)); irToIl.Add(instrStart); + ir.Add((uint)tokIdx); irToIl.Add(instrStart); + ir.Add((uint)(argc + 1)); irToIl.Add(instrStart); + ir.Add((uint)vdst); irToIl.Add(instrStart); // `this` + for (int k = 0; k < argc; k++) + { ir.Add((uint)evalStack[argBaseF + k].slot); irToIl.Add(instrStart); } + sp = argBaseF; + evalStack[sp++] = (vdst, SType.Vt); + ensuredScriptSlots.Clear(); + break; + } + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + ir.Add((uint)Op.newobj_script); irToIl.Add(instrStart); + ir.Add((uint)dst); irToIl.Add(instrStart); + ir.Add((uint)tokIdx); irToIl.Add(instrStart); + ir.Add((uint)argc); irToIl.Add(instrStart); + int argBase = sp - argc; + for (int k = 0; k < argc; k++) + { + ir.Add((uint)evalStack[argBase + k].slot); irToIl.Add(instrStart); + } + sp = argBase; + evalStack[sp++] = (dst, SType.O); + } + else if (asm.HostCtors.TryGetValue(tok, out var hostCtor)) + { + int argc = hostCtor.Binding.ParamCount; + // A host ctor whose declaring type is a flat-registered struct and that + // has a flat-write Fast → allocate dst as Vt and let the executor write + // the struct bytes directly. Otherwise stay on O. + // Same slow-path-flat reasoning as call_host's useFlatVt above. + bool useFlat = hostCtor.ReturnStruct != null; + int dst = useFlat + ? AllocStructSlot(ref frameSize, slotTypes, slotStructs, hostCtor.ReturnStruct!) + : AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + int argBase = sp - argc; + // Inline the ctor when field order is verified and the dst is flat Vt. + if (hostCtor.Binding.IsInlineableOp && useFlat && hostCtor.ReturnStruct != null + && CanInlineOp(hostCtor, argc, hostCtor.ReturnStruct, isCtor: true)) + { + EmitInlinedOp(ir, irToIl, evalStack, argBase, argc, dst, + hostCtor.ReturnStruct, hostCtor, instrStart, isCtor: true); + sp = argBase; + evalStack[sp++] = (dst, SType.Vt); + break; + } + ir.Add((uint)Op.newobj_host); irToIl.Add(instrStart); + ir.Add((uint)dst); irToIl.Add(instrStart); + ir.Add((uint)tokIdx); irToIl.Add(instrStart); + ir.Add((uint)argc); irToIl.Add(instrStart); + for (int k = 0; k < argc; k++) + { + ir.Add((uint)evalStack[argBase + k].slot); irToIl.Add(instrStart); + } + sp = argBase; + evalStack[sp++] = (dst, useFlat ? SType.Vt : SType.O); + } + else + { + goto notSupported; + } + ensuredScriptSlots.Clear(); + break; + } + + // --- Field access --- + case ILOpCode.Ldfld: + { + int tok = BitConverter.ToInt32(il, ip); ip += 4; + int tokIdx = tokens.Count; tokens.Add(tok); + var (obj, _) = evalStack[--sp]; + // Resolve address phantoms to actual object slots + int actualObj; + int recvOff = 0; // composed byte offset within a Vt receiver slot + int heapOff = -1; // composed PrimBytes offset for a heap receiver (-1 = token mode) + if (addrTagBySlot[obj] >= 0) + { + // Frame-slot address (ldloca.s / composed inline chain) + actualObj = addrTagBySlot[obj]; + recvOff = addrByteOffBySlot[obj]; + } + else if (addrTagBySlot[obj] == -1 && addrFldOffBySlot[obj] >= 0) + { + // Composed inline address on a heap ScriptObject: parent + byte offset. + actualObj = addrFldObjBySlot[obj]; + heapOff = addrFldOffBySlot[obj]; + } + else if (addrTagBySlot[obj] == -1) + { + // Field-address phantom (ldflda): materialise the intermediate field first + int midFldObj = addrFldObjBySlot[obj]; + int midFldToki = addrFldTokBySlot[obj]; + int midFldTok = tokens[midFldToki]; + asm.FieldSTypes.TryGetValue(midFldTok, out var midFst); + if (midFst == SType.Vt && asm.FieldSlots.TryGetValue(midFldTok, out var midFsVt)) + { + // Vt field on a script class — allocate a Vt slot and emit ldfld_sc_vt. + var midVtLay = midFsVt.Item1.VtFieldLayouts?[midFsVt.Item2]; + int midSlotVt = midVtLay != null + ? AllocStructSlot(ref frameSize, slotTypes, slotStructs, midVtLay) + : AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + int midOffVt = midFsVt.Item1.FieldOffsets[midFsVt.Item2]; + Emit4(ir, irToIl, Op.ldfld_sc_vt, midSlotVt, midFldObj, midOffVt, instrStart); + actualObj = midSlotVt; + } + else + { + int midSlot = AllocSlot(ref frameSize, slotTypes, slotStructs, midFst, null); + if (asm.FieldSlots.TryGetValue(midFldTok, out var midFs)) + { + int midOff = midFs.Item1.FieldOffsets[midFs.Item2]; + var midOp2 = midFst == SType.I4 ? Op.ldfld_sc_i4 : midFst == SType.R4 ? Op.ldfld_sc_r4 : Op.ldfld_sc_o; + Emit4(ir, irToIl, midOp2, midSlot, midFldObj, midOff, instrStart); + } + else + { + var midOp = midFst == SType.I4 ? Op.ldfld_i4 : midFst == SType.R4 ? Op.ldfld_r4 : Op.ldfld_o; + Emit4(ir, irToIl, midOp, midSlot, midFldObj, midFldToki, instrStart); + } + actualObj = midSlot; + } + } + else if (addrTagBySlot[obj] == -3 && addrElemLayoutBySlot[obj] != null) + { + // Flat array element: memcpy it into a Vt temp — the read flows through + // the Vt-receiver field branch below (no write-back needed for loads). + int arrSlot = addrFldObjBySlot[obj]; + int idxSlot = addrFldTokBySlot[obj]; + int midVt = AllocStructSlot(ref frameSize, slotTypes, slotStructs, addrElemLayoutBySlot[obj]!); + Emit4(ir, irToIl, Op.ldelem_vt, midVt, arrSlot, idxSlot, instrStart); + actualObj = midVt; + recvOff = addrByteOffBySlot[obj]; + } + else if (addrTagBySlot[obj] == -3) + { + // Array-element address (ldelema): materialise the element via ldelem. + int arrSlot = addrFldObjBySlot[obj]; + int idxSlot = addrFldTokBySlot[obj]; + int midSlot = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + Emit4(ir, irToIl, Op.ldelem_o, midSlot, arrSlot, idxSlot, instrStart); + actualObj = midSlot; + } + else + { + actualObj = obj; + } + // HOST-struct field read through a composed heap offset: the flat struct + // lives inline in a ScriptObject's PrimBytes — e.g. a Vector3 hoisted into + // an iterator state-machine field (`target.y` after a yield). Without this + // the read fell through to the boxed host-field path with the ScriptObject + // as receiver ("Field y ... is not a field on ScriptObject"). + if (heapOff >= 0 && asm.HostFields.TryGetValue(tok, out var hfheap) + && hfheap.DeclaringStruct != null) + { + if (hfheap.PrimitiveSt == SType.I4 || hfheap.PrimitiveSt == SType.R4) + { + // Primitive field: materialize the declaring struct into a Vt temp + // so the flat fast path below applies (widening kinds included). + int midVtH = AllocStructSlot(ref frameSize, slotTypes, slotStructs, hfheap.DeclaringStruct); + Emit4(ir, irToIl, Op.ldfld_sc_vt, midVtH, actualObj, heapOff, instrStart); + actualObj = midVtH; + recvOff = 0; + heapOff = -1; + } + else if (hfheap.FieldTypeName != null && asm.HostSurface != null + && asm.HostSurface.TryGetStructLayout(hfheap.FieldTypeName, out var nLayH) + && nLayH != null) + { + // NESTED struct field (`pose.P` value read): copy its byte range + // straight out at the summed offset. + int dstNH = AllocStructSlot(ref frameSize, slotTypes, slotStructs, nLayH); + evalStack[sp++] = (dstNH, SType.Vt); + Emit4(ir, irToIl, Op.ldfld_sc_vt, dstNH, actualObj, heapOff + hfheap.ByteOffset, instrStart); + break; + } + } + // Flat-struct fast path: receiver is a Vt slot AND the field is a registered + // primitive on that struct → emit ldfld_vt_* with the byte offset, bypassing + // the boxed Get delegate entirely. + if (heapOff < 0 && slotTypes[actualObj] == SType.Vt + && asm.HostFields.TryGetValue(tok, out var hfvt) + && hfvt.DeclaringStruct != null + && (hfvt.PrimitiveSt == SType.I4 || hfvt.PrimitiveSt == SType.R4)) + { + int dstv = AllocSlot(ref frameSize, slotTypes, slotStructs, hfvt.PrimitiveSt, null); + evalStack[sp++] = (dstv, hfvt.PrimitiveSt); + Emit4(ir, irToIl, LdFldVtOpFor(hfvt), dstv, actualObj, recvOff + hfvt.ByteOffset, instrStart); + break; + } + // Flat script-struct receiver (Vt frame slot): field reads are direct + // byte-offset loads; nested blittable struct fields memcpy a sub-range. + if (heapOff < 0 && slotTypes[actualObj] == SType.Vt + && asm.FieldSlots.TryGetValue(tok, out var vfs)) + { + var vfst = vfs.Item1.FieldTypes[vfs.Item2]; + int vOff = recvOff + vfs.Item1.FieldOffsets[vfs.Item2]; + if (vfst == SType.Vt) + { + var nLay = vfs.Item1.VtFieldLayouts?[vfs.Item2]; + int dstn = nLay != null + ? AllocStructSlot(ref frameSize, slotTypes, slotStructs, nLay) + : AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + evalStack[sp++] = (dstn, SType.Vt); + Emit4(ir, irToIl, Op.ldfld_vt_vt, dstn, actualObj, vOff, instrStart); + } + else + { + var pst = vfst == SType.R4 ? SType.R4 : SType.I4; + int dstn = AllocSlot(ref frameSize, slotTypes, slotStructs, pst, null); + evalStack[sp++] = (dstn, pst); + Emit4(ir, irToIl, pst == SType.I4 ? Op.ldfld_vt_i4 : Op.ldfld_vt_r4, + dstn, actualObj, vOff, instrStart); + } + break; + } + // Heap receiver with a COMPOSED inline offset (nested blittable struct + // inside a heap ScriptObject): direct PrimBytes access at the summed offset. + if (heapOff >= 0 && asm.FieldSlots.TryGetValue(tok, out var cfs)) + { + var cfst = cfs.Item1.FieldTypes[cfs.Item2]; + int cOff = heapOff + cfs.Item1.FieldOffsets[cfs.Item2]; + if (cfst == SType.Vt) + { + var nLay = cfs.Item1.VtFieldLayouts?[cfs.Item2]; + int dstn = nLay != null + ? AllocStructSlot(ref frameSize, slotTypes, slotStructs, nLay) + : AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + evalStack[sp++] = (dstn, SType.Vt); + Emit4(ir, irToIl, Op.ldfld_sc_vt, dstn, actualObj, cOff, instrStart); + } + else + { + var pst = cfst == SType.R4 ? SType.R4 : SType.I4; + int dstn = AllocSlot(ref frameSize, slotTypes, slotStructs, pst, null); + evalStack[sp++] = (dstn, pst); + Emit4(ir, irToIl, pst == SType.I4 ? Op.ldfld_sc_i4 : Op.ldfld_sc_r4, + dstn, actualObj, cOff, instrStart); + } + break; + } + asm.FieldSTypes.TryGetValue(tok, out var fst); + if (asm.FieldSlots.TryGetValue(tok, out var fsLo)) + { + int off = fsLo.Item1.FieldOffsets[fsLo.Item2]; + if (fst == SType.Vt) + { + // Host-struct Vt field stored inline in PrimBytes; copy bytes out. + var vtLay = fsLo.Item1.VtFieldLayouts?[fsLo.Item2]; + int dst2 = vtLay != null + ? AllocStructSlot(ref frameSize, slotTypes, slotStructs, vtLay) + : AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + evalStack[sp++] = (dst2, fst); + Emit4(ir, irToIl, Op.ldfld_sc_vt, dst2, actualObj, off, instrStart); + } + else + { + int dst2 = AllocSlot(ref frameSize, slotTypes, slotStructs, fst, null); + evalStack[sp++] = (dst2, fst); + var op2 = fst == SType.I4 ? Op.ldfld_sc_i4 : fst == SType.R4 ? Op.ldfld_sc_r4 : Op.ldfld_sc_o; + Emit4(ir, irToIl, op2, dst2, actualObj, off, instrStart); + } + } + else + { + int dst2 = AllocSlot(ref frameSize, slotTypes, slotStructs, fst, null); + evalStack[sp++] = (dst2, fst); + var ldfldOp = fst == SType.I4 ? Op.ldfld_i4 : fst == SType.R4 ? Op.ldfld_r4 : Op.ldfld_o; + Emit4(ir, irToIl, ldfldOp, dst2, actualObj, tokIdx, instrStart); + } + // Value-load of a script-struct field: clone so the pushed value is an + // independent copy (struct copy semantics). Field mutation uses ldflda, which + // takes a different path and is unaffected. + if (fst == SType.O && asm.FieldIsScriptStruct.Contains(tok)) + { + var (fldSlot, _) = evalStack[sp - 1]; + int cl = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + Emit3(ir, irToIl, Op.clone_sc, cl, fldSlot, instrStart); + evalStack[sp - 1] = (cl, SType.O); + } + break; + } + case ILOpCode.Ldflda: + { + int tok = BitConverter.ToInt32(il, ip); ip += 4; + int tokIdx = tokens.Count; tokens.Add(tok); + var (obj, _) = evalStack[--sp]; + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); // phantom slot + asm.FieldSTypes.TryGetValue(tok, out var fldaFst); + bool isScFldA = asm.FieldSlots.TryGetValue(tok, out var fldaFs); + int inTag = addrTagBySlot[obj]; + + // Address of a field INSIDE flat struct bytes: accumulate the byte offset + // instead of materializing — this is what makes nested chains like + // `a.inner.x = v` (ldloca a; ldflda inner; stfld x) work. HOST flat-struct + // fields (Pose.P where Pose is a registered flat struct) compose the same + // way via the FieldEntry byte offset — without this a chain rooted at a + // hoisted iterator field fell to the token-mode phantom and consumers + // reflected on a null or ScriptObject receiver. + HostBinding.FieldEntry? hfA = null; + bool isHostFlatA = !isScFldA + && asm.HostFields.TryGetValue(tok, out hfA) && hfA!.DeclaringStruct != null; + if ((isScFldA && (fldaFst == SType.Vt || fldaFst == SType.I4 || fldaFst == SType.R4)) + || isHostFlatA) + { + int fOff = isScFldA + ? fldaFs.Item1.FieldOffsets[fldaFs.Item2] + : hfA!.ByteOffset; + // "Is the addressed field itself a struct?" — gates the heap-receiver + // branch below. For host fields, anything non-primitive is a nested struct. + bool fldaIsVt = isScFldA + ? fldaFst == SType.Vt + : hfA!.PrimitiveSt != SType.I4 && hfA.PrimitiveSt != SType.R4; + if (inTag >= 0 && slotTypes[inTag] == SType.Vt) + { + // base = frame Vt slot (+ prior offset) + addrTagBySlot[dst] = inTag; + addrByteOffBySlot[dst] = addrByteOffBySlot[obj] + fOff; + addrFldTokBySlot[dst] = tokIdx; + evalStack[sp++] = (dst, SType.O); + break; + } + if (inTag == -1 && addrFldOffBySlot[obj] >= 0) + { + // base = heap parent + prior PrimBytes offset + addrTagBySlot[dst] = -1; + addrFldObjBySlot[dst] = addrFldObjBySlot[obj]; + addrFldOffBySlot[dst] = addrFldOffBySlot[obj] + fOff; + addrFldTokBySlot[dst] = tokIdx; + evalStack[sp++] = (dst, SType.O); + break; + } + if (inTag == -1 && addrFldOffBySlot[obj] < 0) + { + // base = token-addressed field phantom. Composition is only valid + // when the OUTER field is itself inline (sc-Vt); resolve its offset. + int outTok = tokens[addrFldTokBySlot[obj]]; + asm.FieldSTypes.TryGetValue(outTok, out var outFst); + if (outFst == SType.Vt && asm.FieldSlots.TryGetValue(outTok, out var outFs)) + { + addrTagBySlot[dst] = -1; + addrFldObjBySlot[dst] = addrFldObjBySlot[obj]; + addrFldOffBySlot[dst] = outFs.Item1.FieldOffsets[outFs.Item2] + fOff; + addrFldTokBySlot[dst] = tokIdx; + evalStack[sp++] = (dst, SType.O); + break; + } + } + if (inTag == -2 && slotTypes[obj] == SType.Vt) + { + // base = a Vt VALUE slot on the stack (r-value receiver) + addrTagBySlot[dst] = obj; + addrByteOffBySlot[dst] = fOff; + addrFldTokBySlot[dst] = tokIdx; + evalStack[sp++] = (dst, SType.O); + break; + } + if (inTag == -3 && addrElemLayoutBySlot[obj] != null) + { + // Address of a field inside a FLAT ARRAY ELEMENT: keep the element + // address, accumulate the byte offset (consumers materialize the + // element and write it back). + addrTagBySlot[dst] = -3; + addrFldObjBySlot[dst] = addrFldObjBySlot[obj]; + addrFldTokBySlot[dst] = addrFldTokBySlot[obj]; + addrElemLayoutBySlot[dst] = addrElemLayoutBySlot[obj]; + addrByteOffBySlot[dst] = addrByteOffBySlot[obj] + fOff; + evalStack[sp++] = (dst, SType.O); + break; + } + if (fldaIsVt) + { + // Address of an INLINE (Vt) struct field on a HEAP receiver (class + // instance or heap-struct local): offset-mode phantom rooted at the + // OBJECT slot, so consumers read/write PrimBytes in place — + // materializing would copy and lose mutations (h.pos.x = 3). + int baseObj = inTag >= 0 ? inTag : obj; + addrTagBySlot[dst] = -1; + addrFldObjBySlot[dst] = baseObj; + addrFldOffBySlot[dst] = fOff; + addrFldTokBySlot[dst] = tokIdx; + evalStack[sp++] = (dst, SType.O); + break; + } + } + + // Classic path: address of a field on a (heap) object — resolve ldloca + // bases to the actual slot; consumers materialize via the token. + int actualObj = inTag >= 0 ? inTag : obj; + addrTagBySlot[dst] = -1; // field address + addrFldObjBySlot[dst] = actualObj; + addrFldTokBySlot[dst] = tokIdx; + evalStack[sp++] = (dst, SType.O); + break; + } + + case ILOpCode.Stfld: + { + int tok = BitConverter.ToInt32(il, ip); ip += 4; + int tokIdx = tokens.Count; tokens.Add(tok); + var (src, srcT) = evalStack[--sp]; + var (obj, _) = evalStack[--sp]; + int tag = addrTagBySlot[obj]; + int recvOffS = tag >= 0 ? addrByteOffBySlot[obj] : 0; + int heapOffS = tag == -1 ? addrFldOffBySlot[obj] : -1; + // If obj is a frame-slot addr (from ldloca.s), use the actual local slot as receiver. + // If obj is a field-address phantom (ldflda on a struct class-field), materialise the + // field into a temp slot. ScriptObject is a reference type, so writing through the + // reference propagates to the parent's field slot automatically — no write-back needed. + // If obj is an array-element phantom (ldelema on a struct array), materialise the + // element the same way. + int actualObj; + if (tag >= 0) + { + actualObj = tag; // ldloca.s → resolve to actual local + } + else if (tag == -1 && heapOffS >= 0) + { + // Composed inline address on a heap ScriptObject: use the parent directly. + actualObj = addrFldObjBySlot[obj]; + } + else if (tag == -1) + { + // ldflda phantom: load the struct reference stored in the parent class field + int midFldObj = addrFldObjBySlot[obj]; + int midFldToki = addrFldTokBySlot[obj]; + int midTok = tokens[midFldToki]; + asm.FieldSTypes.TryGetValue(midTok, out var midFst); + if (midFst == SType.Vt && asm.FieldSlots.TryGetValue(midTok, out var midFs2Vt)) + { + // Vt field on a script class — allocate Vt slot and emit ldfld_sc_vt. + var midVtLay2 = midFs2Vt.Item1.VtFieldLayouts?[midFs2Vt.Item2]; + int midSlotVt2 = midVtLay2 != null + ? AllocStructSlot(ref frameSize, slotTypes, slotStructs, midVtLay2) + : AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + int midOff2Vt = midFs2Vt.Item1.FieldOffsets[midFs2Vt.Item2]; + Emit4(ir, irToIl, Op.ldfld_sc_vt, midSlotVt2, midFldObj, midOff2Vt, instrStart); + actualObj = midSlotVt2; + } + else + { + int midSlot = AllocSlot(ref frameSize, slotTypes, slotStructs, midFst, null); + if (asm.FieldSlots.TryGetValue(midTok, out var midFs2)) + { + int midOff2 = midFs2.Item1.FieldOffsets[midFs2.Item2]; + var midOp2 = midFst == SType.I4 ? Op.ldfld_sc_i4 : midFst == SType.R4 ? Op.ldfld_sc_r4 : Op.ldfld_sc_o; + Emit4(ir, irToIl, midOp2, midSlot, midFldObj, midOff2, instrStart); + } + else + { + var midOp = midFst == SType.I4 ? Op.ldfld_i4 : midFst == SType.R4 ? Op.ldfld_r4 : Op.ldfld_o; + Emit4(ir, irToIl, midOp, midSlot, midFldObj, midFldToki, instrStart); + } + actualObj = midSlot; + } + } + else if (tag == -3 && addrElemLayoutBySlot[obj] != null) + { + // Flat array element write (`arr[i].f = v`): materialize → mutate the + // Vt temp → memcpy the whole element back. Handled inline because the + // write-back must follow the field store. + int arrSlotW = addrFldObjBySlot[obj]; + int idxSlotW = addrFldTokBySlot[obj]; + var elemLayW = addrElemLayoutBySlot[obj]!; + int elemTmp = AllocStructSlot(ref frameSize, slotTypes, slotStructs, elemLayW); + Emit4(ir, irToIl, Op.ldelem_vt, elemTmp, arrSlotW, idxSlotW, instrStart); + int baseOffW = addrByteOffBySlot[obj]; + // Host-struct element field (arr[i].x on Vector3[]): FieldEntry byte offset. + if (asm.HostFields.TryGetValue(tok, out var whf) && whf.DeclaringStruct != null + && (whf.PrimitiveSt == SType.I4 || whf.PrimitiveSt == SType.R4)) + { + Emit4(ir, irToIl, StFldVtOpFor(whf), + elemTmp, baseOffW + whf.ByteOffset, src, instrStart); + Emit4(ir, irToIl, Op.stelem_vt, arrSlotW, idxSlotW, elemTmp, instrStart); + break; + } + if (asm.FieldSlots.TryGetValue(tok, out var wfs)) + { + var wfst = wfs.Item1.FieldTypes[wfs.Item2]; + int wOff = baseOffW + wfs.Item1.FieldOffsets[wfs.Item2]; + if (wfst == SType.Vt) + { + if (srcT != SType.Vt) + { + var nLayW = wfs.Item1.VtFieldLayouts?[wfs.Item2]; + if (nLayW != null) + { + int vtmpW = AllocStructSlot(ref frameSize, slotTypes, slotStructs, nLayW); + Emit3(ir, irToIl, Op.unbox_vt, vtmpW, src, instrStart); + src = vtmpW; + } + } + Emit4(ir, irToIl, Op.stfld_vt_vt, elemTmp, wOff, src, instrStart); + } + else + { + Emit4(ir, irToIl, wfst == SType.R4 ? Op.stfld_vt_r4 : Op.stfld_vt_i4, + elemTmp, wOff, src, instrStart); + } + } + Emit4(ir, irToIl, Op.stelem_vt, arrSlotW, idxSlotW, elemTmp, instrStart); + break; + } + else if (tag == -3) + { + // ldelema phantom: load the struct reference stored in the array element + int arrSlot = addrFldObjBySlot[obj]; + int idxSlot = addrFldTokBySlot[obj]; + int midSlot = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + Emit4(ir, irToIl, Op.ldelem_o, midSlot, arrSlot, idxSlot, instrStart); + actualObj = midSlot; + } + else + { + actualObj = obj; + } + // Auto-init: if this stfld writes into an O slot (script-defined struct local + // addressed via ldloca.s), emit ensure_script before the first field write. + // Roslyn omits initobj when the struct is "definitely assigned" by consecutive + // field stores, but our runtime O slot starts null — so the first stfld on + // any execution path would NRE without this guard. + // Optimization: skip if the slot is already known initialized in this basic block + // (tracked in ensuredScriptSlots). Cleared at block boundaries and after calls/branches. + // Same for a BOXED host struct local (`S s; s.x = 1; s.y = 2;` with no + // initobj): the field's declaring TypeRef token has a synthetic default + // ctor (see the parse-time hostCtors registration), and ensure_script + // creates the box through it when the slot is still null. + if (tag >= 0 && slotTypes[actualObj] == SType.O + && (asm.FieldToTypeDef.TryGetValue(tok, out int fieldTypeDef) + || (asm.HostFieldDeclTypeTok.TryGetValue(tok, out fieldTypeDef) + && asm.HostCtors.ContainsKey(fieldTypeDef)))) + { + if (!ensuredScriptSlots.Contains(actualObj)) + { + int typeDefTokIdx2 = tokens.Count; tokens.Add(fieldTypeDef); + ir.Add((uint)Op.ensure_script); irToIl.Add(instrStart); + ir.Add((uint)actualObj); irToIl.Add(instrStart); + ir.Add((uint)typeDefTokIdx2); irToIl.Add(instrStart); + } + ensuredScriptSlots.Add(actualObj); + } + // HOST-struct field write through a composed heap offset (the mirror of the + // Ldfld handling above — a flat host struct inlined in a ScriptObject's + // PrimBytes, e.g. `target.y = v` on a hoisted iterator local). + if (heapOffS >= 0 && asm.HostFields.TryGetValue(tok, out var hfheapS) + && hfheapS.DeclaringStruct != null) + { + if (hfheapS.PrimitiveSt == SType.I4 || hfheapS.PrimitiveSt == SType.R4) + { + // Primitive field: the temp is a copy, so read-modify-WRITE-BACK — + // copy the struct out, store the field into the temp (widening/ + // truncating kinds included), copy the whole struct back. + int midVtS = AllocStructSlot(ref frameSize, slotTypes, slotStructs, hfheapS.DeclaringStruct); + Emit4(ir, irToIl, Op.ldfld_sc_vt, midVtS, actualObj, heapOffS, instrStart); + Emit4(ir, irToIl, StFldVtOpFor(hfheapS), midVtS, hfheapS.ByteOffset, src, instrStart); + Emit4(ir, irToIl, Op.stfld_sc_vt, actualObj, heapOffS, midVtS, instrStart); + break; + } + if (srcT == SType.Vt) + { + // NESTED struct field (`pose.P = v`): write the source's byte range + // (stfld_sc_vt sizes from the SRC slot's layout) at the summed offset. + Emit4(ir, irToIl, Op.stfld_sc_vt, actualObj, heapOffS + hfheapS.ByteOffset, src, instrStart); + break; + } + } + // Flat-struct fast path: stfld of a primitive into a Vt slot. + if (heapOffS < 0 && slotTypes[actualObj] == SType.Vt + && asm.HostFields.TryGetValue(tok, out var hfvtS) + && hfvtS.DeclaringStruct != null + && (hfvtS.PrimitiveSt == SType.I4 || hfvtS.PrimitiveSt == SType.R4)) + { + Emit4(ir, irToIl, StFldVtOpFor(hfvtS), actualObj, recvOffS + hfvtS.ByteOffset, src, instrStart); + break; + } + // Flat script-struct receiver (Vt frame slot). + if (heapOffS < 0 && slotTypes[actualObj] == SType.Vt + && asm.FieldSlots.TryGetValue(tok, out var vfsS)) + { + var vfst = vfsS.Item1.FieldTypes[vfsS.Item2]; + int vOff = recvOffS + vfsS.Item1.FieldOffsets[vfsS.Item2]; + if (vfst == SType.Vt) + { + if (srcT != SType.Vt) + { + var nLay = vfsS.Item1.VtFieldLayouts?[vfsS.Item2]; + if (nLay != null) + { + int vtmp = AllocStructSlot(ref frameSize, slotTypes, slotStructs, nLay); + Emit3(ir, irToIl, Op.unbox_vt, vtmp, src, instrStart); + src = vtmp; + } + } + Emit4(ir, irToIl, Op.stfld_vt_vt, actualObj, vOff, src, instrStart); + } + else + { + Emit4(ir, irToIl, vfst == SType.R4 ? Op.stfld_vt_r4 : Op.stfld_vt_i4, + actualObj, vOff, src, instrStart); + } + break; + } + // Heap receiver with a COMPOSED inline offset. + if (heapOffS >= 0 && asm.FieldSlots.TryGetValue(tok, out var cfsS)) + { + var cfst = cfsS.Item1.FieldTypes[cfsS.Item2]; + int cOff = heapOffS + cfsS.Item1.FieldOffsets[cfsS.Item2]; + if (cfst == SType.Vt) + { + if (srcT != SType.Vt) + { + var nLay = cfsS.Item1.VtFieldLayouts?[cfsS.Item2]; + if (nLay != null) + { + int vtmp = AllocStructSlot(ref frameSize, slotTypes, slotStructs, nLay); + Emit3(ir, irToIl, Op.unbox_vt, vtmp, src, instrStart); + src = vtmp; + } + } + Emit4(ir, irToIl, Op.stfld_sc_vt, actualObj, cOff, src, instrStart); + } + else + { + Emit4(ir, irToIl, cfst == SType.R4 ? Op.stfld_sc_r4 : Op.stfld_sc_i4, + actualObj, cOff, src, instrStart); + } + break; + } + asm.FieldSTypes.TryGetValue(tok, out var sfSType); + if (asm.FieldSlots.TryGetValue(tok, out var sfScFs)) + { + int sfOff = sfScFs.Item1.FieldOffsets[sfScFs.Item2]; + // Vt-typed destination field (inline in PrimBytes): emit stfld_sc_vt. + if (sfSType == SType.Vt) + { + // The runtime stfld_sc_vt copies the struct bytes out of the source's + // Vt frame slot. If the value instead arrived boxed in an O slot (e.g. + // a host call/ctor whose return wasn't flattened — common when a struct + // type is registered after its consumers), unbox it into a Vt temp using + // the field's layout first, so the store always reads real frame bytes. + if (srcT != SType.Vt) + { + var fieldLay = sfScFs.Item1.VtFieldLayouts?[sfScFs.Item2]; + if (fieldLay != null) + { + int vtmp = AllocStructSlot(ref frameSize, slotTypes, slotStructs, fieldLay); + Emit3(ir, irToIl, Op.unbox_vt, vtmp, src, instrStart); + src = vtmp; + } + } + ir.Add((uint)Op.stfld_sc_vt); irToIl.Add(instrStart); + ir.Add((uint)actualObj); irToIl.Add(instrStart); + ir.Add((uint)sfOff); irToIl.Add(instrStart); + ir.Add((uint)src); irToIl.Add(instrStart); + break; + } + // Vt source into a non-Vt receiver field (script struct field boxed in + // RefSlots): box it first. + if (srcT == SType.Vt) + { + int boxed = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + Emit3(ir, irToIl, Op.box_vt, boxed, src, instrStart); + src = boxed; + } + var scOp = sfSType == SType.I4 ? Op.stfld_sc_i4 : sfSType == SType.R4 ? Op.stfld_sc_r4 : Op.stfld_sc_o; + ir.Add((uint)scOp); irToIl.Add(instrStart); + ir.Add((uint)actualObj); irToIl.Add(instrStart); + ir.Add((uint)sfOff); irToIl.Add(instrStart); + ir.Add((uint)src); irToIl.Add(instrStart); + } + else + { + // Non-script-class field (host field). If src is Vt, box it first. + if (srcT == SType.Vt) + { + int boxed = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + Emit3(ir, irToIl, Op.box_vt, boxed, src, instrStart); + src = boxed; + } + var sfldOp = sfSType == SType.I4 ? Op.stfld_i4 : sfSType == SType.R4 ? Op.stfld_r4 : Op.stfld_o; + ir.Add((uint)sfldOp); irToIl.Add(instrStart); + ir.Add((uint)actualObj); irToIl.Add(instrStart); + ir.Add((uint)tokIdx); irToIl.Add(instrStart); + ir.Add((uint)src); irToIl.Add(instrStart); + } + break; + } + case ILOpCode.Ldsfld: + { + int tok = BitConverter.ToInt32(il, ip); ip += 4; + int tokIdx = tokens.Count; tokens.Add(tok); + // Host STRUCT field (the Vector3.one shape): unbox the Get() result into + // a flat Vt slot. The O-slot form handed a BOXED struct to flat consumers + // (inlined operators, Vt args, component reads), which read the numeric + // frame and saw zeros (found by fuzzing: HVec.One + v summed only v). + if (asm.HostFields.TryGetValue(tok, out var sfe) && sfe.FieldTypeName != null + && asm.HostSurface != null + && asm.HostSurface.TryGetStructLayout(sfe.FieldTypeName, out var sLay) && sLay != null) + { + int dstv = AllocStructSlot(ref frameSize, slotTypes, slotStructs, sLay); + evalStack[sp++] = (dstv, SType.Vt); + Emit3(ir, irToIl, Op.ldsfld_struct, dstv, tokIdx, instrStart); + break; + } + // SCRIPT static of primitive type: load into a typed numeric slot, not O. + // The boxed O form broke every consumer that keys off the slot type — + // `if (s_hp == 0 && …)` compiles to brtrue on the load, and brtrue_o + // tested the BOX for null (boxed 0 is non-null → wrong branch). + if (ScriptStaticPrimitiveSType(asm, tok) is { } sst) + { + int dstn = AllocSlot(ref frameSize, slotTypes, slotStructs, sst, null); + evalStack[sp++] = (dstn, sst); + Emit3(ir, irToIl, sst == SType.I4 ? Op.ldsfld_i4 : Op.ldsfld_r4, + dstn, tokIdx, instrStart); + break; + } + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + evalStack[sp++] = (dst, SType.O); + Emit3(ir, irToIl, Op.ldsfld_o, dst, tokIdx, instrStart); + break; + } + case ILOpCode.Ldsflda: + { + int tok = BitConverter.ToInt32(il, ip); ip += 4; + int tokIdx = tokens.Count; tokens.Add(tok); + // Address of a static field. C# emits this for member calls THROUGH the + // address — `str + s_count` becomes `ldsflda s_count; call int.ToString()`. + // For IMMUTABLE field types (primitives, enums, string) the address is + // equivalent to the value. Script statics load into TYPED slots like + // Ldsfld does (an enum static then hits the constrained-enum boxing on + // the call); host prims/strings load boxed. Mutable struct statics keep + // failing — a value copy would silently drop their mutations. + if (ScriptStaticPrimitiveSType(asm, tok) is { } ast) + { + int tdst = AllocSlot(ref frameSize, slotTypes, slotStructs, ast, null); + evalStack[sp++] = (tdst, ast); + Emit3(ir, irToIl, ast == SType.I4 ? Op.ldsfld_i4 : Op.ldsfld_r4, + tdst, tokIdx, instrStart); + break; + } + if (!StaticFieldIsImmutableValue(asm, tok)) + goto notSupported; + int adst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + evalStack[sp++] = (adst, SType.O); + Emit3(ir, irToIl, Op.ldsfld_o, adst, tokIdx, instrStart); + break; + } + case ILOpCode.Stsfld: + { + int tok = BitConverter.ToInt32(il, ip); ip += 4; + int tokIdx = tokens.Count; tokens.Add(tok); + var (src, srcT) = evalStack[--sp]; + // Primitive script static: emit an unboxed typed store (mirrors Ldsfld). The old + // unconditional stsfld_o boxed every primitive static write. + if (srcT != SType.Vt && ScriptStaticPrimitiveSType(asm, tok) is { } sst) + { + Emit3(ir, irToIl, sst == SType.I4 ? Op.stsfld_i4 : Op.stsfld_r4, tokIdx, src, instrStart); + break; + } + // Host static fields take a boxed value (FieldEntry.Set); box a flat struct first. + if (srcT == SType.Vt) + { + int boxed = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + Emit3(ir, irToIl, Op.box_vt, boxed, src, instrStart); + src = boxed; + } + Emit3(ir, irToIl, Op.stsfld_o, tokIdx, src, instrStart); + break; + } + // --- Arrays --- + case ILOpCode.Newarr: + { + int elemTok = BitConverter.ToInt32(il, ip); ip += 4; + int elemTokIdx = tokens.Count; tokens.Add(elemTok); + var (lenSlot, _) = evalStack[--sp]; + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + evalStack[sp++] = (dst, SType.O); + + // Typed backing when the element type is statically int/float: the executor + // allocates int[]/float[] and element accesses skip boxing entirely. + // Flat script-struct elements get a ScriptVtArray (single byte[] backing, + // no per-element ScriptObject). Host flat structs (Vector3[]) still use the + // boxed object?[] path — the lowerer has no binding access here; follow-up. + var arrOp = Op.newarr; + var elemHandle2 = MetadataTokens.EntityHandle(elemTok); + if (elemHandle2.Kind == HandleKind.TypeReference) + { + var elemRef2 = asm.Reader.GetTypeReference((TypeReferenceHandle)elemHandle2); + if (asm.Reader.GetString(elemRef2.Namespace) == "System") + { + var elemName2 = asm.Reader.GetString(elemRef2.Name); + if (elemName2 == "Int32") arrOp = Op.newarr_i4; + else if (elemName2 == "Single") arrOp = Op.newarr_r4; + // Other primitives keep Op.newarr but get a real typed runtime + // array (bool[]/char[]/…) via the side table, so element reads box + // with the correct type (element ToString/identity were wrong when + // object?[]-backed: bool boxed as int, defaults null). + else if (PrimArrayElemType(elemName2) is { } pt) + (primArrayElemTypeByTokIdx ??= new Dictionary())[elemTokIdx] = pt; + } + } + // Host ENUM elements need a real typed array too: Roslyn skips storing + // zero-valued members into `{ ... }` initializers (newarr zeroes them), + // so an object?[] backing left NULLS where C# guarantees the zero member. + if (arrOp == Op.newarr + && (primArrayElemTypeByTokIdx == null || !primArrayElemTypeByTokIdx.ContainsKey(elemTokIdx)) + && ResolveHostEnumType(asm, elemTok) is { } enumElem2) + (primArrayElemTypeByTokIdx ??= new Dictionary())[elemTokIdx] = enumElem2; + if (arrOp == Op.newarr && FlatElemLayout(asm, elemTok) is { } elemFlat2) + { + // Flat elements — script structs AND flat host structs (new Vector3[n]). + // Also fixes uninitialized-element access: object?[] held nulls where C# + // guarantees zeroed structs; the byte backing is zeroed by construction. + arrOp = Op.newarr_vt; + (layoutByTokIdx ??= new Dictionary())[elemTokIdx] = elemFlat2; + } + + // Check for eager InitializeArray pattern (dup; ldtoken; call InitializeArray) + // If present, we can't lower it cleanly — fall through to not-supported + if (ip + 11 <= il.Length && il[ip] == 0x25 && il[ip + 1] == 0xD0) + { + if (il[ip + 6] == 0x28) + { + int callTok2 = BitConverter.ToInt32(il, ip + 7); + if (asm.TokenNames.TryGetValue(callTok2, out var calleeName2) + && calleeName2 == "RuntimeHelpers.InitializeArray/2") + { + // Skip the dup+ldtoken+call pattern and emit with init flag + int fieldTok = BitConverter.ToInt32(il, ip + 2); + int fieldTokIdx = tokens.Count; tokens.Add(fieldTok); + ip += 11; + // Emit: [newarr*, dst, lenSlot, elemTokIdx, fieldTokIdx] (5 words) + ir.Add((uint)arrOp); irToIl.Add(instrStart); + ir.Add((uint)dst); irToIl.Add(instrStart); + ir.Add((uint)lenSlot); irToIl.Add(instrStart); + ir.Add((uint)elemTokIdx); irToIl.Add(instrStart); + ir.Add((uint)fieldTokIdx); irToIl.Add(instrStart); + break; + } + } + } + + // Normal newarr (no initializer): fieldTokIdx = 0xFFFFFFFF + ir.Add((uint)arrOp); irToIl.Add(instrStart); + ir.Add((uint)dst); irToIl.Add(instrStart); + ir.Add((uint)lenSlot); irToIl.Add(instrStart); + ir.Add((uint)elemTokIdx); irToIl.Add(instrStart); + ir.Add(unchecked((uint)-1)); irToIl.Add(instrStart); + break; + } + case ILOpCode.Ldlen: + { + var (src, _) = evalStack[sp - 1]; + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.I4, null); + evalStack[sp - 1] = (dst, SType.I4); + Emit3(ir, irToIl, Op.ldlen, dst, src, instrStart); + break; + } + // Generic `ldelem ` — emitted by Roslyn only for value-type elements (reference + // types use ldelem.ref). In this representation a struct element is an O + // ScriptObject, so the destination is O, and the loaded value must be cloned for + // struct copy semantics. clone_sc is a safe pass-through for any non-ScriptObject. + case ILOpCode.Ldelem: + { + int ldeTok = BitConverter.ToInt32(il, ip); ip += 4; + var (idxSlot, _) = evalStack[--sp]; + var (arrSlot, _) = evalStack[sp - 1]; + if (FlatElemLayout(asm, ldeTok) is { } ldeFlat) + { + // Flat element: memcpy out of the ScriptVtArray backing — value + // semantics without a clone allocation. + int vdst = AllocStructSlot(ref frameSize, slotTypes, slotStructs, ldeFlat); + evalStack[sp - 1] = (vdst, SType.Vt); + Emit4(ir, irToIl, Op.ldelem_vt, vdst, arrSlot, idxSlot, instrStart); + break; + } + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + evalStack[sp - 1] = (dst, SType.O); + Emit4(ir, irToIl, Op.ldelem_o, dst, arrSlot, idxSlot, instrStart); + int cl = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + Emit3(ir, irToIl, Op.clone_sc, cl, dst, instrStart); + evalStack[sp - 1] = (cl, SType.O); + break; + } + case ILOpCode.Ldelem_i: + case ILOpCode.Ldelem_i1: + case ILOpCode.Ldelem_u1: + case ILOpCode.Ldelem_i2: + case ILOpCode.Ldelem_u2: + case ILOpCode.Ldelem_i4: + case ILOpCode.Ldelem_u4: + case ILOpCode.Ldelem_i8: + case ILOpCode.Ldelem_r4: + case ILOpCode.Ldelem_r8: + case ILOpCode.Ldelem_ref: + { + var (idxSlot, _) = evalStack[--sp]; + var (arrSlot, _) = evalStack[sp - 1]; + SType et = op == ILOpCode.Ldelem_r4 ? SType.R4 + : op == ILOpCode.Ldelem_r8 ? SType.R8 + : op == ILOpCode.Ldelem_i8 ? SType.I8 + : op == ILOpCode.Ldelem_ref ? SType.O : SType.I4; + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, et, null); + evalStack[sp - 1] = (dst, et); + Emit4(ir, irToIl, Op.ldelem_o, dst, arrSlot, idxSlot, instrStart); + break; + } + case ILOpCode.Stelem: + case ILOpCode.Stelem_i: + case ILOpCode.Stelem_i1: + case ILOpCode.Stelem_i2: + case ILOpCode.Stelem_i4: + case ILOpCode.Stelem_i8: + case ILOpCode.Stelem_r4: + case ILOpCode.Stelem_r8: + case ILOpCode.Stelem_ref: + { + int steTok = 0; + if (op == ILOpCode.Stelem) { steTok = BitConverter.ToInt32(il, ip); ip += 4; } + var (src, srcTE) = evalStack[--sp]; + var (idxSlot, _) = evalStack[--sp]; + var (arrSlot, _) = evalStack[--sp]; + if (steTok != 0 && FlatElemLayout(asm, steTok) is { } steFlat) + { + // Flat element: memcpy into the ScriptVtArray backing. A boxed (O) + // source is unboxed into a Vt temp first. + if (srcTE != SType.Vt) + { + int vtmp = AllocStructSlot(ref frameSize, slotTypes, slotStructs, steFlat); + Emit3(ir, irToIl, Op.unbox_vt, vtmp, src, instrStart); + src = vtmp; + } + Emit4(ir, irToIl, Op.stelem_vt, arrSlot, idxSlot, src, instrStart); + break; + } + // [stelem_o, arr, idx, src] + ir.Add((uint)Op.stelem_o); irToIl.Add(instrStart); + ir.Add((uint)arrSlot); irToIl.Add(instrStart); + ir.Add((uint)idxSlot); irToIl.Add(instrStart); + ir.Add((uint)src); irToIl.Add(instrStart); + break; + } + + // ldelema — push a phantom array-element address. Consumed in-place by + // ldind/stind (read or write the element directly), or as a byref call arg + // (then call_host_byref reads/writes through the array slot post-call). + case ILOpCode.Ldelema: + { + int lmaTok = BitConverter.ToInt32(il, ip); ip += 4; + var (idxSlot, _) = evalStack[--sp]; + var (arrSlot, _) = evalStack[--sp]; + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); // phantom + addrTagBySlot[dst] = -3; // array-element address + addrFldObjBySlot[dst] = arrSlot; + addrFldTokBySlot[dst] = idxSlot; // reuse slot — points to index slot, not a token + if (FlatElemLayout(asm, lmaTok) is { } lmaFlat) + addrElemLayoutBySlot[dst] = lmaFlat; // flat elem: consumers ldelem_vt/stelem_vt + evalStack[sp++] = (dst, SType.O); + break; + } + + // initobj — zero-initialize the value-type at the address. For our model: + // - phantom frame-slot address pointing to a Vt slot: zero the slot's bytes. + // - phantom frame-slot address pointing to an O slot (script struct): emit newobj_script + // with 0 explicit args to create a zero-initialized ScriptObject. + // - phantom field address: stfld of null/zero. + // - phantom array-element address: stelem of null/zero. + case ILOpCode.Initobj: + { + int typeDefTok = BitConverter.ToInt32(il, ip); + ip += 4; // skip type token + var (addrSlot, _) = evalStack[--sp]; + int tag = addrTagBySlot[addrSlot]; + if (tag >= 0) + { + int targetSlot = tag; + SType ts = slotTypes[targetSlot]; + // Roslyn REUSES one temp local across consecutive struct initializers + // (`F(new V{...}, new V{...})`): the first arg's eval-stack entry still + // points at the slot this initobj is about to zero. CLR stack semantics + // say that entry is a COPY — materialize it before overwriting. + ProtectStackAliases(ir, irToIl, evalStack, sp, ref frameSize, + slotTypes, slotStructs, targetSlot, instrStart); + if (ts == SType.Vt) + { + ir.Add((uint)Op.initobj); irToIl.Add(instrStart); + ir.Add((uint)targetSlot); irToIl.Add(instrStart); + } + else if (ts == SType.I4 || ts == SType.R4) + { + Emit3(ir, irToIl, Op.ldc_i4, targetSlot, 0, instrStart); + } + else if (asm.TypeDefToType.ContainsKey(typeDefTok)) + { + // Script-defined struct/class O slot. + // If there is an explicit 0-arg ctor, call it via newobj_script. + // Otherwise (default struct ctor with RVA=0), zero-init without a call. + if (asm.TypeDefToCtorTok.TryGetValue(typeDefTok, out int ctorTok)) + { + int ctorTokIdx = tokens.Count; tokens.Add(ctorTok); + ir.Add((uint)Op.newobj_script); irToIl.Add(instrStart); + ir.Add((uint)targetSlot); irToIl.Add(instrStart); + ir.Add((uint)ctorTokIdx); irToIl.Add(instrStart); + ir.Add(0u); irToIl.Add(instrStart); // argc = 0 explicit args + } + else + { + // No body ctor — emit initobj_script with TypeDef token. + int typeDefTokIdx = tokens.Count; tokens.Add(typeDefTok); + ir.Add((uint)Op.initobj_script); irToIl.Add(instrStart); + ir.Add((uint)targetSlot); irToIl.Add(instrStart); + ir.Add((uint)typeDefTokIdx); irToIl.Add(instrStart); + } + // Slot is now initialized: subsequent stfld in this block won't need ensure_script. + ensuredScriptSlots.Add(targetSlot); + } + else if (PrimitiveSTypeForTypeToken(asm, typeDefTok) is { } pst) + { + // `initobj System.Int32` on a local PreClassifyLocals never saw a + // store to (Roslyn rewrites `stloc ` into `ldloca; initobj` + // when the constant is default(T)) — the slot defaulted to O. Retype + // it numeric and zero it; otherwise the value read null (found by + // fuzzing: `(byte)(p*0)` folds to 0, so `(...).ToString()` saw null). + slotTypes[targetSlot] = pst; + Emit3(ir, irToIl, pst == SType.R4 ? Op.ldc_r4 : Op.ldc_i4, targetSlot, 0, instrStart); + } + else if (asm.HostCtors.ContainsKey(typeDefTok)) + { + // Boxed host struct local: materialize the default box so the + // initializer's stfld sequence has a target (registered at parse + // time, keyed by the type token). + int hostTypeTokIdx = tokens.Count; tokens.Add(typeDefTok); + ir.Add((uint)Op.newobj_host); irToIl.Add(instrStart); + ir.Add((uint)targetSlot); irToIl.Add(instrStart); + ir.Add((uint)hostTypeTokIdx); irToIl.Add(instrStart); + ir.Add(0u); irToIl.Add(instrStart); // argc = 0 + ensuredScriptSlots.Add(targetSlot); + } + else + { + Emit2(ir, irToIl, Op.ldnull, targetSlot, instrStart); + } + } + else if (tag == -1) + { + // field-address initobj: store null / 0 / zero-Vt into the field. + int objSlot = addrFldObjBySlot[addrSlot]; + int tokIdx2 = addrFldTokBySlot[addrSlot]; + int tok2 = tokens[tokIdx2]; + asm.FieldSTypes.TryGetValue(tok2, out var fst2); + // Vt (flat host struct) field inline in the ScriptObject's PrimBytes — + // Roslyn zero-inits hoisted iterator locals through their field address + // (`ldarg.0; ldflda '5__N'; initobj Vec2`). Zero a Vt temp and copy + // its bytes in. The reference path below would emit stfld_sc_o with the + // field's BYTE offset as a RefSlots INDEX (found live: RefSlots[24] out + // of bounds on an iterator state machine). + if (fst2 == SType.Vt && asm.FieldSlots.TryGetValue(tok2, out var vtFsI) + && vtFsI.Item1.VtFieldLayouts?[vtFsI.Item2] is { } vtLayI) + { + int zeroVt = AllocStructSlot(ref frameSize, slotTypes, slotStructs, vtLayI); + ir.Add((uint)Op.initobj); irToIl.Add(instrStart); + ir.Add((uint)zeroVt); irToIl.Add(instrStart); + // A composed phantom carries the summed PrimBytes offset; a plain + // field phantom resolves it from the descriptor. + int vtOffI = addrFldOffBySlot[addrSlot] >= 0 + ? addrFldOffBySlot[addrSlot] + : vtFsI.Item1.FieldOffsets[vtFsI.Item2]; + Emit4(ir, irToIl, Op.stfld_sc_vt, objSlot, vtOffI, zeroVt, instrStart); + break; + } + // Same shape one level deeper: initobj on a HOST struct member of a + // hoisted flat struct (`pose.P = default` lowers to + // `ldflda ''; ldflda Pose::P; initobj Vec2`). The composed + // phantom's offset already sums the whole chain; zero the nested + // struct's byte range there. + if (addrFldOffBySlot[addrSlot] >= 0 + && asm.HostFields.TryGetValue(tok2, out var hfI) && hfI.DeclaringStruct != null + && hfI.PrimitiveSt != SType.I4 && hfI.PrimitiveSt != SType.R4 + && hfI.FieldTypeName != null && asm.HostSurface != null + && asm.HostSurface.TryGetStructLayout(hfI.FieldTypeName, out var nLayI) + && nLayI != null) + { + int zeroVtH = AllocStructSlot(ref frameSize, slotTypes, slotStructs, nLayI); + ir.Add((uint)Op.initobj); irToIl.Add(instrStart); + ir.Add((uint)zeroVtH); irToIl.Add(instrStart); + Emit4(ir, irToIl, Op.stfld_sc_vt, objSlot, addrFldOffBySlot[addrSlot], zeroVtH, instrStart); + break; + } + int zeroSlot = AllocSlot(ref frameSize, slotTypes, slotStructs, fst2, null); + if (fst2 == SType.I4 || fst2 == SType.R4) + Emit3(ir, irToIl, Op.ldc_i4, zeroSlot, 0, instrStart); + else + Emit2(ir, irToIl, Op.ldnull, zeroSlot, instrStart); + if (asm.FieldSlots.TryGetValue(tok2, out var sfScFsI)) + { + int sfOffI = sfScFsI.Item1.FieldOffsets[sfScFsI.Item2]; + var scOpI = fst2 == SType.I4 ? Op.stfld_sc_i4 : fst2 == SType.R4 ? Op.stfld_sc_r4 : Op.stfld_sc_o; + ir.Add((uint)scOpI); irToIl.Add(instrStart); + ir.Add((uint)objSlot); irToIl.Add(instrStart); + ir.Add((uint)sfOffI); irToIl.Add(instrStart); + ir.Add((uint)zeroSlot); irToIl.Add(instrStart); + } + else + { + var sfldOp = fst2 == SType.I4 ? Op.stfld_i4 : fst2 == SType.R4 ? Op.stfld_r4 : Op.stfld_o; + ir.Add((uint)sfldOp); irToIl.Add(instrStart); + ir.Add((uint)objSlot); irToIl.Add(instrStart); + ir.Add((uint)tokIdx2); irToIl.Add(instrStart); + ir.Add((uint)zeroSlot); irToIl.Add(instrStart); + } + } + else if (tag == -3) + { + // array-element initobj: stelem of null/0. + int arrSlot = addrFldObjBySlot[addrSlot]; + int idxSlot = addrFldTokBySlot[addrSlot]; + int zeroSlot = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + Emit2(ir, irToIl, Op.ldnull, zeroSlot, instrStart); + ir.Add((uint)Op.stelem_o); irToIl.Add(instrStart); + ir.Add((uint)arrSlot); irToIl.Add(instrStart); + ir.Add((uint)idxSlot); irToIl.Add(instrStart); + ir.Add((uint)zeroSlot); irToIl.Add(instrStart); + } + else + goto notSupported; + break; + } + + // ldind.* — dereference an address. The address may be: + // • a frame-slot address (addrTagBySlot[s] >= 0): read from that slot + // • a field address (addrTagBySlot[s] == -1): emit ldfld + // • an array-element address (addrTagBySlot[s] == -3): emit ldelem + case ILOpCode.Ldind_i1: case ILOpCode.Ldind_u1: case ILOpCode.Ldind_i2: + case ILOpCode.Ldind_u2: case ILOpCode.Ldind_i4: case ILOpCode.Ldind_u4: + case ILOpCode.Ldind_i: case ILOpCode.Ldind_r4: case ILOpCode.Ldind_r8: + case ILOpCode.Ldind_ref: + { + var (addrSlot, _) = evalStack[--sp]; + int tag = addrTagBySlot[addrSlot]; + SType ldindT = (op == ILOpCode.Ldind_r4 || op == ILOpCode.Ldind_r8) ? SType.R4 + : (op == ILOpCode.Ldind_ref) ? SType.O : SType.I4; + if (tag == -1 && addrFldOffBySlot[addrSlot] >= 0) + { + // Composed inline address on a heap ScriptObject: direct PrimBytes access. + int objSlot = addrFldObjBySlot[addrSlot]; + int cOff = addrFldOffBySlot[addrSlot]; + var pst = ldindT == SType.R4 ? SType.R4 : SType.I4; + int dst2 = AllocSlot(ref frameSize, slotTypes, slotStructs, pst, null); + evalStack[sp++] = (dst2, pst); + Emit4(ir, irToIl, pst == SType.I4 ? Op.ldfld_sc_i4 : Op.ldfld_sc_r4, dst2, objSlot, cOff, instrStart); + } + else if (tag == -1) + { + // field address: emit ldfld + int objSlot = addrFldObjBySlot[addrSlot]; + int tokIdx2 = addrFldTokBySlot[addrSlot]; + int tok2 = tokens[tokIdx2]; + asm.FieldSTypes.TryGetValue(tok2, out var fst2); + int dst2 = AllocSlot(ref frameSize, slotTypes, slotStructs, fst2, null); + evalStack[sp++] = (dst2, fst2); + if (asm.FieldSlots.TryGetValue(tok2, out var fsLo2)) + { + int off2 = fsLo2.Item1.FieldOffsets[fsLo2.Item2]; + var ldfldOp2 = fst2 == SType.I4 ? Op.ldfld_sc_i4 : fst2 == SType.R4 ? Op.ldfld_sc_r4 : Op.ldfld_sc_o; + Emit4(ir, irToIl, ldfldOp2, dst2, objSlot, off2, instrStart); + } + else + { + var ldfldOp2 = fst2 == SType.I4 ? Op.ldfld_i4 : fst2 == SType.R4 ? Op.ldfld_r4 : Op.ldfld_o; + Emit4(ir, irToIl, ldfldOp2, dst2, objSlot, tokIdx2, instrStart); + } + } + else if (tag == -3 && addrElemLayoutBySlot[addrSlot] != null) + { + // Flat array element field read via address: materialize the element + // and read the field at the composed offset. + int arrSlot = addrFldObjBySlot[addrSlot]; + int idxSlot = addrFldTokBySlot[addrSlot]; + int elemTmp = AllocStructSlot(ref frameSize, slotTypes, slotStructs, addrElemLayoutBySlot[addrSlot]!); + Emit4(ir, irToIl, Op.ldelem_vt, elemTmp, arrSlot, idxSlot, instrStart); + var pst = ldindT == SType.R4 ? SType.R4 : SType.I4; + int dst2 = AllocSlot(ref frameSize, slotTypes, slotStructs, pst, null); + evalStack[sp++] = (dst2, pst); + Emit4(ir, irToIl, pst == SType.I4 ? Op.ldfld_vt_i4 : Op.ldfld_vt_r4, + dst2, elemTmp, addrByteOffBySlot[addrSlot], instrStart); + } + else if (tag == -3) + { + // array element address: emit ldelem (chooses dst type from ldind suffix) + int arrSlot = addrFldObjBySlot[addrSlot]; + int idxSlot = addrFldTokBySlot[addrSlot]; + int dst2 = AllocSlot(ref frameSize, slotTypes, slotStructs, ldindT, null); + evalStack[sp++] = (dst2, ldindT); + Emit4(ir, irToIl, Op.ldelem_o, dst2, arrSlot, idxSlot, instrStart); + } + else if (tag >= 0) + { + int targetSlot = tag; + SType tgt = slotTypes[targetSlot]; + if (tgt == SType.Vt) + { + // Address inside a flat struct's bytes: read the field at the + // composed byte offset — a plain mov reads word 0 regardless of + // the addressed field and silently misreads offsets > 0. + int vOff2 = addrByteOffBySlot[addrSlot]; + var pst = ldindT == SType.R4 ? SType.R4 : SType.I4; + int dst2 = AllocSlot(ref frameSize, slotTypes, slotStructs, pst, null); + evalStack[sp++] = (dst2, pst); + Emit4(ir, irToIl, pst == SType.I4 ? Op.ldfld_vt_i4 : Op.ldfld_vt_r4, dst2, targetSlot, vOff2, instrStart); + } + else + { + int dst2 = AllocSlot(ref frameSize, slotTypes, slotStructs, tgt, null); + evalStack[sp++] = (dst2, tgt); + Emit3(ir, irToIl, Op.mov, dst2, targetSlot, instrStart); + } + } + else + { + // normal slot (e.g. ldind after non-phantom): copy it + int dst2 = AllocSlot(ref frameSize, slotTypes, slotStructs, slotTypes[addrSlot], null); + evalStack[sp++] = (dst2, slotTypes[addrSlot]); + Emit3(ir, irToIl, Op.mov, dst2, addrSlot, instrStart); + } + break; + } + + // stind.* — write through an address. The address may be: + // • a frame-slot address (addrTagBySlot[s] >= 0): mov val → that slot + // • a field address (addrTagBySlot[s] == -1): emit stfld + // • an array-element address (addrTagBySlot[s] == -3): emit stelem + case ILOpCode.Stind_ref: case ILOpCode.Stind_i1: case ILOpCode.Stind_i2: + case ILOpCode.Stind_i4: case ILOpCode.Stind_r4: case ILOpCode.Stind_r8: + { + var (val, _) = evalStack[--sp]; + var (addrSlot, _) = evalStack[--sp]; + int tag = addrTagBySlot[addrSlot]; + + if (tag == -1 && addrFldOffBySlot[addrSlot] >= 0) + { + // Composed inline address on a heap ScriptObject: write PrimBytes direct. + int objSlot = addrFldObjBySlot[addrSlot]; + int cOff = addrFldOffBySlot[addrSlot]; + bool isR4s = op == ILOpCode.Stind_r4 || op == ILOpCode.Stind_r8; + Emit4(ir, irToIl, isR4s ? Op.stfld_sc_r4 : Op.stfld_sc_i4, objSlot, cOff, val, instrStart); + } + else if (tag == -1) + { + // field address: emit stfld + int objSlot = addrFldObjBySlot[addrSlot]; + int tokIdx2 = addrFldTokBySlot[addrSlot]; + int tok2 = tokens[tokIdx2]; + asm.FieldSTypes.TryGetValue(tok2, out var fst2); + if (asm.FieldSlots.TryGetValue(tok2, out var sfScFs2)) + { + int sfOff2 = sfScFs2.Item1.FieldOffsets[sfScFs2.Item2]; + var scOp2 = fst2 == SType.I4 ? Op.stfld_sc_i4 : fst2 == SType.R4 ? Op.stfld_sc_r4 : Op.stfld_sc_o; + ir.Add((uint)scOp2); irToIl.Add(instrStart); + ir.Add((uint)objSlot); irToIl.Add(instrStart); + ir.Add((uint)sfOff2); irToIl.Add(instrStart); + ir.Add((uint)val); irToIl.Add(instrStart); + } + else + { + var sfldOp = fst2 == SType.I4 ? Op.stfld_i4 : fst2 == SType.R4 ? Op.stfld_r4 : Op.stfld_o; + ir.Add((uint)sfldOp); irToIl.Add(instrStart); + ir.Add((uint)objSlot); irToIl.Add(instrStart); + ir.Add((uint)tokIdx2); irToIl.Add(instrStart); + ir.Add((uint)val); irToIl.Add(instrStart); + } + } + else if (tag == -3 && addrElemLayoutBySlot[addrSlot] != null) + { + // Flat array element field write via address: read-modify-write the + // whole element (materialize, patch the field, memcpy back). + int arrSlot = addrFldObjBySlot[addrSlot]; + int idxSlot = addrFldTokBySlot[addrSlot]; + int elemTmp = AllocStructSlot(ref frameSize, slotTypes, slotStructs, addrElemLayoutBySlot[addrSlot]!); + Emit4(ir, irToIl, Op.ldelem_vt, elemTmp, arrSlot, idxSlot, instrStart); + bool isR4st = op == ILOpCode.Stind_r4 || op == ILOpCode.Stind_r8; + Emit4(ir, irToIl, isR4st ? Op.stfld_vt_r4 : Op.stfld_vt_i4, + elemTmp, addrByteOffBySlot[addrSlot], val, instrStart); + Emit4(ir, irToIl, Op.stelem_vt, arrSlot, idxSlot, elemTmp, instrStart); + } + else if (tag == -3) + { + int arrSlot = addrFldObjBySlot[addrSlot]; + int idxSlot = addrFldTokBySlot[addrSlot]; + ir.Add((uint)Op.stelem_o); irToIl.Add(instrStart); + ir.Add((uint)arrSlot); irToIl.Add(instrStart); + ir.Add((uint)idxSlot); irToIl.Add(instrStart); + ir.Add((uint)val); irToIl.Add(instrStart); + } + else if (tag >= 0) + { + if (slotTypes[tag] == SType.Vt) + { + // Write the field at the composed byte offset within the flat + // struct's bytes (a plain mov would clobber word 0 AND retarget + // nothing at offsets > 0). + bool isR4s2 = op == ILOpCode.Stind_r4 || op == ILOpCode.Stind_r8; + Emit4(ir, irToIl, isR4s2 ? Op.stfld_vt_r4 : Op.stfld_vt_i4, tag, addrByteOffBySlot[addrSlot], val, instrStart); + } + else + { + // frame-slot address: mov val → target slot + Emit3(ir, irToIl, Op.mov, tag, val, instrStart); + } + } + else + { + // Shouldn't happen — no valid stind target + throw new NotSupportedException( + $"IR lowering: stind with non-address operand in '{method.Name}' at IL+0x{instrStart:X4}"); + } + break; + } + + // ldobj — load a value-type from an address. Like ldind but for whole structs. + case ILOpCode.Ldobj: + { + ip += 4; // skip type token + var (addrSlot2, _) = evalStack[--sp]; + int tag = addrTagBySlot[addrSlot2]; + if (tag == -1) + { + // field address: emit ldfld + int objSlot = addrFldObjBySlot[addrSlot2]; + int tokIdx2 = addrFldTokBySlot[addrSlot2]; + int tok2 = tokens[tokIdx2]; + asm.FieldSTypes.TryGetValue(tok2, out var fst2); + int dst2 = AllocSlot(ref frameSize, slotTypes, slotStructs, fst2, null); + evalStack[sp++] = (dst2, fst2); + if (asm.FieldSlots.TryGetValue(tok2, out var fsLo3)) + { + int off3 = fsLo3.Item1.FieldOffsets[fsLo3.Item2]; + var ldfldOp2 = fst2 == SType.I4 ? Op.ldfld_sc_i4 : fst2 == SType.R4 ? Op.ldfld_sc_r4 : Op.ldfld_sc_o; + Emit4(ir, irToIl, ldfldOp2, dst2, objSlot, off3, instrStart); + } + else + { + var ldfldOp2 = fst2 == SType.I4 ? Op.ldfld_i4 : fst2 == SType.R4 ? Op.ldfld_r4 : Op.ldfld_o; + Emit4(ir, irToIl, ldfldOp2, dst2, objSlot, tokIdx2, instrStart); + } + } + else if (tag == -3 && addrElemLayoutBySlot[addrSlot2] != null) + { + int arrSlot = addrFldObjBySlot[addrSlot2]; + int idxSlot = addrFldTokBySlot[addrSlot2]; + int dst2 = AllocStructSlot(ref frameSize, slotTypes, slotStructs, addrElemLayoutBySlot[addrSlot2]!); + evalStack[sp++] = (dst2, SType.Vt); + Emit4(ir, irToIl, Op.ldelem_vt, dst2, arrSlot, idxSlot, instrStart); + } + else if (tag == -3) + { + int arrSlot = addrFldObjBySlot[addrSlot2]; + int idxSlot = addrFldTokBySlot[addrSlot2]; + int dst2 = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + evalStack[sp++] = (dst2, SType.O); + Emit4(ir, irToIl, Op.ldelem_o, dst2, arrSlot, idxSlot, instrStart); + } + else if (tag >= 0) + { + // frame-slot address: mov / mov_vt from that slot (ldfld_vt_vt when the + // address points INSIDE the flat struct at a composed offset). + SType tgt = slotTypes[tag]; + if (tgt == SType.Vt) + { + int vOff3 = addrByteOffBySlot[addrSlot2]; + if (vOff3 > 0) + { + int lTok = tokens[addrFldTokBySlot[addrSlot2]]; + HostBinding.StructLayout? nLay = null; + if (asm.FieldSlots.TryGetValue(lTok, out var lfs)) + nLay = lfs.Item1.VtFieldLayouts?[lfs.Item2]; + int dst3 = nLay != null + ? AllocStructSlot(ref frameSize, slotTypes, slotStructs, nLay) + : AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + evalStack[sp++] = (dst3, SType.Vt); + Emit4(ir, irToIl, Op.ldfld_vt_vt, dst3, tag, vOff3, instrStart); + } + else + { + var lay = slotStructs[tag]; + int dst2 = AllocStructSlot(ref frameSize, slotTypes, slotStructs, lay!); + evalStack[sp++] = (dst2, SType.Vt); + Emit3(ir, irToIl, Op.mov_vt, dst2, tag, instrStart); + } + } + else + { + int dst2 = AllocSlot(ref frameSize, slotTypes, slotStructs, tgt, null); + evalStack[sp++] = (dst2, tgt); + Emit3(ir, irToIl, Op.mov, dst2, tag, instrStart); + } + } + else + goto notSupported; + break; + } + + // stobj — store a value-type to an address. Like stind but for whole structs. + case ILOpCode.Stobj: + { + ip += 4; // skip type token + var (val, _) = evalStack[--sp]; + var (addrSlot2, _) = evalStack[--sp]; + int tag = addrTagBySlot[addrSlot2]; + if (tag == -1) + { + int objSlot = addrFldObjBySlot[addrSlot2]; + int tokIdx2 = addrFldTokBySlot[addrSlot2]; + int tok2 = tokens[tokIdx2]; + asm.FieldSTypes.TryGetValue(tok2, out var fst2); + var sfldOp = fst2 == SType.I4 ? Op.stfld_i4 : fst2 == SType.R4 ? Op.stfld_r4 : Op.stfld_o; + ir.Add((uint)sfldOp); irToIl.Add(instrStart); + ir.Add((uint)objSlot); irToIl.Add(instrStart); + ir.Add((uint)tokIdx2); irToIl.Add(instrStart); + ir.Add((uint)val); irToIl.Add(instrStart); + } + else if (tag == -3 && addrElemLayoutBySlot[addrSlot2] != null) + { + int arrSlot = addrFldObjBySlot[addrSlot2]; + int idxSlot = addrFldTokBySlot[addrSlot2]; + int vSrc = val; + if (slotTypes[val] != SType.Vt) + { + int vtmpO = AllocStructSlot(ref frameSize, slotTypes, slotStructs, addrElemLayoutBySlot[addrSlot2]!); + Emit3(ir, irToIl, Op.unbox_vt, vtmpO, val, instrStart); + vSrc = vtmpO; + } + Emit4(ir, irToIl, Op.stelem_vt, arrSlot, idxSlot, vSrc, instrStart); + } + else if (tag == -3) + { + int arrSlot = addrFldObjBySlot[addrSlot2]; + int idxSlot = addrFldTokBySlot[addrSlot2]; + ir.Add((uint)Op.stelem_o); irToIl.Add(instrStart); + ir.Add((uint)arrSlot); irToIl.Add(instrStart); + ir.Add((uint)idxSlot); irToIl.Add(instrStart); + ir.Add((uint)val); irToIl.Add(instrStart); + } + else if (tag >= 0) + { + // frame-slot address: mov / mov_vt val → target slot (sub-range write + // when the address carries a composed offset into the flat bytes). + int vOffS = addrByteOffBySlot[addrSlot2]; + if (slotTypes[tag] == SType.Vt && slotTypes[val] == SType.Vt) + { + if (vOffS > 0) Emit4(ir, irToIl, Op.stfld_vt_vt, tag, vOffS, val, instrStart); + else Emit3(ir, irToIl, Op.mov_vt, tag, val, instrStart); + } + else + Emit3(ir, irToIl, Op.mov, tag, val, instrStart); + } + else + goto notSupported; + break; + } + + // cpobj is in Rejected (validator bans it as unsafe), so we never see it + // here. If a valid script ever needs struct-to-struct copy, Roslyn emits + // ldobj + stobj instead, both of which are handled above. + + default: + goto notSupported; + } + continue; + + notSupported: + // Name the opcode: "ldftn" tells the user it's a method group / delegate + // creation; "0xFE06" tells them nothing. + throw new NotSupportedException( + $"IR lowering: opcode {op.ToString().ToLowerInvariant()} (0x{(int)op:X4}) in '{method.Name}' at IL+0x{instrStart:X4} not yet supported"); + } + + // Patch forward branch targets + var irArray = ir.ToArray(); + foreach (var (pIdx, ilTarget) in patchList) + { + if (ilToIrIp.TryGetValue(ilTarget, out int irTarget)) + irArray[pIdx] = (uint)irTarget; + else if (ilTarget == il.Length) + irArray[pIdx] = (uint)irArray.Length; // legit branch to method end -> ret sentinel + else + // Out of range, or mid-instruction (not an IL boundary). Rejecting instead of the + // old silent "jump past end = return" rewrite, which turned corrupt/hostile control + // flow into silently-wrong control flow with no diagnostic. + throw new NotSupportedException( + $"branch target IL+0x{ilTarget:X4} in '{method.Name}' is out of range or not at an instruction boundary"); + } + + var slotTypesArr = slotTypes.ToArray(); + var irToIlArr = irToIl.ToArray(); + var tokensArr = tokens.ToArray(); + // Wide (I8/R8) slots span two cells under one index; the pass tables (rename, + // coalesce, retarget) reason per-cell and would merge another value into a wide + // slot's continuation cell. Until the tables learn wide widths, a method whose + // frame contains any wide slot runs unoptimized — correctness first. + bool hasWideSlots = false; + for (int wi = 0; wi < slotTypesArr.Length; wi++) + if (slotTypesArr[wi] is SType.I8 or SType.R8) { hasWideSlots = true; break; } + if (!hasWideSlots && Environment.GetEnvironmentVariable("ILINTERPRETER_NOOPT") == null) { + var skip = Environment.GetEnvironmentVariable("ILINTERPRETER_SKIP_PASS") ?? ""; + if (!skip.Contains("frl")) ForwardRedundantLoads(ref irArray, ref irToIlArr, slotTypesArr, tokensArr); + if (!skip.Contains("fci")) FoldConstantImmediates(ref irArray, ref irToIlArr, slotTypesArr); + if (!skip.Contains("cdm")) CoalesceDestMovs(ref irArray, ref irToIlArr, slotTypesArr); + if (!skip.Contains("fcb")) FoldCompareBranch(ref irArray, ref irToIlArr, slotTypesArr); + if (!skip.Contains("ffl")) FoldForIntLoop(ref irArray, ref irToIlArr, slotTypesArr); + if (!skip.Contains("hlc")) HoistLoopConsts(ref irArray, ref irToIlArr, slotTypesArr, method.ArgCount); + } + + // Pre-resolve fast delegates per tokIdx so call_host can skip the dict + // lookup. Setup-time cost; eliminates ~37 ns/iter from mixed bench + // (call_host is dispatched 3+ times per inner step there). + FastCallDelegate?[]? hostFastByTokIdx = null; + bool[]? hostFastVtRecvByTokIdx = null; + bool[]? hostFastWideOkByTokIdx = null; + ParsedMethod?[]? calleeByTokIdx = null; + for (int t = 0; t < tokensArr.Length; t++) + { + int tok = tokensArr[t]; + if (asm.HostCalls.TryGetValue(tok, out var he) && he.Binding.Fast != null) + { + if (hostFastByTokIdx == null) hostFastByTokIdx = new FastCallDelegate?[tokensArr.Length]; + hostFastByTokIdx[t] = he.Binding.Fast; + if (he.Binding.FastVtRecv) + { + if (hostFastVtRecvByTokIdx == null) hostFastVtRecvByTokIdx = new bool[tokensArr.Length]; + hostFastVtRecvByTokIdx[t] = true; + } + if (he.Binding.FastWideOk) + { + if (hostFastWideOkByTokIdx == null) hostFastWideOkByTokIdx = new bool[tokensArr.Length]; + hostFastWideOkByTokIdx[t] = true; + } + } + if (asm.ByToken.TryGetValue(tok, out var callee)) + { + if (calleeByTokIdx == null) calleeByTokIdx = new ParsedMethod?[tokensArr.Length]; + calleeByTokIdx[t] = callee; + } + } + + int refClearLen = 0; + for (int s = slotTypesArr.Length - 1; s >= 0; s--) + if (slotTypesArr[s] == SType.O) { refClearLen = s + 1; break; } + + // A frame larger than either VM arena would write past its backing block on the first + // slot store. Reject at lowering (a clean load failure) instead of corrupting memory at + // invoke. Both arenas are indexed by the same slot number, but the reference arena is + // smaller, so a ref-heavy frame can exceed it while the numeric count still fits. + // Reachable from a pathological method body or a crafted LOCAL_SIG. + if (frameSize > Vm.NumSlots || refClearLen > Vm.RefSlots) + throw new NotSupportedException( + $"method '{method.Name}' needs {frameSize} frame slots and {refClearLen} reference slots, " + + $"over the {Vm.NumSlots}/{Vm.RefSlots}-slot arena limits"); + + return new LoweredMethod + { + Ir = irArray, + FrameSize = frameSize, + IrToIlOffset = irToIlArr, + Strings = strings.ToArray(), + Tokens = tokensArr, + SlotTypes = slotTypesArr, + StructLayouts = slotStructs.ToArray(), + HostFastByTokIdx = hostFastByTokIdx, + HostFastVtRecvByTokIdx = hostFastVtRecvByTokIdx, + HostFastWideOkByTokIdx = hostFastWideOkByTokIdx, + CalleeByTokIdx = calleeByTokIdx, + RefClearLen = refClearLen, + ArgSlot = argIndirect ? argFrameSlot : null, + LayoutByTokIdx = BuildLayoutByTokIdx(layoutByTokIdx, tokensArr.Length), + PrimArrayElemTypeByTokIdx = BuildPrimArrayTypes(primArrayElemTypeByTokIdx, tokensArr.Length), + DelegateSiteByTokIdx = BuildDelegateSites(delegateSiteByTokIdx, tokensArr.Length), + }; + } + + // Op selection for flat host-struct field access: sub-4-byte integer fields + // (Color32.r-class) need widening loads / truncating stores; everything else uses + // the plain 4-byte cell ops. + static Op LdFldVtOpFor(HostBinding.FieldEntry fe) + { + if (fe.PrimitiveSt == SType.R4) return Op.ldfld_vt_r4; + switch (fe.PrimitiveKind) + { + case 1: return Op.ldfld_vt_u1; + case 2: return Op.ldfld_vt_i1; + case 3: return Op.ldfld_vt_u2; + case 4: return Op.ldfld_vt_i2; + default: return Op.ldfld_vt_i4; + } + } + + static Op StFldVtOpFor(HostBinding.FieldEntry fe) + { + if (fe.PrimitiveSt == SType.R4) return Op.stfld_vt_r4; + switch (fe.PrimitiveKind) + { + case 1: case 2: return Op.stfld_vt_b1; + case 3: case 4: return Op.stfld_vt_b2; + default: return Op.stfld_vt_i4; + } + } + + // Runtime Type for a `box` token that names a HOST enum (TypeRef parent), null otherwise. + // Script-declared enums are TypeDefs — no runtime Type exists, so they keep the int form. + static Type? ResolveHostEnumType(ParsedAssembly asm, int tok) + { + if (asm.HostSurface == null) return null; + try + { + var h = MetadataTokens.EntityHandle(tok); + if (h.Kind != HandleKind.TypeReference) return null; + var t = ResolveSigTypeRef(asm.Reader, (TypeReferenceHandle)h, asm.HostSurface); + return t is { IsEnum: true } ? t : null; + } + catch { return null; } + } + + // Slot type for a SCRIPT static field (FieldDef) whose signature is an I4/R4-mapped + // primitive; null for host fields, reference/struct/wide types (those stay boxed O). + // Enums included: a script enum static's underlying value rides the I4 slot. + static SType? ScriptStaticPrimitiveSType(ParsedAssembly asm, int tok) + { + var h = MetadataTokens.EntityHandle(tok); + if (h.Kind != HandleKind.FieldDefinition) return null; + try + { + var blob = asm.Reader.GetBlobBytes( + asm.Reader.GetFieldDefinition((FieldDefinitionHandle)h).Signature); + if (blob.Length < 2 || blob[0] != 0x06) return null; + switch (blob[1]) + { + case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: + case 0x07: case 0x08: case 0x09: // bool..uint + return SType.I4; + case 0x0C: // float + return SType.R4; + case 0x11: // VALUETYPE coded-index — a script ENUM static maps to I4 (its + { // value flows as the underlying int everywhere else already) + int idx = 2; + int coded = DecompressIntAdv(blob, ref idx); + if ((coded & 0x03) == 0 && IsEnumTypeDef(asm.Reader, coded >> 2)) + return SType.I4; + return null; + } + default: + return null; + } + } + catch { return null; } + } + + // True when a static field's type is immutable-by-value (primitive or string), so its + // address can be lowered as a value load (see the Ldsflda case). Script FieldDefs decode + // the field signature blob; host MemberRefs consult the registered FieldEntry. + static bool StaticFieldIsImmutableValue(ParsedAssembly asm, int tok) + { + var h = MetadataTokens.EntityHandle(tok); + if (h.Kind == HandleKind.FieldDefinition) + { + try + { + var blob = asm.Reader.GetBlobBytes( + asm.Reader.GetFieldDefinition((FieldDefinitionHandle)h).Signature); + // Field sig: FIELD (0x06) then the type. 0x02..0x0D = bool..double, 0x0E = string. + return blob.Length >= 2 && blob[0] == 0x06 && blob[1] >= 0x02 && blob[1] <= 0x0E; + } + catch { return false; } + } + if (asm.HostFields.TryGetValue(tok, out var fe)) + return fe.PrimitiveSt is SType.I4 or SType.R4 || fe.FieldTypeName == "String"; + return false; + } + + // Flat layout for an array-element type token: script TypeDefs use the descriptor's + // synthesized FlatLayout; host TypeRefs resolve by simple name through the binding. + static HostBinding.StructLayout? FlatElemLayout(ParsedAssembly asm, int tok) + { + if (asm.TypeDefToType.TryGetValue(tok, out var d)) return d.FlatLayout; + var h = MetadataTokens.EntityHandle(tok); + if (h.Kind == HandleKind.TypeReference && asm.HostSurface != null) + { + string name; + try { name = asm.Reader.GetString(asm.Reader.GetTypeReference((TypeReferenceHandle)h).Name); } + catch (Exception) { return null; } + if (asm.HostSurface.TryGetStructLayout(name, out var lay)) return lay; + } + return null; + } + + static HostBinding.StructLayout?[]? BuildLayoutByTokIdx( + Dictionary? sparse, int tokenCount) + { + if (sparse == null) return null; + var arr = new HostBinding.StructLayout?[tokenCount]; + foreach (var kv in sparse) arr[kv.Key] = kv.Value; + return arr; + } + + static Type?[]? BuildPrimArrayTypes(Dictionary? sparse, int tokenCount) + { + if (sparse == null) return null; + var arr = new Type?[tokenCount]; + foreach (var kv in sparse) arr[kv.Key] = kv.Value; + return arr; + } + + static DelegateSite?[]? BuildDelegateSites(Dictionary? sparse, int tokenCount) + { + if (sparse == null) return null; + var arr = new DelegateSite?[tokenCount]; + foreach (var kv in sparse) arr[kv.Key] = kv.Value; + return arr; + } + + // Primitive element types that need a real typed runtime array (I4-mapped but whose boxed + // identity differs from int, or that C# zero-inits differently than object?[] null). Int32 + // and Single are handled by newarr_i4/newarr_r4 and are intentionally not here. + static Type? PrimArrayElemType(string elemName) => elemName switch + { + "Boolean" => typeof(bool), + "Char" => typeof(char), + "Byte" => typeof(byte), + "SByte" => typeof(sbyte), + "Int16" => typeof(short), + "UInt16" => typeof(ushort), + "Int64" => typeof(long), + "UInt64" => typeof(ulong), + "Double" => typeof(double), + _ => null, + }; + + // Constant-immediate fold: `ldc_X tmp; binop_X_nn dst, src, tmp` with a single-use + // tmp folds into `binop_X_nk dst, src, K` (K inline in the IR word) — one dispatch + // less per pair. RHS-constant only (no _kn opcodes exist); commutative ops also + // accept tmp on the LEFT via operand swap. Skipped when a branch target lands on + // the binop (the ldc would be lost on that edge). Runs BEFORE CoalesceDestMovs so + // the trailing `mov local <- tmp_dst` is still available for coalescing. + static void FoldConstantImmediates(ref uint[] ir, ref int[] irToIl, SType[] slotTypes) + { + int n = ir.Length; + if (n == 0) return; + + // Walk IR, record (ip, op, width). + var ips = new List(n / 3); + var ops = new List(n / 3); + var widths = new List(n / 3); + int pos = 0; + while (pos < n) + { + var op = (Op)ir[pos]; + int w = OpWidthForCoalesce(op, ir, pos); + if (w <= 0) return; + ips.Add(pos); ops.Add(op); widths.Add(w); + pos += w; + } + int insnCount = ips.Count; + + int slotCount = slotTypes.Length; + var reads = new int[slotCount]; + var writes = new int[slotCount]; + for (int i = 0; i < insnCount; i++) + AccumulateSlotUses(ir, ips[i], ops[i], widths[i], reads, writes, slotCount); + + var isBranchTarget = new bool[n + 1]; + for (int i = 0; i < insnCount; i++) + MarkInsnBranchTargets(ir, ips[i], ops[i], isBranchTarget); + + var deleted = new bool[insnCount]; + int deletedWords = 0; + for (int i = 0; i < insnCount - 1; i++) + { + if (deleted[i]) continue; + var ldcOp = ops[i]; + if (ldcOp != Op.ldc_i4 && ldcOp != Op.ldc_r4) continue; + + int ldcIp = ips[i]; + int tmpSlot = (int)ir[ldcIp + 1]; + uint kBits = ir[ldcIp + 2]; + + if (writes[tmpSlot] != 1 || reads[tmpSlot] != 1) continue; + + // Find the next *non-deleted* instruction. + int j = i + 1; + while (j < insnCount && deleted[j]) j++; + if (j >= insnCount) continue; + + var binOp = ops[j]; + int binIp = ips[j]; + if (widths[j] != 4) continue; + if (isBranchTarget[binIp]) continue; + + int s1 = (int)ir[binIp + 2]; + int s2 = (int)ir[binIp + 3]; + bool tmpRight = (s2 == tmpSlot); + bool tmpLeft = (s1 == tmpSlot); + if (!tmpRight && !tmpLeft) continue; + + if (!TryFoldNN(ldcOp, binOp, tmpRight, out Op nkOp)) continue; + + // Apply: rewrite binop in place, mark ldc deleted. + ir[binIp] = (uint)nkOp; + if (tmpLeft) + { + // Commutative swap: move src1 into the operand-slot position + // (word 2), put k in word 3. Original encoding was [op, dst, + // tmp_left, src_right] — we want [nk, dst, src_right, k]. + ir[binIp + 2] = (uint)s2; + } + ir[binIp + 3] = kBits; + + deleted[i] = true; + deletedWords += widths[i]; + + // Maintain reads/writes so a future pass over the same IR sees + // the correct counts (we don't iterate to fixpoint, but defensive). + reads[tmpSlot] = 0; writes[tmpSlot] = 0; + } + + if (deletedWords == 0) return; + + // Compact (same shift-table machinery as CoalesceDestMovs). + var deletedWord = new bool[n]; + for (int i = 0; i < insnCount; i++) + { + if (!deleted[i]) continue; + for (int k = 0; k < widths[i]; k++) deletedWord[ips[i] + k] = true; + } + var shift = new int[n + 1]; + int run = 0; + for (int oldIp = 0; oldIp <= n; oldIp++) + { + shift[oldIp] = run; + if (oldIp < n && deletedWord[oldIp]) run++; + } + + int newLen = n - deletedWords; + var newIr = new uint[newLen]; + var newToIl = new int[newLen]; + int dstIdx = 0; + for (int i = 0; i < insnCount; i++) + { + if (deleted[i]) continue; + int oldIp = ips[i]; + int w = widths[i]; + for (int k = 0; k < w; k++) + { + newIr[dstIdx + k] = ir[oldIp + k]; + newToIl[dstIdx + k] = irToIl[oldIp + k]; + } + PatchInsnBranchTargets(newIr, dstIdx, ops[i], shift, ir, oldIp); + dstIdx += w; + } + + ir = newIr; + irToIl = newToIl; + } + + // Map an (ldc, binop_nn) pair to the matching binop_nk. Returns false if + // we don't have an _nk variant for this combination — no fold. + // tmpRight=true means the constant is on the right (no swap needed); for + // commutative ops we may also fold tmpLeft via operand swap. + static bool TryFoldNN(Op ldcOp, Op binOp, bool tmpRight, out Op nkOp) + { + nkOp = default; + // Type compatibility: ldc_i4 with i4 binop, ldc_r4 with r4 binop. + bool isI4Ldc = ldcOp == Op.ldc_i4; + switch (binOp) + { + case Op.add_i4_nn: if (!isI4Ldc) return false; nkOp = Op.add_i4_nk; return true; // commutative + case Op.add_r4_nn: if (isI4Ldc) return false; nkOp = Op.add_r4_nk; return true; // commutative + case Op.mul_r4_nn: if (isI4Ldc) return false; nkOp = Op.mul_r4_nk; return true; // commutative + case Op.ceq_i4_nn: if (!isI4Ldc) return false; nkOp = Op.ceq_i4_nk; return true; // commutative + case Op.mul_i4_nn: if (!isI4Ldc) return false; nkOp = Op.mul_i4_nk; return true; // commutative + case Op.and_i4_nn: if (!isI4Ldc) return false; nkOp = Op.and_i4_nk; return true; // commutative + case Op.or_i4_nn: if (!isI4Ldc) return false; nkOp = Op.or_i4_nk; return true; // commutative + case Op.xor_i4_nn: if (!isI4Ldc) return false; nkOp = Op.xor_i4_nk; return true; // commutative + case Op.ceq_r4_nn: if (isI4Ldc) return false; nkOp = Op.ceq_r4_nk; return true; // commutative + // Non-commutative: tmp must be on the right. + case Op.sub_i4_nn: if (!tmpRight || !isI4Ldc) return false; nkOp = Op.sub_i4_nk; return true; + case Op.sub_r4_nn: if (!tmpRight || isI4Ldc) return false; nkOp = Op.sub_r4_nk; return true; + case Op.clt_i4_nn: if (!tmpRight || !isI4Ldc) return false; nkOp = Op.clt_i4_nk; return true; + case Op.clt_r4_nn: if (!tmpRight || isI4Ldc) return false; nkOp = Op.clt_r4_nk; return true; + case Op.cgt_i4_nn: if (!tmpRight || !isI4Ldc) return false; nkOp = Op.cgt_i4_nk; return true; + case Op.cgt_r4_nn: if (!tmpRight || isI4Ldc) return false; nkOp = Op.cgt_r4_nk; return true; + case Op.div_i4_nn: if (!tmpRight || !isI4Ldc) return false; nkOp = Op.div_i4_nk; return true; + case Op.rem_i4_nn: if (!tmpRight || !isI4Ldc) return false; nkOp = Op.rem_i4_nk; return true; + case Op.shl_i4_nn: if (!tmpRight || !isI4Ldc) return false; nkOp = Op.shl_i4_nk; return true; + case Op.shr_i4_nn: if (!tmpRight || !isI4Ldc) return false; nkOp = Op.shr_i4_nk; return true; + case Op.shr_un_i4_nn: if (!tmpRight || !isI4Ldc) return false; nkOp = Op.shr_un_i4_nk; return true; + case Op.div_r4_nn: if (!tmpRight || isI4Ldc) return false; nkOp = Op.div_r4_nk; return true; + default: return false; + } + } + + // --- Redundant-load forwarding --- + // + // Within each basic block, tracks for each (objSlot, resolvedFieldToken) + // pair which slot currently holds the field's value: + // ldfld_X dst, obj, tok → cache[(obj, tok)] = dst + // stfld_X obj, tok, src → cache[(obj, tok)] = src + // + // On a subsequent matching ldfld_X with cache hit (and matching SType), + // the second load is redundant: rewrite all reads of its dst slot to + // the cached value slot, delete the load. Slot rename is global, + // applied via a slotMap[] table; safe because the deleted load was the + // sole writer of its dst within the live region (we're conservative + // with cache invalidation). + // + // Cache invalidation events (cleared aggressively): + // - Any call (host/script/byref) — could mutate any field. + // - Any newobj — constructor side effects. + // - Any stsfld_*, stelem_* — written field/elem could alias. + // - Any branch — basic-block boundary. + // - A target landing on the next instruction also resets the block. + // + // Subset is corpus-driven: ldfld_o, ldfld_r4, ldfld_i4 (with matching + // stfld variants for store-to-load forwarding). Other field-bearing + // ops (ldelem, ldfld_struct, ldsfld) deferred — no bench evidence. + /// Removes cached (obj, field) forwards for held under + /// any object slot other than — a store through one slot must not + /// leave stale forwards alive for other slots that may alias the same object. + static void DropAliasedField(Dictionary<(int, int), int> cache, int objS, int fieldKey) + { + List<(int, int)>? stale = null; + foreach (var kv in cache) + if (kv.Key.Item2 == fieldKey && kv.Key.Item1 != objS) (stale ??= new()).Add(kv.Key); + if (stale != null) foreach (var k in stale) cache.Remove(k); + } + + static void ForwardRedundantLoads(ref uint[] ir, ref int[] irToIl, + SType[] slotTypes, int[] tokens) + { + int n = ir.Length; + if (n == 0) return; + + var ips = new List(n / 3); + var ops = new List(n / 3); + var widths = new List(n / 3); + int pos = 0; + while (pos < n) + { + var op = (Op)ir[pos]; + int w = OpWidthForCoalesce(op, ir, pos); + if (w <= 0) return; + ips.Add(pos); ops.Add(op); widths.Add(w); + pos += w; + } + int insnCount = ips.Count; + + var isBranchTarget = new bool[n + 1]; + for (int i = 0; i < insnCount; i++) + MarkInsnBranchTargets(ir, ips[i], ops[i], isBranchTarget); + + int slotCount = slotTypes.Length; + var slotMap = new int[slotCount]; + for (int i = 0; i < slotCount; i++) slotMap[i] = i; + + var deleted = new bool[insnCount]; + int deletedWords = 0; + + // (objSlot, resolvedTok) → valueSlot. Cleared at block boundaries + // and on any side effect. + var cache = new Dictionary<(int, int), int>(); + + for (int i = 0; i < insnCount; i++) + { + int ip = ips[i]; + var op = ops[i]; + + // Block boundary: an instruction that's a branch target starts + // a new block (we may have entered via either fall-through or + // jump — conservative). + if (i > 0 && isBranchTarget[ip]) cache.Clear(); + + // Invalidate cache entries whose object slot OR cached value slot is overwritten by + // this instruction. Without this, store-to-load forwarding (stfld caches the SOURCE + // slot) or load forwarding (keyed by the OBJECT slot) survives a later reassignment of + // that slot and forwards a stale value — e.g. `bx.p = s1; s1 = other; read bx.p`. + if (WritesFrameDstAt1(op)) + { + int wdst = (int)ir[ip + 1]; + if (wdst >= 0) + { + List<(int, int)>? drop = null; + foreach (var kv in cache) + if (kv.Value == wdst || kv.Key.Item1 == wdst) (drop ??= new()).Add(kv.Key); + if (drop != null) foreach (var k in drop) cache.Remove(k); + } + } + + switch (op) + { + case Op.ldfld_o: + case Op.ldfld_r4: + case Op.ldfld_i4: + { + int dst = (int)ir[ip + 1]; + int objS = (int)ir[ip + 2]; + int tokIdx = (int)ir[ip + 3]; + if ((uint)tokIdx >= (uint)tokens.Length) break; + int resolvedTok = tokens[tokIdx]; + var key = (objS, resolvedTok); + if (cache.TryGetValue(key, out int valueSlot) + && (uint)valueSlot < (uint)slotCount + && slotTypes[valueSlot] == slotTypes[dst]) + { + // Forward: subsequent reads of dst become reads of + // valueSlot; this load is redundant. + slotMap[dst] = valueSlot; + deleted[i] = true; + deletedWords += widths[i]; + } + else + { + cache[key] = dst; + } + break; + } + + case Op.ldfld_sc_o: + case Op.ldfld_sc_r4: + case Op.ldfld_sc_i4: + { + int dst = (int)ir[ip + 1]; + int objS = (int)ir[ip + 2]; + int off = (int)ir[ip + 3]; + // Negated keys avoid collision with raw token values; the ref/prim split + // (~(2*off) vs ~(2*off+1)) keeps a stfld_sc_o REF-SLOT index from aliasing + // a stfld_sc_i4 PRIM BYTE offset of the same number — that collision + // forwarded a field read to an unrelated O field's source slot (found by + // fuzzing: a hoisted char at ref slot 4 hijacked the int at prim byte 4). + var key = (objS, op == Op.ldfld_sc_o ? ~(2 * off + 1) : ~(2 * off)); + if (cache.TryGetValue(key, out int valueSlot) + && (uint)valueSlot < (uint)slotCount + && slotTypes[valueSlot] == slotTypes[dst]) + { + slotMap[dst] = valueSlot; + deleted[i] = true; + deletedWords += widths[i]; + } + else + { + cache[key] = dst; + } + break; + } + + case Op.stfld_o: + case Op.stfld_r4: + case Op.stfld_i4: + { + int objS = (int)ir[ip + 1]; + int tokIdx = (int)ir[ip + 2]; + int srcS = (int)ir[ip + 3]; + if ((uint)tokIdx >= (uint)tokens.Length) break; + int resolvedTok = tokens[tokIdx]; + // Alias hazard: another slot may reference the SAME object (`C0 b = a;`), + // so a store through one slot must drop every cached entry for the same + // field under any OTHER object slot — else `a.f0 = 5; C0 b = a; + // b.f0 = 9; read a.f0` forwards the stale 5 (found by fuzzing). + DropAliasedField(cache, objS, resolvedTok); + // The stored value lives in srcS; subsequent loads of + // (objS, tok) can forward to it. + cache[(objS, resolvedTok)] = srcS; + break; + } + + case Op.stfld_sc_o: + case Op.stfld_sc_r4: + case Op.stfld_sc_i4: + { + int objS = (int)ir[ip + 1]; + int off = (int)ir[ip + 2]; + int srcS = (int)ir[ip + 3]; + int koff = op == Op.stfld_sc_o ? ~(2 * off + 1) : ~(2 * off); // see ldfld_sc key split + DropAliasedField(cache, objS, koff); // same alias hazard as stfld_o above + cache[(objS, koff)] = srcS; + break; + } + + case Op.call_script: + case Op.call_host: + case Op.call_host_byref: + case Op.newobj_script: + case Op.newobj_host: + case Op.stsfld_i4: case Op.stsfld_r4: + case Op.stsfld_o: case Op.stsfld_struct: + case Op.stelem_i4: case Op.stelem_r4: + case Op.stelem_o: case Op.stelem_struct: + case Op.stfld_struct: + case Op.box_vt: case Op.unbox_vt: case Op.mov_vt: + case Op.stfld_vt_i4: case Op.stfld_vt_r4: + case Op.stfld_vt_b1: case Op.stfld_vt_b2: + // Multi-byte flat-struct stores overwrite RANGES that can cover any cached + // (obj, offset) entry of the same object — e.g. `bx.p = s1` (stfld_sc_vt) + // rewrites every field of p, so a cached forward of bx.p.n.v goes stale. + case Op.stfld_sc_vt: case Op.stfld_vt_vt: case Op.stelem_vt: + cache.Clear(); + break; + + // stfld_sc_* only update the cache (handled above); no full clear needed. + + case Op.br: + case Op.brtrue_i4: case Op.brfalse_i4: + case Op.brtrue_o: case Op.brfalse_o: + case Op.blt_i4_nn: case Op.blt_i4_nk: + case Op.bgt_r4_nn: case Op.bgt_r4_nk: + case Op.beq_i4_nn: case Op.beq_i4_nk: + case Op.bne_i4_nn: case Op.bne_i4_nk: + case Op.for_i4_nk: + case Op.switch_i4: + case Op.push_cont: case Op.br_cont: + case Op.ret_void: case Op.ret_i4: case Op.ret_r4: case Op.ret_o: case Op.ret_vt: + case Op.throw_o: + // End-of-block: anything past here gets a fresh cache. + cache.Clear(); + break; + } + } + + if (deletedWords == 0) return; + + // Apply slotMap globally to all slot operands. + int Resolve(int s) { while (slotMap[s] != s) s = slotMap[s]; return s; } + + for (int i = 0; i < insnCount; i++) + { + if (deleted[i]) continue; + RenameSlots(ir, ips[i], ops[i], Resolve); + } + + // Compact + branch-target patch. + var deletedWord = new bool[n]; + for (int i = 0; i < insnCount; i++) + { + if (!deleted[i]) continue; + for (int k = 0; k < widths[i]; k++) deletedWord[ips[i] + k] = true; + } + var shift = new int[n + 1]; + int run = 0; + for (int oldIp = 0; oldIp <= n; oldIp++) + { + shift[oldIp] = run; + if (oldIp < n && deletedWord[oldIp]) run++; + } + + int newLen = n - deletedWords; + var newIr = new uint[newLen]; + var newToIl = new int[newLen]; + int dstIdx = 0; + for (int i = 0; i < insnCount; i++) + { + if (deleted[i]) continue; + int oldIp = ips[i]; + int w = widths[i]; + for (int k = 0; k < w; k++) + { + newIr[dstIdx + k] = ir[oldIp + k]; + newToIl[dstIdx + k] = irToIl[oldIp + k]; + } + PatchInsnBranchTargets(newIr, dstIdx, ops[i], shift, ir, oldIp); + dstIdx += w; + } + + ir = newIr; + irToIl = newToIl; + } + + // For each slot operand of `op` at `ip` in `ir`, apply `resolve` and write + // back. Mirrors AccumulateSlotUses' positions; keep both in sync. + static void RenameSlots(uint[] ir, int ip, Op op, Func resolve) + { + void RW(int wOff) + { + int s = (int)ir[ip + wOff]; + if (s < 0) return; // sentinel (-1 for void-call dst, no-receiver, etc.) + ir[ip + wOff] = (uint)resolve(s); + } + + if (Is4WordArithForCoalesce(op)) + { + RW(1); RW(2); + if (!IsNkForm(op)) RW(3); + return; + } + if (IsFusedCmpBranch(op)) + { + RW(1); + if (!IsFusedCmpBranchNk(op)) RW(2); + return; + } + if (op == Op.for_i4_nk) { RW(1); return; } + + switch (op) + { + case Op.nop: case Op.ret_void: case Op.br: + case Op.push_cont: case Op.br_cont: return; + + case Op.mov: case Op.box: case Op.mov_vt: case Op.box_vt: case Op.unbox_vt: + case Op.clone_sc: + case Op.ldlen: + case Op.neg_i4: case Op.neg_i4_n: case Op.neg_r4: case Op.neg_r4_n: + case Op.not_i4: case Op.not_i4_n: + case Op.conv_i4_r4: case Op.conv_r4_i4: + case Op.conv_i4_i1: case Op.conv_i4_u1: + case Op.conv_i4_i2: case Op.conv_i4_u2: + RW(1); RW(2); return; + + case Op.ldc_i4: case Op.ldc_r4: case Op.ldstr: + case Op.ldsfld_i4: case Op.ldsfld_r4: case Op.ldsfld_o: case Op.ldsfld_struct: + case Op.ldtoken: + case Op.ldnull: case Op.initobj: case Op.initobj_script: case Op.ensure_script: + RW(1); return; + + case Op.stsfld_i4: case Op.stsfld_r4: case Op.stsfld_o: case Op.stsfld_struct: + RW(2); return; + + case Op.ret_i4: case Op.ret_r4: case Op.ret_o: case Op.ret_vt: + case Op.throw_o: + RW(1); return; + + case Op.brtrue_i4: case Op.brfalse_i4: case Op.brtrue_o: case Op.brfalse_o: + RW(1); return; + + case Op.ldfld_i4: case Op.ldfld_r4: case Op.ldfld_o: + case Op.ldfld_struct: case Op.ldflda: + case Op.ldfld_vt_i4: case Op.ldfld_vt_r4: case Op.ldfld_vt_vt: + case Op.ldfld_vt_u1: case Op.ldfld_vt_i1: case Op.ldfld_vt_u2: case Op.ldfld_vt_i2: + case Op.ldfld_sc_i4: case Op.ldfld_sc_r4: case Op.ldfld_sc_o: case Op.ldfld_sc_vt: + RW(1); RW(2); return; + + case Op.stfld_i4: case Op.stfld_r4: case Op.stfld_o: case Op.stfld_struct: + case Op.stfld_vt_i4: case Op.stfld_vt_r4: case Op.stfld_vt_vt: + case Op.stfld_vt_b1: case Op.stfld_vt_b2: + case Op.stfld_sc_i4: case Op.stfld_sc_r4: case Op.stfld_sc_o: case Op.stfld_sc_vt: + RW(1); RW(3); return; + + case Op.ldelem_i4: case Op.ldelem_r4: case Op.ldelem_o: case Op.ldelem_struct: + case Op.ldelem_vt: + RW(1); RW(2); RW(3); return; + + case Op.stelem_i4: case Op.stelem_r4: case Op.stelem_o: case Op.stelem_struct: + case Op.stelem_vt: + RW(1); RW(2); RW(3); return; + + case Op.castclass: case Op.unbox_any: case Op.isinst: case Op.box_prim: + case Op.box_enum: + RW(1); RW(2); return; + + case Op.newarr: case Op.newarr_i4: case Op.newarr_r4: case Op.newarr_vt: + RW(1); RW(2); return; + + case Op.new_delegate: + RW(1); RW(3); return; // dst, receiver slot (word 2 is a tokIdx) + + case Op.call_script: + case Op.newobj_script: + case Op.newobj_host: + { + RW(1); + int argc = (int)ir[ip + 3]; + for (int k = 0; k < argc; k++) RW(4 + k); + return; + } + + case Op.call_host: + { + RW(1); RW(2); + int argc = (int)ir[ip + 4]; + for (int k = 0; k < argc; k++) RW(5 + k); + return; + } + + case Op.call_host_byref: + { + RW(1); RW(2); + int argc = (int)ir[ip + 4]; + for (int k = 0; k < argc; k++) RW(5 + k); + int wbBase = ip + 5 + argc; + int wbCount = (int)ir[wbBase]; + for (int k = 0; k < wbCount; k++) + { + int kind = (int)ir[wbBase + 1 + k * 4 + 1]; + // word offsets relative to ip: + int t1Off = wbBase + 1 + k * 4 + 2 - ip; + int t2Off = wbBase + 1 + k * 4 + 3 - ip; + if (kind == 0) { RW(t1Off); } + else if (kind == 1) { RW(t1Off); } + else { RW(t1Off); RW(t2Off); } + } + return; + } + + case Op.switch_i4: + RW(1); return; + } + } + + // --- Numeric for-loop super-instruction --- + // + // Detects the canonical Roslyn-emitted for-loop tail + // add_i4_nk slot[N], slot[N], 1 + // blt_i4_nk slot[N], K_limit, body_top + // plus the matching "test-at-bottom" loop entry + // ldc_i4 slot[N] = K_init + // br -> blt_ip + // and fuses the add+blt into one `for_i4_nk slot[N], K_limit, body_top` + // dispatch. Redirects the entry br from blt_ip to body_top so the first + // body iteration isn't skipped (the executor's increment-then-test + // would otherwise consume the first slot value). + // + // Safety: + // - Step is hardcoded to 1 (the add's K must be exactly 1). + // - K_init < K_limit must hold statically — without the entry test we + // can't guarantee zero-iter loops behave correctly. + // - The induction slot is single-write across the loop entry pattern + // (the ldc + the add). This rules out odd cases where the body + // re-initializes the counter. + // + // Not handled: + // - Reverse loops (`i--`). + // - Step != 1. + // - r4 induction (rare in idiomatic C#, accumulates error). + // - Slot-valued limit (`for (int i=0; i(n / 3); + var ops = new List(n / 3); + var widths = new List(n / 3); + int pos = 0; + while (pos < n) + { + var op = (Op)ir[pos]; + int w = OpWidthForCoalesce(op, ir, pos); + if (w <= 0) return; + ips.Add(pos); ops.Add(op); widths.Add(w); + pos += w; + } + int insnCount = ips.Count; + + // Map IP → instruction index for lookup. + var ipToIdx = new Dictionary(insnCount); + for (int i = 0; i < insnCount; i++) ipToIdx[ips[i]] = i; + + // Branch-target set: which IPs are jumped to by some branch? + var isBranchTarget = new bool[n + 1]; + for (int i = 0; i < insnCount; i++) + MarkInsnBranchTargets(ir, ips[i], ops[i], isBranchTarget); + + var deleted = new bool[insnCount]; + int deletedWords = 0; + + for (int i = 1; i < insnCount; i++) + { + if (deleted[i]) continue; + if (ops[i] != Op.blt_i4_nk) continue; + int bltIp = ips[i]; + int slotN = (int)ir[bltIp + 1]; + int kLimit = (int)ir[bltIp + 2]; + int bodyTop = (int)ir[bltIp + 3]; + if (bodyTop >= bltIp) continue; // must be a backward branch + if (!ipToIdx.ContainsKey(bodyTop)) continue; + + // Preceding instruction must be add_i4_nk slot[N], slot[N], 1. + int j = i - 1; + if (deleted[j] || ops[j] != Op.add_i4_nk) continue; + int addIp = ips[j]; + if ((int)ir[addIp + 1] != slotN) continue; // dst == N + if ((int)ir[addIp + 2] != slotN) continue; // src == N (in-place) + if ((int)ir[addIp + 3] != 1) continue; // step == 1 + + // Two cases: + // (a) Test-at-bottom loop: an entry `br -> bltIp` exists. We must + // redirect it to body_top so the for_i4_nk doesn't consume the + // first body iteration. Requires statically provable + // K_init < K_limit (otherwise we'd execute the body once when + // the original loop wouldn't have run at all). + // (b) Test-at-top / do-while loop: nothing branches to the blt. The + // loop is entered by fall-through and exited by fall-through past + // the blt. for_i4_nk has identical semantics to add+blt at the + // loop tail, so the fuse is unconditionally safe. + bool needRedirect = isBranchTarget[bltIp]; + if (needRedirect) + { + if (!ipToIdx.TryGetValue(bodyTop, out int topIdx)) continue; + if (topIdx < 2) continue; + int brIdx = topIdx - 1; + if (deleted[brIdx] || ops[brIdx] != Op.br) continue; + int brIp = ips[brIdx]; + if ((int)ir[brIp + 1] != bltIp) continue; // br must target the blt + + int initIdx = brIdx - 1; + if (initIdx < 0 || deleted[initIdx]) continue; + if (ops[initIdx] != Op.ldc_i4) continue; + int initIp = ips[initIdx]; + if ((int)ir[initIp + 1] != slotN) continue; + int kInit = (int)ir[initIp + 2]; + if (kInit >= kLimit) continue; // entry-check guard + + // Redirect entry br to body_top. + ir[brIp + 1] = (uint)bodyTop; + } + + // Apply: rewrite add → for_i4_nk in place; mark blt for deletion. + ir[addIp + 0] = (uint)Op.for_i4_nk; + ir[addIp + 1] = (uint)slotN; + ir[addIp + 2] = (uint)kLimit; + ir[addIp + 3] = (uint)bodyTop; + ops[j] = Op.for_i4_nk; + + deleted[i] = true; + deletedWords += widths[i]; + } + + if (deletedWords == 0) return; + + var deletedWord = new bool[n]; + for (int i = 0; i < insnCount; i++) + { + if (!deleted[i]) continue; + for (int k = 0; k < widths[i]; k++) deletedWord[ips[i] + k] = true; + } + var shift = new int[n + 1]; + int run = 0; + for (int oldIp = 0; oldIp <= n; oldIp++) + { + shift[oldIp] = run; + if (oldIp < n && deletedWord[oldIp]) run++; + } + + int newLen = n - deletedWords; + var newIr = new uint[newLen]; + var newToIl = new int[newLen]; + int dstIdx = 0; + for (int i = 0; i < insnCount; i++) + { + if (deleted[i]) continue; + int oldIp = ips[i]; + int w = widths[i]; + for (int k = 0; k < w; k++) + { + newIr[dstIdx + k] = ir[oldIp + k]; + newToIl[dstIdx + k] = irToIl[oldIp + k]; + } + PatchInsnBranchTargets(newIr, dstIdx, ops[i], shift, ir, oldIp); + dstIdx += w; + } + + ir = newIr; + irToIl = newToIl; + } + + // --- Loop-invariant constant hoisting --- + // + // A `ldc_i4 / ldc_r4 / ldstr` inside a loop re-executes every iteration even though it + // always produces the same value into the same slot. Profiling showed constant reloads at + // 10–38% of all dispatches on loop-heavy bodies (`i & 255`, `Translate(0.01f, 0f, -0.01f)`). + // This pass moves qualifying ldcs into a prologue emitted once at IR entry. + // + // A candidate ldc must satisfy: + // - writes[dst] == 1: this ldc is the slot's only writer in the whole method. C# definite + // assignment then guarantees the write dominates every read, so "execute once up front" + // observes the same values (re-executions were idempotent). + // - dst >= argCount: arg slots are populated by the CALLER before Run enters the IR; + // a prologue write would clobber the incoming argument. + // - the ldc sits inside a loop body — between a backward branch and its target. Hoisting + // straight-line or cold-branch constants would ADD a dispatch per call, not remove one. + // + // Branch targets all shift by the prologue length; the shared shift-table mechanism handles + // that with negative entries (newTarget = old - shift[old]). + static void HoistLoopConsts(ref uint[] ir, ref int[] irToIl, SType[] slotTypes, int argCount) + { + int n = ir.Length; + if (n == 0) return; + + var ips = new List(n / 3); + var ops = new List(n / 3); + var widths = new List(n / 3); + int pos = 0; + while (pos < n) + { + var op = (Op)ir[pos]; + int w = OpWidthForCoalesce(op, ir, pos); + if (w <= 0) return; + ips.Add(pos); ops.Add(op); widths.Add(w); + pos += w; + } + int insnCount = ips.Count; + + int slotCount = slotTypes.Length; + var reads = new int[slotCount]; + var writes = new int[slotCount]; + for (int i = 0; i < insnCount; i++) + AccumulateSlotUses(ir, ips[i], ops[i], widths[i], reads, writes, slotCount); + + // Mark loop-body words: for every backward branch at ip with target t <= ip, the + // whole [t, ip] range is (over-approximately) a loop body. Difference array over words. + var loopDelta = new int[n + 2]; + void MarkLoop(int from, int to) { if (to <= from) { loopDelta[to]++; loopDelta[from + 1]--; } } + for (int i = 0; i < insnCount; i++) + { + int ip = ips[i]; + switch (ops[i]) + { + case Op.br: case Op.push_cont: MarkLoop(ip, (int)ir[ip + 1]); break; + case Op.brtrue_i4: case Op.brfalse_i4: + case Op.brtrue_o: case Op.brfalse_o: MarkLoop(ip, (int)ir[ip + 2]); break; + case Op.blt_i4_nn: case Op.blt_i4_nk: + case Op.bgt_r4_nn: case Op.bgt_r4_nk: + case Op.beq_i4_nn: case Op.beq_i4_nk: + case Op.bne_i4_nn: case Op.bne_i4_nk: + case Op.for_i4_nk: MarkLoop(ip, (int)ir[ip + 3]); break; + case Op.switch_i4: + { + int cnt = (int)ir[ip + 2]; + MarkLoop(ip, (int)ir[ip + 3]); + for (int k = 0; k < cnt; k++) MarkLoop(ip, (int)ir[ip + 4 + k]); + break; + } + } + } + var inLoop = new bool[n]; + int depth = 0; + for (int w2 = 0; w2 < n; w2++) { depth += loopDelta[w2]; inLoop[w2] = depth > 0; } + + var hoisted = new List(); // instruction indexes to move + var deleted = new bool[insnCount]; + int hoistWords = 0; + for (int i = 0; i < insnCount; i++) + { + var op = ops[i]; + if (op != Op.ldc_i4 && op != Op.ldc_r4 && op != Op.ldstr) continue; + int ip = ips[i]; + if (!inLoop[ip]) continue; + int dst = (int)ir[ip + 1]; + if (dst < argCount) continue; + if ((uint)dst >= (uint)slotCount) continue; + if (writes[dst] != 1 || reads[dst] == 0) continue; + hoisted.Add(i); + deleted[i] = true; + hoistWords += widths[i]; + } + if (hoisted.Count == 0) return; + + // shift[t] = (deleted words strictly before t) - prologueLen, so + // newTarget = t - shift[t] lands on the surviving instruction, offset by the prologue. + var deletedWord = new bool[n]; + foreach (var i in hoisted) + for (int k = 0; k < widths[i]; k++) deletedWord[ips[i] + k] = true; + var shift = new int[n + 1]; + int run = 0; + for (int oldIp = 0; oldIp <= n; oldIp++) + { + shift[oldIp] = run - hoistWords; + if (oldIp < n && deletedWord[oldIp]) run++; + } + + int newLen = n; // deleted words re-emitted verbatim in the prologue + var newIr = new uint[newLen]; + var newToIl = new int[newLen]; + int dstIdx = 0; + foreach (var i in hoisted) + { + int oldIp = ips[i]; + for (int k = 0; k < widths[i]; k++) + { + newIr[dstIdx + k] = ir[oldIp + k]; + newToIl[dstIdx + k] = irToIl[oldIp + k]; + } + dstIdx += widths[i]; + } + for (int i = 0; i < insnCount; i++) + { + if (deleted[i]) continue; + int oldIp = ips[i]; + int w = widths[i]; + for (int k = 0; k < w; k++) + { + newIr[dstIdx + k] = ir[oldIp + k]; + newToIl[dstIdx + k] = irToIl[oldIp + k]; + } + PatchInsnBranchTargets(newIr, dstIdx, ops[i], shift, ir, oldIp); + dstIdx += w; + } + + ir = newIr; + irToIl = newToIl; + } + + // --- Fused compare-and-branch --- + // + // Detects `compare_X_form dst, ...; brtrue/brfalse dst, target` where + // dst is single-use (the brtrue/brfalse is its only reader) and folds + // into one fused `bX_form ...args, target`. Runs AFTER CoalesceDestMovs + // so that the compare's dst is already the local slot the branch + // reads — pattern detection becomes a clean two-instruction window. + // + // Mappings (only ones with bench-corpus evidence): + // clt_i4_nn + brtrue → blt_i4_nn ceq_i4_nn + brtrue → beq_i4_nn + // clt_i4_nk + brtrue → blt_i4_nk ceq_i4_nk + brtrue → beq_i4_nk + // cgt_r4_nn + brtrue → bgt_r4_nn ceq_i4_nn + brfalse → bne_i4_nn + // cgt_r4_nk + brtrue → bgt_r4_nk ceq_i4_nk + brfalse → bne_i4_nk + // + // Other polarity combinations (clt+brfalse, cgt+brfalse, etc.) are + // left as two ops — adding "bge"/"ble" etc. would double the opcode + // count for patterns we don't have. Add on demand. + static void FoldCompareBranch(ref uint[] ir, ref int[] irToIl, SType[] slotTypes) + { + int n = ir.Length; + if (n == 0) return; + + var ips = new List(n / 3); + var ops = new List(n / 3); + var widths = new List(n / 3); + int pos = 0; + while (pos < n) + { + var op = (Op)ir[pos]; + int w = OpWidthForCoalesce(op, ir, pos); + if (w <= 0) return; + ips.Add(pos); ops.Add(op); widths.Add(w); + pos += w; + } + int insnCount = ips.Count; + + int slotCount = slotTypes.Length; + var reads = new int[slotCount]; + var writes = new int[slotCount]; + for (int i = 0; i < insnCount; i++) + AccumulateSlotUses(ir, ips[i], ops[i], widths[i], reads, writes, slotCount); + + var isBranchTarget = new bool[n + 1]; + for (int i = 0; i < insnCount; i++) + MarkInsnBranchTargets(ir, ips[i], ops[i], isBranchTarget); + + var deleted = new bool[insnCount]; + int deletedWords = 0; + for (int i = 0; i < insnCount - 1; i++) + { + if (deleted[i]) continue; + int cmpIp = ips[i]; + if (widths[i] != 4) continue; + int dstSlot = (int)ir[cmpIp + 1]; + if ((uint)dstSlot >= (uint)slotCount) continue; // -1 sentinel (e.g. zero-arg void call_script) + if (writes[dstSlot] != 1 || reads[dstSlot] != 1) continue; + + int j = i + 1; + if (j >= insnCount || deleted[j]) continue; + var brOp = ops[j]; + if (brOp != Op.brtrue_i4 && brOp != Op.brfalse_i4) continue; + int brIp = ips[j]; + if (isBranchTarget[brIp]) continue; + if ((int)ir[brIp + 1] != dstSlot) continue; + + bool brIfTrue = (brOp == Op.brtrue_i4); + if (!TryFoldCompareBranch(ops[i], brIfTrue, out Op fusedOp)) continue; + + uint target = ir[brIp + 2]; + + // Rewrite cmp in place: [op, s1, s2_or_k, target_ip] + ir[cmpIp] = (uint)fusedOp; + ir[cmpIp + 1] = ir[cmpIp + 2]; // slide src1 from word 2 → word 1 + ir[cmpIp + 2] = ir[cmpIp + 3]; // slide src2/k from word 3 → word 2 + ir[cmpIp + 3] = target; // target at word 3 + + // Update cached op so PatchInsnBranchTargets sees the new opcode and + // applies the shift to word 3 (not the original cmp's word 3, which + // was an operand and shouldn't be shifted). + ops[i] = fusedOp; + + deleted[j] = true; + deletedWords += widths[j]; + + reads[dstSlot] = 0; writes[dstSlot] = 0; + } + + if (deletedWords == 0) return; + + // Compact + branch-target patch. + var deletedWord = new bool[n]; + for (int i = 0; i < insnCount; i++) + { + if (!deleted[i]) continue; + for (int k = 0; k < widths[i]; k++) deletedWord[ips[i] + k] = true; + } + var shift = new int[n + 1]; + int run = 0; + for (int oldIp = 0; oldIp <= n; oldIp++) + { + shift[oldIp] = run; + if (oldIp < n && deletedWord[oldIp]) run++; + } + + int newLen = n - deletedWords; + var newIr = new uint[newLen]; + var newToIl = new int[newLen]; + int dstIdx = 0; + for (int i = 0; i < insnCount; i++) + { + if (deleted[i]) continue; + int oldIp = ips[i]; + int w = widths[i]; + for (int k = 0; k < w; k++) + { + newIr[dstIdx + k] = ir[oldIp + k]; + newToIl[dstIdx + k] = irToIl[oldIp + k]; + } + PatchInsnBranchTargets(newIr, dstIdx, ops[i], shift, ir, oldIp); + dstIdx += w; + } + + ir = newIr; + irToIl = newToIl; + } + + // True when the op writes a frame slot at ir[ip+1] (its dst). False for control flow, stores + // (which write memory, not a frame slot), and returns. Used by ForwardRedundantLoads to know + // which cached slots a reassignment invalidates. Calls/newobj also write a dst but clear the + // whole cache separately, so treating them as writers here is harmless. + static bool WritesFrameDstAt1(Op op) => op switch + { + Op.nop or Op.br + or Op.brtrue_i4 or Op.brfalse_i4 or Op.brtrue_o or Op.brfalse_o + or Op.ret_void or Op.ret_i4 or Op.ret_r4 or Op.ret_o or Op.throw_o + or Op.stfld_i4 or Op.stfld_r4 or Op.stfld_o or Op.stfld_struct + or Op.stfld_sc_i4 or Op.stfld_sc_r4 or Op.stfld_sc_o or Op.stfld_sc_vt + or Op.stfld_vt_i4 or Op.stfld_vt_r4 or Op.stfld_vt_b1 or Op.stfld_vt_b2 + or Op.stelem_i4 or Op.stelem_r4 or Op.stelem_o or Op.stelem_struct + or Op.stsfld_i4 or Op.stsfld_r4 or Op.stsfld_o or Op.stsfld_struct + or Op.switch_i4 + or Op.blt_i4_nn or Op.blt_i4_nk or Op.bgt_r4_nn or Op.bgt_r4_nk + or Op.beq_i4_nn or Op.beq_i4_nk or Op.bne_i4_nn or Op.bne_i4_nk + or Op.push_cont or Op.br_cont => false, + _ => true, + }; + + static bool TryFoldCompareBranch(Op cmpOp, bool brIfTrue, out Op fused) + { + fused = default; + switch (cmpOp) + { + case Op.clt_i4_nn: if (brIfTrue) { fused = Op.blt_i4_nn; return true; } return false; + case Op.clt_i4_nk: if (brIfTrue) { fused = Op.blt_i4_nk; return true; } return false; + case Op.cgt_r4_nn: if (brIfTrue) { fused = Op.bgt_r4_nn; return true; } return false; + case Op.cgt_r4_nk: if (brIfTrue) { fused = Op.bgt_r4_nk; return true; } return false; + case Op.ceq_i4_nn: fused = brIfTrue ? Op.beq_i4_nn : Op.bne_i4_nn; return true; + case Op.ceq_i4_nk: fused = brIfTrue ? Op.beq_i4_nk : Op.bne_i4_nk; return true; + default: return false; + } + } + + // Helpers shared by all three peephole passes. + static void MarkInsnBranchTargets(uint[] ir, int ip, Op op, bool[] isBranchTarget) + { + switch (op) + { + case Op.br: + case Op.push_cont: + MarkTarget(isBranchTarget, ir[ip + 1]); break; + case Op.brtrue_i4: case Op.brfalse_i4: + case Op.brtrue_o: case Op.brfalse_o: + MarkTarget(isBranchTarget, ir[ip + 2]); break; + case Op.blt_i4_nn: case Op.blt_i4_nk: + case Op.bgt_r4_nn: case Op.bgt_r4_nk: + case Op.beq_i4_nn: case Op.beq_i4_nk: + case Op.bne_i4_nn: case Op.bne_i4_nk: + case Op.for_i4_nk: + MarkTarget(isBranchTarget, ir[ip + 3]); break; + case Op.switch_i4: + { + int cnt = (int)ir[ip + 2]; + MarkTarget(isBranchTarget, ir[ip + 3]); + for (int k = 0; k < cnt; k++) + MarkTarget(isBranchTarget, ir[ip + 4 + k]); + break; + } + } + } + + static void PatchInsnBranchTargets(uint[] newIr, int dstIdx, Op op, int[] shift, + uint[] oldIr, int oldIp) + { + switch (op) + { + case Op.br: + case Op.push_cont: + newIr[dstIdx + 1] = (uint)((int)oldIr[oldIp + 1] - shift[(int)oldIr[oldIp + 1]]); + break; + case Op.brtrue_i4: case Op.brfalse_i4: + case Op.brtrue_o: case Op.brfalse_o: + case Op.brtrue_i8: case Op.brfalse_i8: + newIr[dstIdx + 2] = (uint)((int)oldIr[oldIp + 2] - shift[(int)oldIr[oldIp + 2]]); + break; + case Op.blt_i4_nn: case Op.blt_i4_nk: + case Op.bgt_r4_nn: case Op.bgt_r4_nk: + case Op.beq_i4_nn: case Op.beq_i4_nk: + case Op.bne_i4_nn: case Op.bne_i4_nk: + case Op.for_i4_nk: + newIr[dstIdx + 3] = (uint)((int)oldIr[oldIp + 3] - shift[(int)oldIr[oldIp + 3]]); + break; + case Op.switch_i4: + { + int cnt = (int)oldIr[oldIp + 2]; + int defT = (int)oldIr[oldIp + 3]; + newIr[dstIdx + 3] = (uint)(defT - shift[defT]); + for (int k = 0; k < cnt; k++) + { + int t = (int)oldIr[oldIp + 4 + k]; + newIr[dstIdx + 4 + k] = (uint)(t - shift[t]); + } + break; + } + } + } + + // --- Dest-coalescing peephole --- + // + // Eliminates `mov dst=X, src=tmp` where `tmp` is a single-use temp produced by + // the immediately-preceding instruction. Rewrites that instruction's dst to X + // and deletes the mov. Run after branch-target patching so target IPs are + // word-indexed; we re-patch them after compaction. + // + // Safety: + // - tmp has exactly 1 read (the candidate mov) and 1 write (prev op) globally. + // - slotTypes[tmp] == slotTypes[X], and neither is Vt — guarantees the prev + // op's frame write (numFrame vs refFrame, byte vs ref) is valid for X. + // - The mov's IP is not a branch target. + // - Prev op is in a conservative whitelist (IsRetargetable) of ops that write + // their dst at words[1] with no other side effects on dst. + static void CoalesceDestMovs(ref uint[] ir, ref int[] irToIl, SType[] slotTypes) + { + int n = ir.Length; + if (n == 0) return; + + // Walk IR once: record (ip, op, width) per instruction. Bail out if any + // op has unknown width — leaves IR untouched. + var ips = new List(n / 3); + var ops = new List(n / 3); + var widths = new List(n / 3); + int pos = 0; + while (pos < n) + { + var op = (Op)ir[pos]; + int w = OpWidthForCoalesce(op, ir, pos); + if (w <= 0) return; + ips.Add(pos); ops.Add(op); widths.Add(w); + pos += w; + } + int insnCount = ips.Count; + + // Per-slot read/write counts. Conservative: any value in a "slot position" + // is counted, even if -1 (sentinel for void/static); -1 just bumps a phantom + // entry that nothing else references. + int slotCount = slotTypes.Length; + var reads = new int[slotCount]; + var writes = new int[slotCount]; + for (int i = 0; i < insnCount; i++) + AccumulateSlotUses(ir, ips[i], ops[i], widths[i], reads, writes, slotCount); + + // Set of branch-target word IPs. Branches target alive-instruction IPs; we + // refuse to delete a mov that anything jumps to. + var isBranchTarget = new bool[n + 1]; + for (int i = 0; i < insnCount; i++) + MarkInsnBranchTargets(ir, ips[i], ops[i], isBranchTarget); + + // Identify mov instructions to coalesce. + var deleted = new bool[insnCount]; + int deletedWords = 0; + for (int i = 1; i < insnCount; i++) + { + if (ops[i] != Op.mov) continue; + int movIp = ips[i]; + if (isBranchTarget[movIp]) continue; + + int dstSlot = (int)ir[movIp + 1]; + int srcSlot = (int)ir[movIp + 2]; + if ((uint)dstSlot >= (uint)slotCount || (uint)srcSlot >= (uint)slotCount) continue; + + var stSrc = slotTypes[srcSlot]; + var stDst = slotTypes[dstSlot]; + if (stSrc == SType.Vt || stDst == SType.Vt) continue; + if (stSrc != stDst) continue; + + if (writes[srcSlot] != 1 || reads[srcSlot] != 1) continue; + + // Prev instruction must define srcSlot in retargetable position. + var prevOp = ops[i - 1]; + if (deleted[i - 1]) continue; + if (!IsRetargetable(prevOp)) continue; + int prevDstWord = ips[i - 1] + 1; + if ((int)ir[prevDstWord] != srcSlot) continue; + + // Apply rewrite + mark deletion. + ir[prevDstWord] = (uint)dstSlot; + deleted[i] = true; + deletedWords += widths[i]; + + // Update counts so a chained mov (X <- Y where Y was just rewritten + // away) sees the new state. srcSlot loses its lone read+write; dstSlot + // gains one of each (the rewritten prev op now reads/writes dst). + reads[srcSlot] = 0; writes[srcSlot] = 0; + writes[dstSlot]++; + } + + if (deletedWords == 0) return; + + // Build old-IP → new-IP shift table for branch-target patching. + // shift[oldIp] = total deleted words at positions strictly less than oldIp. + var deletedWord = new bool[n]; + for (int i = 0; i < insnCount; i++) + { + if (!deleted[i]) continue; + for (int k = 0; k < widths[i]; k++) deletedWord[ips[i] + k] = true; + } + var shift = new int[n + 1]; + int run = 0; + for (int oldIp = 0; oldIp <= n; oldIp++) + { + shift[oldIp] = run; + if (oldIp < n && deletedWord[oldIp]) run++; + } + + // Compact: copy alive instructions, patching branch targets via shift. + int newLen = n - deletedWords; + var newIr = new uint[newLen]; + var newToIl = new int[newLen]; + int dstIdx = 0; + for (int i = 0; i < insnCount; i++) + { + if (deleted[i]) continue; + int oldIp = ips[i]; + int w = widths[i]; + for (int k = 0; k < w; k++) + { + newIr[dstIdx + k] = ir[oldIp + k]; + newToIl[dstIdx + k] = irToIl[oldIp + k]; + } + switch (ops[i]) + { + case Op.br: + case Op.push_cont: + newIr[dstIdx + 1] = (uint)((int)ir[oldIp + 1] - shift[(int)ir[oldIp + 1]]); + break; + case Op.brtrue_i4: case Op.brfalse_i4: + case Op.brtrue_o: case Op.brfalse_o: + newIr[dstIdx + 2] = (uint)((int)ir[oldIp + 2] - shift[(int)ir[oldIp + 2]]); + break; + case Op.switch_i4: + { + int cnt = (int)ir[oldIp + 2]; + int defT = (int)ir[oldIp + 3]; + newIr[dstIdx + 3] = (uint)(defT - shift[defT]); + for (int k = 0; k < cnt; k++) + { + int t = (int)ir[oldIp + 4 + k]; + newIr[dstIdx + 4 + k] = (uint)(t - shift[t]); + } + break; + } + } + dstIdx += w; + } + + ir = newIr; + irToIl = newToIl; + } + + static void MarkTarget(bool[] arr, uint target) + { + int t = (int)target; + if (t >= 0 && t < arr.Length) arr[t] = true; + } + + static bool IsNkForm(Op op) => op switch + { + Op.add_i4_nk or Op.add_r4_nk or Op.sub_i4_nk or Op.sub_r4_nk + or Op.mul_r4_nk + or Op.clt_i4_nk or Op.clt_r4_nk or Op.cgt_i4_nk or Op.cgt_r4_nk + or Op.ceq_i4_nk + or Op.mul_i4_nk or Op.div_i4_nk or Op.rem_i4_nk + or Op.and_i4_nk or Op.or_i4_nk or Op.xor_i4_nk + or Op.shl_i4_nk or Op.shr_i4_nk or Op.shr_un_i4_nk + or Op.div_r4_nk or Op.ceq_r4_nk => true, + _ => false, + }; + + static bool IsFusedCmpBranch(Op op) => op switch + { + Op.blt_i4_nn or Op.blt_i4_nk + or Op.bgt_r4_nn or Op.bgt_r4_nk + or Op.beq_i4_nn or Op.beq_i4_nk + or Op.bne_i4_nn or Op.bne_i4_nk => true, + _ => false, + }; + + // True when the second operand at word 2 is an inline immediate, not a slot. + static bool IsFusedCmpBranchNk(Op op) => op switch + { + Op.blt_i4_nk or Op.bgt_r4_nk or Op.beq_i4_nk or Op.bne_i4_nk => true, + _ => false, + }; + + // Whitelist of ops whose only effect (on the frame) is writing words[1] as a slot index. + // call_host_byref and Vt-dst ops are excluded conservatively (byref write-back touches + // slots beyond dst; Vt dsts span multiple numeric words — the coalesce pass's "types + // equal, neither Vt" check would reject them anyway). + // Calls and newobjs ARE retargetable: their dst is written exactly once, type-routed by + // slotT (numeric or ref frame), after all argument reads — the profile showed 12-25% of + // dispatches were `call tmp; mov local <- tmp` pairs this unlocks. + static bool IsRetargetable(Op op) + { + if (Is4WordArithForCoalesce(op)) return true; + return op switch + { + Op.call_host or Op.call_script or Op.newobj_host or Op.newobj_script + or Op.new_delegate => true, + Op.ldc_i4 or Op.ldc_r4 or Op.ldnull or Op.ldstr => true, + Op.neg_i4 or Op.neg_i4_n or Op.neg_r4 or Op.neg_r4_n + or Op.not_i4 or Op.not_i4_n => true, + Op.conv_i4_r4 or Op.conv_r4_i4 or Op.conv_i4_i1 or Op.conv_i4_u1 + or Op.conv_i4_i2 or Op.conv_i4_u2 => true, + Op.ldfld_i4 or Op.ldfld_r4 or Op.ldfld_o or Op.ldflda => true, + Op.ldfld_sc_i4 or Op.ldfld_sc_r4 or Op.ldfld_sc_o or Op.ldfld_sc_vt => true, + Op.ldsfld_i4 or Op.ldsfld_r4 or Op.ldsfld_o => true, + Op.ldlen => true, + Op.ldelem_i4 or Op.ldelem_r4 or Op.ldelem_o => true, + Op.ldtoken => true, + Op.castclass or Op.unbox_any or Op.isinst => true, + Op.box or Op.box_prim or Op.box_enum => true, + Op.ldfld_vt_i4 or Op.ldfld_vt_r4 => true, // dst is numeric, not Vt + Op.ldfld_vt_u1 or Op.ldfld_vt_i1 or Op.ldfld_vt_u2 or Op.ldfld_vt_i2 => true, + Op.box_vt => true, // dst is O + _ => false, + }; + } + + // Mirrors the executor's per-op ip-advance. Returns -1 for ops we don't + // recognise (causes the pass to bail out, leaving IR untouched). + internal static int OpWidthForCoalesce(Op op, uint[] ir, int ip) + { + if (Is4WordArithForCoalesce(op)) return 4; + if (IsFusedCmpBranch(op)) return 4; + if (op == Op.for_i4_nk) return 4; + return op switch + { + Op.nop or Op.ret_void or Op.br_cont => 1, + Op.br or Op.push_cont or Op.ret_i4 or Op.ret_r4 or Op.ret_o or Op.ret_vt or Op.throw_o or Op.ldnull or Op.initobj + or Op.ret_i8 or Op.ret_r8 => 2, + + // 64-bit family — 4-word binops/constants, 3-word convs/unaries/branches. These + // never reach the optimizer passes (wide frames skip them) but the blob relocator + // widths must be exact. + Op.ldc_i8 or Op.ldc_r8 + or Op.add_i8 or Op.sub_i8 or Op.mul_i8 or Op.div_i8 or Op.rem_i8 + or Op.div_un_i8 or Op.rem_un_i8 + or Op.and_i8 or Op.or_i8 or Op.xor_i8 + or Op.shl_i8 or Op.shr_i8 or Op.shr_un_i8 + or Op.add_r8 or Op.sub_r8 or Op.mul_r8 or Op.div_r8 or Op.rem_r8 + or Op.ceq_i8 or Op.cgt_i8 or Op.clt_i8 or Op.cgt_un_i8 or Op.clt_un_i8 + or Op.ceq_r8 or Op.cgt_r8 or Op.clt_r8 or Op.cgt_un_r8 or Op.clt_un_r8 => 4, + + Op.neg_i8 or Op.not_i8 or Op.neg_r8 + or Op.conv_i8_i4 or Op.conv_i8_u4 or Op.conv_i4_i8 + or Op.conv_i8_r4 or Op.conv_r4_i8 or Op.conv_i8_r8 or Op.conv_r8_i8 + or Op.conv_r8_r4 or Op.conv_r4_r8 or Op.conv_r8_i4 or Op.conv_i4_r8 + or Op.conv_r8_u8 + or Op.brtrue_i8 or Op.brfalse_i8 => 3, + + Op.mov or Op.box or Op.mov_vt or Op.box_vt or Op.unbox_vt or Op.clone_sc + or Op.ldlen or Op.neg_i4 or Op.neg_i4_n or Op.neg_r4 or Op.neg_r4_n + or Op.not_i4 or Op.not_i4_n + or Op.conv_i4_r4 or Op.conv_r4_i4 or Op.conv_i4_i1 or Op.conv_i4_u1 + or Op.conv_i4_i2 or Op.conv_i4_u2 + or Op.initobj_script or Op.ensure_script or Op.ldtoken + or Op.ldc_i4 or Op.ldc_r4 or Op.ldstr + or Op.ldsfld_i4 or Op.ldsfld_r4 or Op.ldsfld_o or Op.ldsfld_struct + or Op.stsfld_i4 or Op.stsfld_r4 or Op.stsfld_o or Op.stsfld_struct + or Op.brtrue_i4 or Op.brfalse_i4 or Op.brtrue_o or Op.brfalse_o => 3, + + Op.ldfld_i4 or Op.ldfld_r4 or Op.ldfld_o or Op.ldfld_struct or Op.ldflda + or Op.stfld_i4 or Op.stfld_r4 or Op.stfld_o or Op.stfld_struct + or Op.ldelem_i4 or Op.ldelem_r4 or Op.ldelem_o or Op.ldelem_struct or Op.ldelem_vt + or Op.stelem_i4 or Op.stelem_r4 or Op.stelem_o or Op.stelem_struct or Op.stelem_vt + or Op.ldfld_vt_i4 or Op.ldfld_vt_r4 or Op.stfld_vt_i4 or Op.stfld_vt_r4 + or Op.ldfld_vt_u1 or Op.ldfld_vt_i1 or Op.ldfld_vt_u2 or Op.ldfld_vt_i2 + or Op.stfld_vt_b1 or Op.stfld_vt_b2 + or Op.ldfld_vt_vt or Op.stfld_vt_vt + or Op.ldfld_sc_i4 or Op.ldfld_sc_r4 or Op.ldfld_sc_o or Op.ldfld_sc_vt + or Op.stfld_sc_i4 or Op.stfld_sc_r4 or Op.stfld_sc_o or Op.stfld_sc_vt + or Op.castclass or Op.unbox_any or Op.isinst or Op.box_prim or Op.box_enum + or Op.new_delegate => 4, + + Op.newarr or Op.newarr_i4 or Op.newarr_r4 or Op.newarr_vt => 5, + + Op.call_script or Op.newobj_script or Op.newobj_host + => ip + 3 < ir.Length ? 4 + (int)ir[ip + 3] : -1, + Op.call_host + => ip + 4 < ir.Length ? 5 + (int)ir[ip + 4] : -1, + Op.call_host_byref => CallHostByrefWidthForCoalesce(ir, ip), + Op.switch_i4 => ip + 2 < ir.Length ? 4 + (int)ir[ip + 2] : -1, + + _ => -1, + }; + } + + static bool Is4WordArithForCoalesce(Op op) => op switch + { + Op.add_i4 or Op.add_i4_nn or Op.sub_i4 or Op.sub_i4_nn + or Op.mul_i4 or Op.mul_i4_nn or Op.div_i4 or Op.div_i4_nn + or Op.rem_i4 or Op.rem_i4_nn + or Op.add_r4 or Op.add_r4_nn or Op.sub_r4 or Op.sub_r4_nn + or Op.mul_r4 or Op.mul_r4_nn or Op.div_r4 or Op.div_r4_nn + or Op.rem_r4 or Op.rem_r4_nn + or Op.and_i4 or Op.and_i4_nn or Op.or_i4 or Op.or_i4_nn + or Op.xor_i4 or Op.xor_i4_nn + or Op.shl_i4 or Op.shl_i4_nn or Op.shr_i4 or Op.shr_i4_nn + or Op.shr_un_i4 or Op.shr_un_i4_nn + or Op.div_un_i4 or Op.div_un_i4_nn or Op.rem_un_i4 or Op.rem_un_i4_nn + or Op.ceq_i4 or Op.ceq_i4_nn or Op.cgt_i4 or Op.cgt_i4_nn + or Op.clt_i4 or Op.clt_i4_nn or Op.cgt_un_i4 or Op.cgt_un_i4_nn + or Op.clt_un_i4 or Op.clt_un_i4_nn + or Op.ceq_r4 or Op.ceq_r4_nn or Op.cgt_r4 or Op.cgt_r4_nn + or Op.clt_r4 or Op.clt_r4_nn or Op.cgt_un_r4 or Op.clt_un_r4 + or Op.ceq_o or Op.cgt_un_o + // _nk forms also encode as [op, dst, src, k] — 4 words. dst at words[1]. + or Op.add_i4_nk or Op.add_r4_nk or Op.sub_i4_nk or Op.sub_r4_nk + or Op.mul_r4_nk + or Op.clt_i4_nk or Op.clt_r4_nk or Op.cgt_i4_nk or Op.cgt_r4_nk + or Op.ceq_i4_nk + or Op.mul_i4_nk or Op.div_i4_nk or Op.rem_i4_nk + or Op.and_i4_nk or Op.or_i4_nk or Op.xor_i4_nk + or Op.shl_i4_nk or Op.shr_i4_nk or Op.shr_un_i4_nk + or Op.div_r4_nk or Op.ceq_r4_nk => true, + _ => false, + }; + + static int CallHostByrefWidthForCoalesce(uint[] ir, int ip) + { + if (ip + 4 >= ir.Length) return -1; + int argc = (int)ir[ip + 4]; + int wbBase = ip + 5 + argc; + if (wbBase >= ir.Length) return -1; + int wbCount = (int)ir[wbBase]; + return (wbBase + 1 + wbCount * 4) - ip; + } + + // Conservative slot read/write accumulation. Counts every value at a known + // slot position. Tokens, immediates, and IP targets are skipped. + static void AccumulateSlotUses(uint[] ir, int ip, Op op, int width, + int[] reads, int[] writes, int slotCount) + { + void R(int s) { if ((uint)s < (uint)slotCount) reads[s]++; } + void W(int s) { if ((uint)s < (uint)slotCount) writes[s]++; } + + if (Is4WordArithForCoalesce(op)) + { + W((int)ir[ip + 1]); R((int)ir[ip + 2]); + // _nk forms have an immediate at word 3; everything else has a 2nd slot. + if (!IsNkForm(op)) R((int)ir[ip + 3]); + return; + } + if (IsFusedCmpBranch(op)) + { + R((int)ir[ip + 1]); + if (!IsFusedCmpBranchNk(op)) R((int)ir[ip + 2]); + // word 3 is target_ip, not a slot + return; + } + if (op == Op.for_i4_nk) + { + // induction slot is read AND written; words 2 and 3 are limit + target. + int s = (int)ir[ip + 1]; + R(s); W(s); + return; + } + switch (op) + { + case Op.nop: case Op.ret_void: case Op.br: + case Op.push_cont: case Op.br_cont: return; + + case Op.mov: case Op.box: case Op.mov_vt: case Op.box_vt: case Op.unbox_vt: + case Op.clone_sc: + case Op.ldlen: + case Op.neg_i4: case Op.neg_i4_n: case Op.neg_r4: case Op.neg_r4_n: + case Op.not_i4: case Op.not_i4_n: + case Op.conv_i4_r4: case Op.conv_r4_i4: + case Op.conv_i4_i1: case Op.conv_i4_u1: + case Op.conv_i4_i2: case Op.conv_i4_u2: + W((int)ir[ip + 1]); R((int)ir[ip + 2]); return; + + case Op.ldc_i4: case Op.ldc_r4: case Op.ldstr: + case Op.ldsfld_i4: case Op.ldsfld_r4: case Op.ldsfld_o: case Op.ldsfld_struct: + case Op.ldtoken: + case Op.ldnull: case Op.initobj: case Op.initobj_script: case Op.ensure_script: + W((int)ir[ip + 1]); return; + + case Op.stsfld_i4: case Op.stsfld_r4: case Op.stsfld_o: case Op.stsfld_struct: + R((int)ir[ip + 2]); return; + + case Op.ret_i4: case Op.ret_r4: case Op.ret_o: case Op.ret_vt: + case Op.throw_o: + R((int)ir[ip + 1]); return; + + case Op.brtrue_i4: case Op.brfalse_i4: case Op.brtrue_o: case Op.brfalse_o: + R((int)ir[ip + 1]); return; + + case Op.ldfld_i4: case Op.ldfld_r4: case Op.ldfld_o: + case Op.ldfld_struct: case Op.ldflda: + case Op.ldfld_vt_i4: case Op.ldfld_vt_r4: case Op.ldfld_vt_vt: + case Op.ldfld_vt_u1: case Op.ldfld_vt_i1: case Op.ldfld_vt_u2: case Op.ldfld_vt_i2: + case Op.ldfld_sc_i4: case Op.ldfld_sc_r4: case Op.ldfld_sc_o: case Op.ldfld_sc_vt: + W((int)ir[ip + 1]); R((int)ir[ip + 2]); return; + + case Op.stfld_i4: case Op.stfld_r4: case Op.stfld_o: case Op.stfld_struct: + case Op.stfld_vt_i4: case Op.stfld_vt_r4: case Op.stfld_vt_vt: + case Op.stfld_vt_b1: case Op.stfld_vt_b2: + case Op.stfld_sc_i4: case Op.stfld_sc_r4: case Op.stfld_sc_o: case Op.stfld_sc_vt: + R((int)ir[ip + 1]); R((int)ir[ip + 3]); return; + + case Op.ldelem_i4: case Op.ldelem_r4: case Op.ldelem_o: case Op.ldelem_struct: + case Op.ldelem_vt: + W((int)ir[ip + 1]); R((int)ir[ip + 2]); R((int)ir[ip + 3]); return; + + case Op.stelem_i4: case Op.stelem_r4: case Op.stelem_o: case Op.stelem_struct: + case Op.stelem_vt: + R((int)ir[ip + 1]); R((int)ir[ip + 2]); R((int)ir[ip + 3]); return; + + case Op.castclass: case Op.unbox_any: case Op.isinst: case Op.box_prim: + case Op.box_enum: + W((int)ir[ip + 1]); R((int)ir[ip + 2]); return; + + case Op.newarr: case Op.newarr_i4: case Op.newarr_r4: case Op.newarr_vt: + W((int)ir[ip + 1]); R((int)ir[ip + 2]); return; + + case Op.new_delegate: + W((int)ir[ip + 1]); R((int)ir[ip + 3]); return; // word 2 is a tokIdx + + case Op.call_script: + case Op.newobj_script: + case Op.newobj_host: + { + W((int)ir[ip + 1]); + int argc = (int)ir[ip + 3]; + for (int k = 0; k < argc; k++) R((int)ir[ip + 4 + k]); + return; + } + + case Op.call_host: + { + W((int)ir[ip + 1]); R((int)ir[ip + 2]); + int argc = (int)ir[ip + 4]; + for (int k = 0; k < argc; k++) R((int)ir[ip + 5 + k]); + return; + } + + case Op.call_host_byref: + { + W((int)ir[ip + 1]); R((int)ir[ip + 2]); + int argc = (int)ir[ip + 4]; + for (int k = 0; k < argc; k++) R((int)ir[ip + 5 + k]); + int wbBase = ip + 5 + argc; + int wbCount = (int)ir[wbBase]; + for (int k = 0; k < wbCount; k++) + { + int kind = (int)ir[wbBase + 1 + k * 4 + 1]; + int t1 = (int)ir[wbBase + 1 + k * 4 + 2]; + int t2 = (int)ir[wbBase + 1 + k * 4 + 3]; + if (kind == 0) { W(t1); } // frame slot writeback + else if (kind == 1) { R(t1); } // field on object + else { R(t1); R(t2); } // array[idx] + } + return; + } + + case Op.switch_i4: + R((int)ir[ip + 1]); return; + } + } + + // --- Pre-scan helpers --- + + // Scan the IL bytes and collect all branch target offsets into a HashSet. + // Used by LowerMethod to detect basic-block boundaries and clear ensuredScriptSlots. + static HashSet CollectIlBranchTargets(byte[] il) + { + var targets = new HashSet(); + int ip = 0; + while (ip < il.Length) + { + byte b = il[ip++]; + ILOpCode op = b == 0xFE ? (ILOpCode)(0xFE00 | il[ip++]) : (ILOpCode)b; + switch (op) + { + case ILOpCode.Br_s: + case ILOpCode.Brtrue_s: case ILOpCode.Brfalse_s: + case ILOpCode.Beq_s: case ILOpCode.Bne_un_s: + case ILOpCode.Blt_s: case ILOpCode.Blt_un_s: + case ILOpCode.Bgt_s: case ILOpCode.Bgt_un_s: + case ILOpCode.Ble_s: case ILOpCode.Ble_un_s: + case ILOpCode.Bge_s: case ILOpCode.Bge_un_s: + case ILOpCode.Leave_s: + { + int off = (sbyte)il[ip++]; + targets.Add(ip + off); + break; + } + case ILOpCode.Br: + case ILOpCode.Brtrue: case ILOpCode.Brfalse: + case ILOpCode.Beq: case ILOpCode.Bne_un: + case ILOpCode.Blt: case ILOpCode.Blt_un: + case ILOpCode.Bgt: case ILOpCode.Bgt_un: + case ILOpCode.Ble: case ILOpCode.Ble_un: + case ILOpCode.Bge: case ILOpCode.Bge_un: + case ILOpCode.Leave: + { + int off = BitConverter.ToInt32(il, ip); ip += 4; + targets.Add(ip + off); + break; + } + case ILOpCode.Switch: + { + int n = BitConverter.ToInt32(il, ip); ip += 4; + int tableStart = ip; + ip += 4 * n; + for (int ci = 0; ci < n; ci++) + { + int off = BitConverter.ToInt32(il, tableStart + ci * 4); + targets.Add(ip + off); + } + break; + } + default: + ip += ILOperandSize(op, il, ip); + break; + } + } + return targets; + } + + // Handler entry points of every finally region a `leave` at leaveOffset must run before + // reaching `target`: try region contains the leave but not the target. Innermost first + // (smallest try region), matching the order the CLR runs them on the non-exceptional path. + static List FinallyChain( + (int TryStart, int TryEnd, int HandlerStart, int HandlerEnd)[]? regions, + int leaveOffset, int target) + { + var chain = new List(); + if (regions == null) return chain; + // Sort by try-region size so nesting order is explicit (metadata usually orders + // inner clauses first, but don't rely on it). + var hits = new List<(int size, int handlerStart)>(); + foreach (var r in regions) + { + if (r.TryStart <= leaveOffset && leaveOffset < r.TryEnd + && !(r.TryStart <= target && target < r.TryEnd)) + hits.Add((r.TryEnd - r.TryStart, r.HandlerStart)); + } + hits.Sort((a, b) => a.size.CompareTo(b.size)); + foreach (var h in hits) chain.Add(h.handlerStart); + return chain; + } + + // Forward-type-flow pre-pass classifying every local's SType before IR emission: + // a simplified run of the main lowering pass that only tracks types (no IR output), + // pre-populating slotTypes[] for args+locals so the main pass allocates correctly + // from the start. + /// Maps a metadata type token to the interpreter SType for a system PRIMITIVE + /// (Int32/Boolean/Byte/…/Char → I4, Single/Double → R4); null for anything else (script + /// types, reference types, unresolvable). Used by initobj to classify a target the + /// local-type inference couldn't see a store to. + // Box typecode for a primitive value type (else -1). Codes: 0=Int32 1=Boolean 2=Char + // 3=Byte 4=SByte 5=Int16 6=UInt16 7=Single. Others (UInt32/Int64/Double/enum/struct/ref) + // return -1 and keep box a no-op (their value-uses already round-trip correctly). + static int BoxPrimTypeCode(ParsedAssembly asm, int token) + { + try + { + var h = MetadataTokens.EntityHandle(token); + string ns, name; + if (h.Kind == HandleKind.TypeReference) + { var tr = asm.Reader.GetTypeReference((TypeReferenceHandle)h); ns = asm.Reader.GetString(tr.Namespace); name = asm.Reader.GetString(tr.Name); } + else if (h.Kind == HandleKind.TypeDefinition) + { var td = asm.Reader.GetTypeDefinition((TypeDefinitionHandle)h); ns = asm.Reader.GetString(td.Namespace); name = asm.Reader.GetString(td.Name); } + else return -1; + if (ns != "System") return -1; + return name switch + { + "Int32" => 0, "Boolean" => 1, "Char" => 2, "Byte" => 3, + "SByte" => 4, "Int16" => 5, "UInt16" => 6, "Single" => 7, + "UInt32" => 8, // uint is analyzer-legal; boxing as int flips big values negative + "Int64" => 9, "UInt64" => 10, "Double" => 11, // wide slots + _ => -1, + }; + } + catch { return -1; } + } + + static SType? PrimitiveSTypeForTypeToken(ParsedAssembly asm, int token) + { + try + { + var h = MetadataTokens.EntityHandle(token); + string ns, name; + if (h.Kind == HandleKind.TypeReference) + { + var tr = asm.Reader.GetTypeReference((TypeReferenceHandle)h); + ns = asm.Reader.GetString(tr.Namespace); name = asm.Reader.GetString(tr.Name); + } + else if (h.Kind == HandleKind.TypeDefinition) + { + var td = asm.Reader.GetTypeDefinition((TypeDefinitionHandle)h); + ns = asm.Reader.GetString(td.Namespace); name = asm.Reader.GetString(td.Name); + } + else return null; + if (ns != "System") return null; + return name switch + { + "Int32" or "Boolean" or "Byte" or "SByte" or "Int16" or "UInt16" + or "UInt32" or "Char" => SType.I4, + "Single" => SType.R4, + "Int64" or "UInt64" => SType.I8, + "Double" => SType.R8, + _ => null, + }; + } + catch { return null; } + } + + static void PreClassifyLocals(byte[] il, ParsedMethod m, List slotTypes, + int[] localFrameSlot, HostBinding.StructLayout?[]? localStrs, bool[] localDeclared) + { + // Simulated eval stack (just types, no slot indices) + var stack = new SType[64]; + int sp = 0; + var localTypes = new SType[m.LocalCount]; // O by default; Vt locals seeded below + var argTypes = new SType[m.ArgCount]; // O by default + // Seed Vt locals so a later ldloc returns Vt instead of O. + if (localStrs != null) + for (int i = 0; i < m.LocalCount; i++) + if (localStrs[i] != null) localTypes[i] = SType.Vt; + // Seed declared-typed locals from their frozen type so the abstract walk sees them + // correctly and never re-infers them (PreStoreLocal skips them below). + for (int i = 0; i < m.LocalCount; i++) + if (localDeclared[i]) localTypes[i] = slotTypes[localFrameSlot[i]]; + + int ip = 0; + while (ip < il.Length) + { + byte b = il[ip++]; + ILOpCode op = b == 0xFE ? (ILOpCode)(0xFE00 | il[ip++]) : (ILOpCode)b; + switch (op) + { + // Constants + case ILOpCode.Ldc_i4_m1: case ILOpCode.Ldc_i4_0: case ILOpCode.Ldc_i4_1: + case ILOpCode.Ldc_i4_2: case ILOpCode.Ldc_i4_3: case ILOpCode.Ldc_i4_4: + case ILOpCode.Ldc_i4_5: case ILOpCode.Ldc_i4_6: case ILOpCode.Ldc_i4_7: + case ILOpCode.Ldc_i4_8: if(sp<64)stack[sp++]=SType.I4; break; + case ILOpCode.Ldc_i4_s: ip++; if(sp<64)stack[sp++]=SType.I4; break; + case ILOpCode.Ldc_i4: ip+=4; if(sp<64)stack[sp++]=SType.I4; break; + case ILOpCode.Ldc_r4: ip+=4; if(sp<64)stack[sp++]=SType.R4; break; + case ILOpCode.Ldc_r8: ip+=8; if(sp<64)stack[sp++]=SType.R8; break; + case ILOpCode.Ldc_i8: ip+=8; if(sp<64)stack[sp++]=SType.I8; break; + case ILOpCode.Ldnull: if(sp<64)stack[sp++]=SType.O; break; + case ILOpCode.Ldstr: ip+=4; if(sp<64)stack[sp++]=SType.O; break; + + // Locals + // Bounds-guarded like Ldloc_s below: valid IL never underflows, but this pass + // walks unknown opcodes by table — a size mistake there must degrade, not throw. + case ILOpCode.Ldloc_0: if(sp<64)stack[sp++]=m.LocalCount>0?localTypes[0]:SType.O; break; + case ILOpCode.Ldloc_1: if(sp<64)stack[sp++]=m.LocalCount>1?localTypes[1]:SType.O; break; + case ILOpCode.Ldloc_2: if(sp<64)stack[sp++]=m.LocalCount>2?localTypes[2]:SType.O; break; + case ILOpCode.Ldloc_3: if(sp<64)stack[sp++]=m.LocalCount>3?localTypes[3]:SType.O; break; + case ILOpCode.Ldloc_s: { int i=il[ip++]; if(sp<64)stack[sp++]=i0?argTypes[0]:SType.O; break; + case ILOpCode.Ldarg_1: if(sp<64)stack[sp++]=argTypes.Length>1?argTypes[1]:SType.O; break; + case ILOpCode.Ldarg_2: if(sp<64)stack[sp++]=argTypes.Length>2?argTypes[2]:SType.O; break; + case ILOpCode.Ldarg_3: if(sp<64)stack[sp++]=argTypes.Length>3?argTypes[3]:SType.O; break; + case ILOpCode.Ldarg_s: { ip++; if(sp<64)stack[sp++]=SType.O; break; } + case ILOpCode.Ldarg: { ip+=2; if(sp<64)stack[sp++]=SType.O; break; } + case ILOpCode.Starg_s: ip++; if(sp>0)sp--; break; + case ILOpCode.Starg: ip+=2; if(sp>0)sp--; break; + + // Arithmetic (consume 2, push 1 of same type) + case ILOpCode.Add: case ILOpCode.Sub: case ILOpCode.Mul: case ILOpCode.Div: case ILOpCode.Rem: + { + if(sp>=2){SType t2=stack[--sp];SType t1=stack[sp-1]; + stack[sp-1]=t1==SType.R8||t2==SType.R8?SType.R8 + :t1==SType.R4||t2==SType.R4?SType.R4 + :t1==SType.I8||t2==SType.I8?SType.I8:SType.I4;} + break; + } + case ILOpCode.Neg: + if(sp>0){SType t=stack[sp-1];stack[sp-1]=t is SType.R4 or SType.R8 or SType.I8?t:SType.I4;} break; + case ILOpCode.And: case ILOpCode.Or: case ILOpCode.Xor: case ILOpCode.Shl: case ILOpCode.Shr: case ILOpCode.Shr_un: + if(sp>=2){SType t2=stack[--sp];SType t1=stack[sp-1];stack[sp-1]=t1==SType.I8||t2==SType.I8?SType.I8:SType.I4;} break; + case ILOpCode.Not: + if(sp>0)stack[sp-1]=SType.I4; break; + + // Comparisons → I4 + case ILOpCode.Ceq: case ILOpCode.Cgt: case ILOpCode.Clt: case ILOpCode.Cgt_un: case ILOpCode.Clt_un: + if(sp>=2){sp--;stack[sp-1]=SType.I4;} break; + + // Conversions + case ILOpCode.Conv_i4: case ILOpCode.Conv_u4: + case ILOpCode.Conv_i1: case ILOpCode.Conv_u1: + case ILOpCode.Conv_i2: case ILOpCode.Conv_u2: + if(sp>0)stack[sp-1]=SType.I4; break; + case ILOpCode.Conv_r4: + if(sp>0)stack[sp-1]=SType.R4; break; + case ILOpCode.Conv_r8: case ILOpCode.Conv_r_un: + if(sp>0)stack[sp-1]=SType.R8; break; + case ILOpCode.Conv_i8: case ILOpCode.Conv_u8: + if(sp>0)stack[sp-1]=SType.I8; break; + + // Box, dup, pop + case ILOpCode.Box: ip+=4; break; + case ILOpCode.Dup: if(sp>0&&sp<64){stack[sp]=stack[sp-1];sp++;} break; + case ILOpCode.Pop: if(sp>0)sp--; break; + + // Branches (pop 0, 1, or 2) + case ILOpCode.Br_s: ip+=1; sp=0; break; + case ILOpCode.Br: ip+=4; sp=0; break; + case ILOpCode.Leave_s: ip+=1; sp=0; break; + case ILOpCode.Leave: ip+=4; sp=0; break; + case ILOpCode.Endfinally: sp=0; break; + case ILOpCode.Brtrue_s: case ILOpCode.Brfalse_s: ip+=1; if(sp>0)sp--; break; + case ILOpCode.Brtrue: case ILOpCode.Brfalse: ip+=4; if(sp>0)sp--; break; + case ILOpCode.Beq_s: case ILOpCode.Bne_un_s: case ILOpCode.Blt_s: case ILOpCode.Bgt_s: + case ILOpCode.Ble_s: case ILOpCode.Bge_s: case ILOpCode.Blt_un_s: case ILOpCode.Bgt_un_s: + case ILOpCode.Ble_un_s: case ILOpCode.Bge_un_s: ip+=1; if(sp>=2)sp-=2; break; + case ILOpCode.Beq: case ILOpCode.Bne_un: case ILOpCode.Blt: case ILOpCode.Bgt: + case ILOpCode.Ble: case ILOpCode.Bge: case ILOpCode.Blt_un: case ILOpCode.Bgt_un: + case ILOpCode.Ble_un: case ILOpCode.Bge_un: ip+=4; if(sp>=2)sp-=2; break; + + // Everything else: skip operands, reset stack conservatively (don't corrupt) + default: + { + int sz = ILOperandSize(op, il, ip); + ip += sz; + // For calls, field access, etc. — conservatively push/pop O values + // We don't need perfect accuracy here; only stloc tracking matters. + if (op == ILOpCode.Call || op == ILOpCode.Callvirt || op == ILOpCode.Newobj) + { + // Just clear the stack to be safe — we can't know arg counts without parsing sigs + sp = 0; + } + else if (op == ILOpCode.Ldfld || op == ILOpCode.Ldflda || op == ILOpCode.Ldsfld) + { + if(sp>0)sp--; + if(sp<64)stack[sp++]=SType.O; + } + else if (op == ILOpCode.Stfld) + { + if(sp>=2)sp-=2; + } + else if (op == ILOpCode.Stsfld) + { + if(sp>0)sp--; + } + else if (op == ILOpCode.Ldlen || op == ILOpCode.Newarr || op == ILOpCode.Ldtoken) + { + if(sp>0)sp--; + if(sp<64)stack[sp++]=SType.O; + } + break; + } + } + } + } + + // On conflicting stores, keep the most recent type — in practice well-typed C# + // stores only one type into each local. + static void UpdateSlotType(List slotTypes, int slot, SType t, string context = "") + { + if (slot < slotTypes.Count && slotTypes[slot] != SType.Vt) // never downgrade a Vt slot + slotTypes[slot] = t; + } + + // Stloc handler for the pre-classify pass: writes localTypes[i] = src type, propagates to + // slotTypes at the local's frame slot. Vt locals are seeded ahead of time and never overwritten. + static void PreStoreLocal(SType[] stack, ref int sp, int i, ParsedMethod m, + SType[] localTypes, List slotTypes, int[] localFrameSlot, HostBinding.StructLayout?[]? localStrs, + bool[] localDeclared) + { + if (sp == 0 || i >= m.LocalCount) { if (sp > 0) sp--; return; } + SType t = stack[--sp]; + if (i < localDeclared.Length && localDeclared[i]) return; // declared type is frozen — never infer + if (localStrs != null && localStrs[i] != null) return; // Vt local — keep type + // A Vt VALUE flowing into a local with no struct layout (e.g. `object o = someStruct;`) + // BOXES at the store — the local is O. Marking it Vt would make StoreLocal alias the + // struct bytes (mov_vt with a null layout) and lose box-snapshot semantics. + if (t == SType.Vt) t = SType.O; + localTypes[i] = t; + UpdateSlotType(slotTypes, localFrameSlot[i], t); + } + + // Returns the operand size in bytes for an IL opcode at position ip (for skipping in pre-scan). + static int ILOperandSize(ILOpCode op, byte[] il, int ip) + { + switch (op) + { + case ILOpCode.Ldarg_s: case ILOpCode.Ldloc_s: case ILOpCode.Stloc_s: + case ILOpCode.Ldarga_s: case ILOpCode.Ldloca_s: case ILOpCode.Starg_s: + case ILOpCode.Ldc_i4_s: case ILOpCode.Brfalse_s: case ILOpCode.Brtrue_s: + case ILOpCode.Br_s: case ILOpCode.Beq_s: case ILOpCode.Bge_s: case ILOpCode.Bgt_s: + case ILOpCode.Ble_s: case ILOpCode.Blt_s: case ILOpCode.Bne_un_s: + case ILOpCode.Bge_un_s: case ILOpCode.Bgt_un_s: case ILOpCode.Ble_un_s: + case ILOpCode.Blt_un_s: case ILOpCode.Leave_s: + case (ILOpCode)0xFE12: // Unaligned prefix (banned opcode) + return 1; + case ILOpCode.Ldarg: case ILOpCode.Ldloc: case ILOpCode.Stloc: case ILOpCode.Ldarga: + case ILOpCode.Ldloca: case ILOpCode.Starg: + return 2; + case ILOpCode.Ldc_i4: case ILOpCode.Ldc_r4: case ILOpCode.Ldstr: case ILOpCode.Newobj: + case ILOpCode.Ldfld: case ILOpCode.Ldflda: case ILOpCode.Stfld: case ILOpCode.Ldsfld: + case ILOpCode.Stsfld: case ILOpCode.Leave: case ILOpCode.Constrained: + case ILOpCode.Call: case ILOpCode.Callvirt: case ILOpCode.Newarr: + case ILOpCode.Ldelem: case ILOpCode.Stelem: case ILOpCode.Ldelema: case ILOpCode.Unbox_any: + case ILOpCode.Box: case ILOpCode.Castclass: case ILOpCode.Isinst: case ILOpCode.Ldtoken: + case ILOpCode.Br: case ILOpCode.Beq: case ILOpCode.Bge: case ILOpCode.Bgt: + case ILOpCode.Ble: case ILOpCode.Blt: case ILOpCode.Bne_un: case ILOpCode.Bge_un: + case ILOpCode.Bgt_un: case ILOpCode.Ble_un: case ILOpCode.Blt_un: + case ILOpCode.Brfalse: case ILOpCode.Brtrue: case ILOpCode.Initobj: + // Token-operand opcodes the lowerer rejects later — the size must still be right + // here, or the walk reads the token bytes as opcodes and desyncs (a misread + // ldloc.N then indexes past the locals array — the ldftn/delegate-creation crash). + case ILOpCode.Ldftn: case ILOpCode.Ldvirtftn: case ILOpCode.Ldsflda: + case ILOpCode.Jmp: case ILOpCode.Calli: case ILOpCode.Cpobj: case ILOpCode.Ldobj: + case ILOpCode.Stobj: case ILOpCode.Unbox: case ILOpCode.Refanyval: + case ILOpCode.Mkrefany: case ILOpCode.Sizeof: + return 4; + case ILOpCode.Ldc_r8: case (ILOpCode)0x21: // 0x21=Ldc_i8 (banned, 8-byte operand) + return 8; + case ILOpCode.Switch: + if (ip < il.Length) { int n = BitConverter.ToInt32(il, ip); return 4 + n * 4; } + return 0; + default: + return 0; // no operand + } + } + + // --- Slot allocation helpers --- + + // AllocSlot ALSO grows slotStructs (with null) in lockstep so the two lists stay aligned. + // For Vt slots, use AllocStructSlot which reserves ceil(size/4) consecutive slots. + static int AllocSlot(ref int frameSize, List slotTypes, List slotStructs, SType t, HostBinding.StructLayout? lay) + { + int s = frameSize++; + slotTypes.Add(t); + slotStructs.Add(lay); + if (t is SType.I8 or SType.R8) + { + // Wide value: reserve the continuation cell, filler-typed like Vt continuation + // cells so nothing else is allocated over the value's second half. + slotTypes.Add(SType.O); + slotStructs.Add(null); + frameSize++; + } + return s; + } + + static int AllocStructSlot(ref int frameSize, List slotTypes, List slotStructs, HostBinding.StructLayout lay) + { + int s = frameSize++; + slotTypes.Add(SType.Vt); + slotStructs.Add(lay); + int filler = (lay.Size + 3) / 4 - 1; + for (int k = 0; k < filler; k++) + { + slotTypes.Add(SType.O); + slotStructs.Add(null); + frameSize++; + } + return s; + } + + // Converge the value currently on top of the eval stack into a single "merge slot" for a forward + // join, so every forward edge into `target` leaves its result in the same frame slot. Used by the + // ternary/short-circuit `br` path and by conditional branches that carry a value to a forward join + // — e.g. `a ?? b`, whose `dup; brtrue L` leaves the left operand on the stack on the taken edge. + // Emits the mov (unconditionally, before the branch) and repoints the eval-stack top at the merge + // slot; the join reconciles the other edge's value into the same slot via mergeSlotForEnd. + static void MergeTopIntoJoinSlot( + List ir, List irToIl, (int slot, SType type)[] evalStack, int sp, + ref int frameSize, List slotTypes, List slotStructs, + Dictionary mergeSlotForEnd, int target, int instrStart) + { + var (firstSlot, firstType) = evalStack[sp - 1]; + int mSlot; + if (mergeSlotForEnd.TryGetValue(target, out var existing)) + mSlot = existing.slot; // multiple edges merging into one join + else if (firstType == SType.Vt) + { + mSlot = AllocStructSlot(ref frameSize, slotTypes, slotStructs, slotStructs[firstSlot]!); + mergeSlotForEnd[target] = (mSlot, firstType); + } + else + { + mSlot = AllocSlot(ref frameSize, slotTypes, slotStructs, firstType, null); + mergeSlotForEnd[target] = (mSlot, firstType); + } + if (mSlot != firstSlot) + Emit3(ir, irToIl, firstType == SType.Vt ? Op.mov_vt : Op.mov, mSlot, firstSlot, instrStart); + evalStack[sp - 1] = (mSlot, firstType); + } + + // Emit call_host_byref. Each byref arg is replaced with a fresh boxed O slot pre-loaded + // with the target's current value (so MethodInfo.Invoke can write through it), then a + // writeback table is appended so the executor copies the post-call value back into + // the original frame slot / field / array element. + static void EmitCallHostByref(List ir, List irToIl, (int slot, SType type)[] evalStack, + ref int sp, ref int frameSize, List slotTypes, List slotStructs, + int[] addrTagBySlot, int[] addrFldObjBySlot, int[] addrFldTokBySlot, int[] addrByteOffBySlot, + ParsedAssembly asm, List tokens, HostEntry hostEntry, int tokIdx, + ParameterInfo[] ps, int instrStart) + { + int argc = hostEntry.Binding.ParamCount; + bool isVoid = hostEntry.IsVoid; + // Type the result slot like the regular call_host dst-picker: from the resolved + // MethodInfo's return type, falling back to the MemberRef signature for string-keyed + // shims. A blanket O dst left bool/int results boxed in the ref frame, and a boxed + // false condition was then null-tested TRUE under brtrue_o's pure reference semantics + // (found by fuzzing: TryHalve-shaped bool-returning byref calls). Vt returns keep O. + SType retSt = SType.O; + if (!isVoid && (hostEntry.ResolvedMethod ?? hostEntry.Binding.Method) is MethodInfo bmi) + { + var brt = bmi.ReturnType; + if (brt == typeof(float)) retSt = SType.R4; + else if (brt == typeof(int) || brt == typeof(bool) || brt == typeof(byte) + || brt == typeof(sbyte) || brt == typeof(short) || brt == typeof(ushort)) retSt = SType.I4; + } + else if (!isVoid && hostEntry.SigRetSType is SType.I4 or SType.R4) + retSt = hostEntry.SigRetSType; + int dst = isVoid ? -1 : AllocSlot(ref frameSize, slotTypes, slotStructs, retSt, null); + + // Receiver — same address-resolution rules as the regular call_host path. + int recvSlotRaw = hostEntry.Binding.HasThis ? evalStack[sp - argc - 1].slot : -1; + int recvSlot = recvSlotRaw; + int recvVtOffB = 0; bool recvVtWbB = false; int recvVtWbBaseB = -1; + if (recvSlotRaw >= 0) + { + int addrTag = addrTagBySlot[recvSlotRaw]; + if (addrTag >= 0) { recvSlot = addrTag; recvVtOffB = addrByteOffBySlot[recvSlotRaw]; } + else if (addrTag == -1) + { + int fldObj = addrFldObjBySlot[recvSlotRaw]; + int fldToki = addrFldTokBySlot[recvSlotRaw]; + int fldTok = tokens[fldToki]; + asm.FieldSTypes.TryGetValue(fldTok, out var fldSt); + bool isScFieldB = asm.FieldSlots.TryGetValue(fldTok, out var fldFsB); + // Vt field receiver: struct slot + byte-range load (see the call_host site). + var fldVtLayB = isScFieldB && fldSt == SType.Vt + ? fldFsB.Item1.VtFieldLayouts?[fldFsB.Item2] : null; + recvSlot = fldVtLayB != null + ? AllocStructSlot(ref frameSize, slotTypes, slotStructs, fldVtLayB) + : AllocSlot(ref frameSize, slotTypes, slotStructs, fldSt, null); + if (isScFieldB) + { + int fldOffB = fldFsB.Item1.FieldOffsets[fldFsB.Item2]; + var fldOpB = fldVtLayB != null ? Op.ldfld_sc_vt + : fldSt == SType.I4 ? Op.ldfld_sc_i4 : fldSt == SType.R4 ? Op.ldfld_sc_r4 : Op.ldfld_sc_o; + Emit4(ir, irToIl, fldOpB, recvSlot, fldObj, fldOffB, instrStart); + } + else + { + var fldLoadOp = fldSt == SType.I4 ? Op.ldfld_i4 : fldSt == SType.R4 ? Op.ldfld_r4 : Op.ldfld_o; + Emit4(ir, irToIl, fldLoadOp, recvSlot, fldObj, fldToki, instrStart); + } + } + } + + // Nested-offset Vt receiver — same materialize + write-back as the call_host path. + if (hostEntry.Binding.HasThis && recvSlot >= 0 && recvVtOffB != 0 + && recvSlot < slotTypes.Count && slotTypes[recvSlot] == SType.Vt + && hostEntry.ReceiverStruct != null) + { + int rTmpB = AllocStructSlot(ref frameSize, slotTypes, slotStructs, hostEntry.ReceiverStruct); + Emit4(ir, irToIl, Op.ldfld_vt_vt, rTmpB, recvSlot, recvVtOffB, instrStart); + recvVtWbB = true; recvVtWbBaseB = recvSlot; + recvSlot = rTmpB; + } + + int argBase = sp - argc; + int spBase = sp - argc - (hostEntry.Binding.HasThis ? 1 : 0); + + // Walk byref args: replace each phantom-addr arg slot with a fresh O slot pre-loaded + // with the current value at the address. Record the writeback target in parallel arrays. + // Max 8 byref args is plenty (Physics.Raycast is the worst common case at ~3). + Span wbArgIdx = stackalloc int[8]; + Span wbKind = stackalloc int[8]; + Span wbT1 = stackalloc int[8]; + Span wbT2 = stackalloc int[8]; + int wbCount = 0; + for (int k = 0; k < argc; k++) + { + if (k >= ps.Length || !ps[k].ParameterType.IsByRef) continue; + int origSlot = evalStack[argBase + k].slot; + int tag = addrTagBySlot[origSlot]; + int boxed = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + if (tag >= 0) + { + // Pre-load current value (may be irrelevant for `out`). A flat (Vt) source + // lives in the numeric frame — box it; a plain mov would read the wrong frame. + Emit3(ir, irToIl, slotTypes[tag] == SType.Vt ? Op.box_vt : Op.mov, boxed, tag, instrStart); + if (wbCount < 8) + { wbArgIdx[wbCount] = k; wbKind[wbCount] = 0; wbT1[wbCount] = tag; wbT2[wbCount] = 0; wbCount++; } + } + else if (tag == -1) + { + int fldObj = addrFldObjBySlot[origSlot]; + int fldToki = addrFldTokBySlot[origSlot]; + int fldTok = tokens[fldToki]; + asm.FieldSTypes.TryGetValue(fldTok, out var fldSt); + bool isScFieldC = asm.FieldSlots.TryGetValue(fldTok, out var fldFsC); + var fldVtLayC = isScFieldC && fldSt == SType.Vt + ? fldFsC.Item1.VtFieldLayouts?[fldFsC.Item2] : null; + // Pre-load into a slot tagged with the FIELD's type, not O: the field-load ops + // write I4/R4 values into the numeric frame, so an O-tagged slot reads back + // null and the host call sees 0 (found by fuzzing: `h.Accumulate(ref acc)` on + // a hoisted iterator field passed 0 in — the writeback masked the wrong input). + // RdObj boxes an I4/R4-tagged slot correctly at call time, like the receiver + // resolution above. Vt and O fields keep the O tag — their pre-load lands a + // boxed object in the ref frame. + if (fldSt == SType.I4 || fldSt == SType.R4) + slotTypes[boxed] = fldSt; + if (fldVtLayC != null) + { + // Flat (Vt) script field — e.g. a Vector3 hoisted into an iterator state + // machine because an out-arg takes its address: materialize the bytes into + // a struct slot, then box for the reflective call. The op picker below + // would emit ldfld_sc_o, indexing RefSlots with a PrimBytes byte offset. + int tmpVtC = AllocStructSlot(ref frameSize, slotTypes, slotStructs, fldVtLayC); + Emit4(ir, irToIl, Op.ldfld_sc_vt, tmpVtC, fldObj, fldFsC.Item1.FieldOffsets[fldFsC.Item2], instrStart); + Emit3(ir, irToIl, Op.box_vt, boxed, tmpVtC, instrStart); + } + else if (isScFieldC) + { + int fldOffC = fldFsC.Item1.FieldOffsets[fldFsC.Item2]; + var fldOpC = fldSt == SType.I4 ? Op.ldfld_sc_i4 : fldSt == SType.R4 ? Op.ldfld_sc_r4 : Op.ldfld_sc_o; + Emit4(ir, irToIl, fldOpC, boxed, fldObj, fldOffC, instrStart); + } + else + { + var fldLoadOp = fldSt == SType.I4 ? Op.ldfld_i4 : fldSt == SType.R4 ? Op.ldfld_r4 : Op.ldfld_o; + Emit4(ir, irToIl, fldLoadOp, boxed, fldObj, fldToki, instrStart); + } + if (wbCount < 8) + { wbArgIdx[wbCount] = k; wbKind[wbCount] = 1; wbT1[wbCount] = fldObj; wbT2[wbCount] = fldToki; wbCount++; } + } + else if (tag == -3) + { + int arrSlot = addrFldObjBySlot[origSlot]; + int idxSlot = addrFldTokBySlot[origSlot]; + Emit4(ir, irToIl, Op.ldelem_o, boxed, arrSlot, idxSlot, instrStart); + if (wbCount < 8) + { wbArgIdx[wbCount] = k; wbKind[wbCount] = 2; wbT1[wbCount] = arrSlot; wbT2[wbCount] = idxSlot; wbCount++; } + } + else + { + // Non-phantom passed by ref — read whatever's there but no writeback target. + Emit3(ir, irToIl, slotTypes[origSlot] == SType.Vt ? Op.box_vt : Op.mov, boxed, origSlot, instrStart); + } + evalStack[argBase + k] = (boxed, SType.O); + } + + // Box any leftover Vt args (slow path doesn't read flat). + for (int k = 0; k < argc; k++) + { + if (evalStack[argBase + k].type == SType.Vt) + { + int boxed = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + Emit3(ir, irToIl, Op.box_vt, boxed, evalStack[argBase + k].slot, instrStart); + evalStack[argBase + k] = (boxed, SType.O); + } + } + + ir.Add((uint)Op.call_host_byref); irToIl.Add(instrStart); + ir.Add((uint)(isVoid ? -1 : dst)); irToIl.Add(instrStart); + ir.Add((uint)(hostEntry.Binding.HasThis ? recvSlot : -1)); irToIl.Add(instrStart); + ir.Add((uint)tokIdx); irToIl.Add(instrStart); + ir.Add((uint)argc); irToIl.Add(instrStart); + for (int k = 0; k < argc; k++) + { ir.Add((uint)evalStack[argBase + k].slot); irToIl.Add(instrStart); } + ir.Add((uint)wbCount); irToIl.Add(instrStart); + for (int k = 0; k < wbCount; k++) + { + ir.Add((uint)wbArgIdx[k]); irToIl.Add(instrStart); + ir.Add((uint)wbKind[k]); irToIl.Add(instrStart); + ir.Add((uint)wbT1[k]); irToIl.Add(instrStart); + ir.Add((uint)wbT2[k]); irToIl.Add(instrStart); + } + if (recvVtWbB) + Emit4(ir, irToIl, Op.stfld_vt_vt, recvVtWbBaseB, recvVtOffB, recvSlot, instrStart); + sp = spBase; + if (!isVoid) evalStack[sp++] = (dst, retSt); + } + + // Operator inlining: synthesize per-field arithmetic IR for a pure host-struct operator + // or constructor. The args on evalStack at [argBase..argBase+argc) are either Vt slots + // (for struct args) or scalar slots (for float/int args). The result goes into dst (a Vt slot). + // + // Strategy: iterate the return struct's fields in byte-offset order, match each to the + // corresponding field in one of the Vt args, and emit a scalar arithmetic op per field. + // For scalar args (no struct layout), use the slot directly for all fields. + // Supported shapes: Vt op Vt, Vt op Scalar, Scalar op Vt, Scalar Scalar Scalar (ctor). + // Cheap pre-check for EmitInlinedOp, evaluated BEFORE the Vt-arg boxing decision: once + // the lowerer skips boundary boxing it is committed to inlining, so every precondition + // must hold up front (a mid-emission bail-out would leave partial IR behind). + static bool CanInlineOp(HostEntry hostEntry, int argc, HostBinding.StructLayout retLayout, bool isCtor) + { + if (retLayout.Fields.Count == 0) return false; + if (isCtor) return argc == retLayout.Fields.Count; + var n = hostEntry.Binding.Method?.Name; + if (n != "op_Addition" && n != "op_Subtraction" && n != "op_Multiply" + && n != "op_Division" && n != "op_UnaryNegation") return false; + return n == "op_UnaryNegation" ? argc == 1 : argc == 2; + } + + // Synthesizes per-field IR for a VERIFIED component-wise operator or field-order ctor + // (see HostBinding.InspectAndMarkOperators — marking guarantees the IL is exactly the + // per-field pattern, so this name-driven emission is semantically equivalent). + static void EmitInlinedOp(List ir, List irToIl, (int slot, SType type)[] evalStack, + int argBase, int argc, int dst, HostBinding.StructLayout retLayout, + HostEntry hostEntry, int instrStart, bool isCtor) + { + // Build sorted field list: (byteOffset, SType) sorted by byte offset. + var fields = new (int Off, SType St)[retLayout.Fields.Count]; + int fi = 0; + foreach (var kv in retLayout.Fields) + fields[fi++] = (kv.Value.Offset, kv.Value.St); + // Sort by offset (Fields dict may be unordered) + for (int a = 0; a < fields.Length - 1; a++) + for (int b = a + 1; b < fields.Length; b++) + if (fields[b].Off < fields[a].Off) { var tmp = fields[a]; fields[a] = fields[b]; fields[b] = tmp; } + + if (isCtor) + { + // Verified field-order ctor: param i is exactly field i's value (arity checked + // by CanInlineOp before any IR was committed). + for (int f = 0; f < fields.Length; f++) + { + var stF = fields[f].St == SType.R4 ? Op.stfld_vt_r4 : Op.stfld_vt_i4; + ir.Add((uint)stF); irToIl.Add(instrStart); + ir.Add((uint)dst); irToIl.Add(instrStart); + ir.Add((uint)fields[f].Off); irToIl.Add(instrStart); + ir.Add((uint)evalStack[argBase + f].slot); irToIl.Add(instrStart); + } + return; + } + + // For each result field, emit one arithmetic instruction. Struct-vs-scalar per arg is + // decided from the CALL SITE's slot types, not the entry's ArgStructs — aliased + // operator pairs ((V3,float) + (float,V3)) share one Entry, so the entry's signature + // metadata may describe the other overload. + for (int f = 0; f < fields.Length; f++) + { + int dstSubSlot = dst + fields[f].Off / 4; + var argSubs = new int[argc]; + for (int k = 0; k < argc; k++) + { + int argSlot = evalStack[argBase + k].slot; + argSubs[k] = evalStack[argBase + k].type == SType.Vt + ? argSlot + fields[f].Off / 4 // struct arg: same-offset component + : argSlot; // scalar arg: same slot for every field + } + + string mName = hostEntry.Binding.Method?.Name ?? ""; + Op fieldOp; + if (mName == "op_Addition") fieldOp = fields[f].St == SType.R4 ? Op.add_r4_nn : Op.add_i4_nn; + else if (mName == "op_Subtraction") fieldOp = fields[f].St == SType.R4 ? Op.sub_r4_nn : Op.sub_i4_nn; + else if (mName == "op_Multiply") fieldOp = fields[f].St == SType.R4 ? Op.mul_r4_nn : Op.mul_i4_nn; + else if (mName == "op_Division") fieldOp = fields[f].St == SType.R4 ? Op.div_r4_nn : Op.div_i4_nn; + else fieldOp = fields[f].St == SType.R4 ? Op.neg_r4_n : Op.neg_i4_n; // op_UnaryNegation (CanInlineOp vetted the name) + + if (argc == 1) + { + ir.Add((uint)fieldOp); irToIl.Add(instrStart); + ir.Add((uint)dstSubSlot); irToIl.Add(instrStart); + ir.Add((uint)argSubs[0]); irToIl.Add(instrStart); + } + else + { + ir.Add((uint)fieldOp); irToIl.Add(instrStart); + ir.Add((uint)dstSubSlot); irToIl.Add(instrStart); + ir.Add((uint)argSubs[0]); irToIl.Add(instrStart); + ir.Add((uint)argSubs[1]); irToIl.Add(instrStart); + } + } + } + + // Value-load a local, cloning script-defined structs so the pushed value is an independent + // copy (struct copy semantics). Address loads (ldloca) never come through here, so in-place + // field mutation is unaffected. + static void PushLocal(List ir, List irToIl, (int, SType)[] stack, ref int sp, + ref int frameSize, int localIdx, int[] localFrameSlot, SType[] localTypes, + List slotTypes, List slotStructs, + bool[]? localIsScStruct, int instrStart) + { + int srcSlot = localFrameSlot[localIdx]; + SType t = localTypes[localIdx]; + if (t == SType.O && localIsScStruct != null && localIdx < localIsScStruct.Length && localIsScStruct[localIdx]) + { + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.O, null); + Emit3(ir, irToIl, Op.clone_sc, dst, srcSlot, instrStart); + stack[sp++] = (dst, SType.O); + } + else + { + stack[sp++] = (srcSlot, t); + } + } + + // Any pending eval-stack entry that ALIASES the slot about to be stored must be + // materialized into a temp first: PushLocal/PushArg push the local's own frame slot, so + // `(a, b) = (b, a)` — `ldloc b; ldloc a; stloc b; stloc a` — left the second-from-top + // entry pointing AT b's slot when b was overwritten, and a came back as the new b + // (found by fuzzing). Address phantoms don't match here (their entry is a fresh phantom + // slot), and a store through an address is genuine aliasing anyway. + static void ProtectStackAliases(List ir, List irToIl, (int, SType)[] stack, int sp, + ref int frameSize, List slotTypes, List slotStructs, + int dst, int instrStart) + { + for (int i = 0; i < sp; i++) + { + if (stack[i].Item1 != dst) continue; + var t = stack[i].Item2; + if (t == SType.Vt && dst < slotStructs.Count && slotStructs[dst] != null) + { + int tmp = AllocStructSlot(ref frameSize, slotTypes, slotStructs, slotStructs[dst]!); + Emit3(ir, irToIl, Op.mov_vt, tmp, dst, instrStart); + stack[i] = (tmp, t); + } + else + { + int tmp = AllocSlot(ref frameSize, slotTypes, slotStructs, dst < slotTypes.Count ? slotTypes[dst] : t, null); + Emit3(ir, irToIl, Op.mov, tmp, dst, instrStart); + stack[i] = (tmp, t); + } + } + } + + static void StoreLocal(List ir, List irToIl, (int, SType)[] stack, ref int sp, int localIdx, int[] localFrameSlot, SType[] localTypes, List slotTypes, List slotStructs, bool[] localDeclared, ref int frameSize, int instrStart) + { + var (src, t) = stack[--sp]; + int dst = localFrameSlot[localIdx]; + ProtectStackAliases(ir, irToIl, stack, sp, ref frameSize, slotTypes, slotStructs, dst, instrStart); + // Vt local: byte-copy struct bytes from src into the local slot. Requires the dst + // slot to actually carry a layout — a Vt-typed slot without one must not alias. + if (slotTypes[dst] == SType.Vt && t == SType.Vt && slotStructs[dst] != null) + { + Emit3(ir, irToIl, Op.mov_vt, dst, src, instrStart); + return; + } + // Vt local being stored from O slot: unbox + flat-write. + if (slotTypes[dst] == SType.Vt && t == SType.O) + { + Emit3(ir, irToIl, Op.unbox_vt, dst, src, instrStart); + return; + } + // Vt source going into a non-Vt local (struct-returning ops produce Vt slots even + // when the local stays O because no ldloca was taken on it). Box the Vt bytes + // into a refFrame entry so the O local sees a normal boxed reference. + if (slotTypes[dst] != SType.Vt && t == SType.Vt) + { + localTypes[localIdx] = SType.O; + if (dst < slotTypes.Count) slotTypes[dst] = SType.O; + Emit3(ir, irToIl, Op.box_vt, dst, src, instrStart); + return; + } + if (localIdx < localDeclared.Length && localDeclared[localIdx]) + { + // Declared type is FROZEN — never retype the slot. Op.mov routes by the (fixed) dst + // slot type at runtime, boxing/unboxing the source to match, so an int stored into a + // declared `object` local boxes and a boxed value read back unboxes, consistently. + localTypes[localIdx] = slotTypes[dst]; + Emit3(ir, irToIl, Op.mov, dst, src, instrStart); + return; + } + localTypes[localIdx] = t; // remember what type this local holds (non-Vt locals only) + if (dst < slotTypes.Count) slotTypes[dst] = t; + Emit3(ir, irToIl, Op.mov, dst, src, instrStart); + } + + static void PushArg((int, SType)[] stack, ref int sp, int argIdx, SType[] argTypes, int[] argFrameSlot) + { + stack[sp++] = (argFrameSlot[argIdx], argTypes[argIdx]); + } + + static void StoreArg(List ir, List irToIl, (int, SType)[] stack, ref int sp, + int argIdx, SType[] argTypes, int[] argFrameSlot, List slotTypes, List slotStructs, ref int frameSize, int instrStart) + { + var (src, t) = stack[--sp]; + int dst = argFrameSlot[argIdx]; + ProtectStackAliases(ir, irToIl, stack, sp, ref frameSize, slotTypes, slotStructs, dst, instrStart); + // Vt arg slots have a FIXED type (the frame layout is part of the call ABI): copy + // struct bytes in (or unbox a boxed ScriptObject); never retype the slot. + if (slotTypes[dst] == SType.Vt) + { + Emit3(ir, irToIl, t == SType.Vt ? Op.mov_vt : Op.unbox_vt, dst, src, instrStart); + return; + } + argTypes[argIdx] = t; + Emit3(ir, irToIl, Op.mov, dst, src, instrStart); + } + + static void PushConst(List ir, List irToIl, (int, SType)[] stack, ref int sp, ref int frameSize, List slotTypes, List slotStructs, int imm, SType t, Op ldc, int instrStart) + { + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, t, null); + stack[sp++] = (dst, t); + Emit3(ir, irToIl, ldc, dst, imm, instrStart); + } + + // Map an i4-family op to its wide sibling. Throws for combinations IL can't + // produce or the subset doesn't support — the LowerAll catch-all keeps it loud. + static Op Wide64(Op i4Op, bool isR8) => (i4Op, isR8) switch + { + (Op.add_i4, false) => Op.add_i8, (Op.add_i4, true) => Op.add_r8, + (Op.sub_i4, false) => Op.sub_i8, (Op.sub_i4, true) => Op.sub_r8, + (Op.mul_i4, false) => Op.mul_i8, (Op.mul_i4, true) => Op.mul_r8, + (Op.div_i4, false) => Op.div_i8, (Op.div_i4, true) => Op.div_r8, + (Op.rem_i4, false) => Op.rem_i8, (Op.rem_i4, true) => Op.rem_r8, + (Op.div_un_i4, false) => Op.div_un_i8, + (Op.rem_un_i4, false) => Op.rem_un_i8, + (Op.and_i4, false) => Op.and_i8, + (Op.or_i4, false) => Op.or_i8, + (Op.xor_i4, false) => Op.xor_i8, + (Op.shl_i4, false) => Op.shl_i8, + (Op.shr_i4, false) => Op.shr_i8, + (Op.shr_un_i4, false) => Op.shr_un_i8, + (Op.ceq_i4, false) => Op.ceq_i8, (Op.ceq_i4, true) => Op.ceq_r8, + (Op.cgt_i4, false) => Op.cgt_i8, (Op.cgt_i4, true) => Op.cgt_r8, + (Op.clt_i4, false) => Op.clt_i8, (Op.clt_i4, true) => Op.clt_r8, + (Op.cgt_un_i4, false) => Op.cgt_un_i8, (Op.cgt_un_i4, true) => Op.cgt_un_r8, + (Op.clt_un_i4, false) => Op.clt_un_i8, (Op.clt_un_i4, true) => Op.clt_un_r8, + _ => throw new NotSupportedException($"IR lowering: no 64-bit form of {i4Op}"), + }; + + // R8 compare from the R4 op the call site chose — the ordered/unordered intent + // (NaN semantics through negated branches) lives in that choice, not the I4 op. + static Op WideCmpR8(Op r4Op) => r4Op switch + { + Op.ceq_r4 or Op.ceq_r4_nn => Op.ceq_r8, + Op.cgt_r4 or Op.cgt_r4_nn => Op.cgt_r8, + Op.clt_r4 or Op.clt_r4_nn => Op.clt_r8, + Op.cgt_un_r4 => Op.cgt_un_r8, + Op.clt_un_r4 => Op.clt_un_r8, + _ => throw new NotSupportedException($"IR lowering: no R8 form of {r4Op}"), + }; + + static void EmitBinop(List ir, List irToIl, (int, SType)[] stack, ref int sp, ref int frameSize, List slotTypes, List slotStructs, + Op opI4, Op opR4, Op opI4_nn, Op opR4_nn, int instrStart) + { + var (s2, t2) = stack[--sp]; + var (s1, t1) = stack[sp - 1]; + // 64-bit operands (Roslyn emits explicit convs, so pairs arrive homogeneous; + // a stray I4 operand is widened by the executor's Rd helpers). + if (t1 is SType.I8 or SType.R8 || t2 is SType.I8 or SType.R8) + { + bool isR8w = t1 == SType.R8 || t2 == SType.R8; + SType wrt = isR8w ? SType.R8 : SType.I8; + int wdst = AllocSlot(ref frameSize, slotTypes, slotStructs, wrt, null); + stack[sp - 1] = (wdst, wrt); + Emit4(ir, irToIl, Wide64(opI4, isR8w), wdst, s1, s2, instrStart); + return; + } + bool isFloat = t1 == SType.R4 || t2 == SType.R4; + SType rt = isFloat ? SType.R4 : SType.I4; + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, rt, null); + stack[sp - 1] = (dst, rt); + bool both_r4 = t1 == SType.R4 && t2 == SType.R4 && slotTypes[s1] == SType.R4 && slotTypes[s2] == SType.R4; + bool both_i4 = t1 == SType.I4 && t2 == SType.I4 && slotTypes[s1] == SType.I4 && slotTypes[s2] == SType.I4; + Op op = isFloat ? (both_r4 ? opR4_nn : opR4) : (both_i4 ? opI4_nn : opI4); + Emit4(ir, irToIl, op, dst, s1, s2, instrStart); + } + + static void EmitBinopI4(List ir, List irToIl, (int, SType)[] stack, ref int sp, ref int frameSize, List slotTypes, List slotStructs, Op opI4, Op opI4_nn, int instrStart) + { + var (s2, t2) = stack[--sp]; + var (s1, t1) = stack[sp - 1]; + // 64-bit form: and/or/xor take two I8s; shifts take (I8 value, I4 count) — either + // way the value operand's width decides. + if (t1 == SType.I8) + { + int wdst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.I8, null); + stack[sp - 1] = (wdst, SType.I8); + Emit4(ir, irToIl, Wide64(opI4, false), wdst, s1, s2, instrStart); + return; + } + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.I4, null); + stack[sp - 1] = (dst, SType.I4); + bool both_i4 = t1 == SType.I4 && t2 == SType.I4 && slotTypes[s1] == SType.I4 && slotTypes[s2] == SType.I4; + Emit4(ir, irToIl, both_i4 ? opI4_nn : opI4, dst, s1, s2, instrStart); + } + + static void EmitUnop(List ir, List irToIl, (int, SType)[] stack, ref int sp, ref int frameSize, List slotTypes, List slotStructs, Op opI4, Op opR4, Op opI4_n, Op opR4_n, int instrStart) + { + var (src, t) = stack[sp - 1]; + if (t is SType.I8 or SType.R8) + { + int wdst = AllocSlot(ref frameSize, slotTypes, slotStructs, t, null); + stack[sp - 1] = (wdst, t); + Emit3(ir, irToIl, t == SType.R8 ? Op.neg_r8 : Op.neg_i8, wdst, src, instrStart); + return; + } + bool is_r4 = t == SType.R4; + // The dst must be typed by what the op WRITES (always flat numeric), not by the source: + // an O-typed src (e.g. a boxed int flowing out of a host call) would otherwise stamp the + // dst O, and every downstream reader would look at the (never-written) ref slot. + var rt = is_r4 ? SType.R4 : SType.I4; + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, rt, null); + stack[sp - 1] = (dst, rt); + bool src_n = is_r4 ? slotTypes[src] == SType.R4 : slotTypes[src] == SType.I4; + Op op = is_r4 ? (src_n ? opR4_n : opR4) : (src_n ? opI4_n : opI4); + Emit3(ir, irToIl, op, dst, src, instrStart); + } + + static void EmitUnopI4(List ir, List irToIl, (int, SType)[] stack, ref int sp, ref int frameSize, List slotTypes, List slotStructs, Op opI4, Op opI4_n, int instrStart) + { + var (src, t) = stack[sp - 1]; + if (t == SType.I8) + { + int wdst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.I8, null); + stack[sp - 1] = (wdst, SType.I8); + Emit3(ir, irToIl, Op.not_i8, wdst, src, instrStart); + return; + } + int dst = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.I4, null); + stack[sp - 1] = (dst, SType.I4); + bool src_n = t == SType.I4 && slotTypes[src] == SType.I4; + Emit3(ir, irToIl, src_n ? opI4_n : opI4, dst, src, instrStart); + } + + static void EmitCmpBranch(List ir, List irToIl, (int, SType)[] stack, ref int sp, ref int frameSize, List slotTypes, List slotStructs, + Op cmpI4, Op cmpR4, Op cmpO, Op cmpI4_nn, Op cmpR4_nn, Op branch, List<(int, int)> patchList, int ilTarget, int instrStart, + Dictionary branchTargetDepth) + { + var (s2, t2) = stack[--sp]; + var (s1, t1) = stack[sp - 1]; + sp--; + // Both operands are consumed; the compare-branch leaves the base stack. Record the depth + // it delivers to a forward target so the join reconciles correctly (see branchTargetDepth). + if (ilTarget > instrStart) branchTargetDepth[ilTarget] = sp; + int tmp = AllocSlot(ref frameSize, slotTypes, slotStructs, SType.I4, null); + Op cmp; + if (t1 == SType.R8 || t2 == SType.R8) + cmp = WideCmpR8(cmpR4); + else if (t1 == SType.I8 || t2 == SType.I8) + cmp = Wide64(cmpI4, false); + else if (t1 == SType.R4 || t2 == SType.R4) + cmp = (t1 == SType.R4 && t2 == SType.R4 && slotTypes[s1] == SType.R4 && slotTypes[s2] == SType.R4) ? cmpR4_nn : cmpR4; + else if (t1 == SType.I4 || t2 == SType.I4) + // cmpI4 reads each operand from the correct stack at runtime (handles O/I4 mix). + cmp = (slotTypes[s1] == SType.I4 && slotTypes[s2] == SType.I4) ? cmpI4_nn : cmpI4; + else + cmp = cmpO; + Emit4(ir, irToIl, cmp, tmp, s1, s2, instrStart); + int patchIdx = ir.Count + 2; + Emit3(ir, irToIl, branch, tmp, -1, instrStart); + patchList.Add((patchIdx, ilTarget)); + } + + // Read a branch target from the IL stream: 1-byte sbyte offset for short, 4-byte int for long. + static int ReadBranchTarget(byte[] il, ref int ip, bool isShort) + { + int off = isShort ? (sbyte)il[ip++] : BitConverter.ToInt32(il, ip); + if (!isShort) ip += 4; + return ip + off; + } + + // --- IR emission helpers (all params are int; cast to uint internally) --- + + static void Emit2(List ir, List irToIl, Op op, int a, int ilOff) + { + ir.Add((uint)op); irToIl.Add(ilOff); + ir.Add((uint)a); irToIl.Add(ilOff); + } + + static void Emit3(List ir, List irToIl, Op op, int a, int b, int ilOff) + { + ir.Add((uint)op); irToIl.Add(ilOff); + ir.Add((uint)a); irToIl.Add(ilOff); + ir.Add((uint)b); irToIl.Add(ilOff); + } + + static void Emit4(List ir, List irToIl, Op op, int a, int b, int c, int ilOff) + { + ir.Add((uint)op); irToIl.Add(ilOff); + ir.Add((uint)a); irToIl.Add(ilOff); + ir.Add((uint)b); irToIl.Add(ilOff); + ir.Add((uint)c); irToIl.Add(ilOff); + } + } + + static (int Line, string Doc) FindSourceLine(ParsedMethod method, int ilOffset) + { + var pts = method.SeqPoints; + if (pts == null) return (-1, ""); + int lo = 0, hi = pts.Length - 1, result = -1; + while (lo <= hi) + { + int mid = (lo + hi) / 2; + if (pts[mid].IlOffset <= ilOffset) { result = mid; lo = mid + 1; } + else hi = mid - 1; + } + return result >= 0 ? (pts[result].Line, pts[result].Doc) : (-1, ""); + } + + static string At(ParsedMethod method, int ilOffset) + { + var (line, doc) = FindSourceLine(method, ilOffset); + if (line <= 0) return $" at IL+0x{ilOffset:X4}"; + // Keep the " at line " marker: the VM's host-call rethrow filter matches it to avoid + // appending a second location when an already-located error bubbles through nested frames. + return doc.Length > 0 ? $" at line {line} ({doc})" : $" at line {line}"; + } + + static int ReadU16(byte[] il, ref int ip) + { + int v = il[ip] | (il[ip + 1] << 8); + ip += 2; + return v; + } + + // Fill `arr` from the FieldDef's RVA blob, decoding bytes per element type. + // Returns false if the element type is non-primitive or the field has no RVA — caller + // then leaves the array zero-initialized and lets the InitializeArray no-op binding run. + // Typed-backing fills for newarr_i4/newarr_r4 array initializers: element type is statically + // Int32/Single (the lowerer only emits the typed ops for those), so only the RVA blob lookup + // remains. + static bool TryFillI4ArrayFromFieldBlob(int[] arr, ParsedAssembly asm, int fieldTok) + { + if (!TryReadFieldBlob(asm, fieldTok, arr.Length * 4, out var bytes)) return false; + for (int i = 0; i < arr.Length; i++) arr[i] = BitConverter.ToInt32(bytes, i * 4); + return true; + } + + static bool TryFillR4ArrayFromFieldBlob(float[] arr, ParsedAssembly asm, int fieldTok) + { + if (!TryReadFieldBlob(asm, fieldTok, arr.Length * 4, out var bytes)) return false; + for (int i = 0; i < arr.Length; i++) arr[i] = BitConverter.ToSingle(bytes, i * 4); + return true; + } + + // Fill a typed primitive array (bool[]/char[]/byte[]/…) from a RuntimeHelpers.InitializeArray + // field blob. The blob layout (little-endian, element-sized) matches the primitive array's + // memory, so a raw block copy is correct. + static bool TryFillTypedArrayFromFieldBlob(Array arr, int elemSize, ParsedAssembly asm, int fieldTok) + { + if (!TryReadFieldBlob(asm, fieldTok, arr.Length * elemSize, out var bytes)) return false; + Buffer.BlockCopy(bytes, 0, arr, 0, arr.Length * elemSize); + return true; + } + + static bool TryReadFieldBlob(ParsedAssembly asm, int fieldTok, int byteLen, out byte[] bytes) + { + bytes = Array.Empty(); + var fieldHandle = MetadataTokens.EntityHandle(fieldTok); + if (fieldHandle.Kind != HandleKind.FieldDefinition) return false; + var fd = asm.Reader.GetFieldDefinition((FieldDefinitionHandle)fieldHandle); + int rva = fd.GetRelativeVirtualAddress(); + if (rva == 0) return false; + var section = asm.Pe.GetSectionData(rva); + var blobReader = section.GetReader(); + bytes = blobReader.ReadBytes(byteLen); + return true; + } + + static bool TryFillArrayFromFieldBlob(object?[] arr, ParsedAssembly asm, int elemTok, int fieldTok) + { + var elemHandle = MetadataTokens.EntityHandle(elemTok); + if (elemHandle.Kind != HandleKind.TypeReference) return false; + var elemRef = asm.Reader.GetTypeReference((TypeReferenceHandle)elemHandle); + var elemName = asm.Reader.GetString(elemRef.Name); + + int elemSize = elemName switch + { + "Boolean" or "Byte" or "SByte" => 1, + "Int16" or "UInt16" or "Char" => 2, + "Int32" or "UInt32" or "Single" => 4, + "Int64" or "UInt64" or "Double" => 8, + _ => 0, + }; + if (elemSize == 0) return false; + + var fieldHandle = MetadataTokens.EntityHandle(fieldTok); + if (fieldHandle.Kind != HandleKind.FieldDefinition) return false; + var fd = asm.Reader.GetFieldDefinition((FieldDefinitionHandle)fieldHandle); + int rva = fd.GetRelativeVirtualAddress(); + if (rva == 0) return false; + + var section = asm.Pe.GetSectionData(rva); + var blobReader = section.GetReader(); + var bytes = blobReader.ReadBytes(arr.Length * elemSize); + + for (int i = 0; i < arr.Length; i++) + { + int o = i * elemSize; + arr[i] = elemName switch + { + "Boolean" => bytes[o] != 0 ? 1 : 0, // bools live as int (1/0) on the stack + "Byte" => (int)bytes[o], + "SByte" => (int)(sbyte)bytes[o], + "Int16" => (int)BitConverter.ToInt16(bytes, o), + "UInt16" => (int)BitConverter.ToUInt16(bytes, o), + "Char" => (int)BitConverter.ToChar(bytes, o), + "Int32" => BitConverter.ToInt32(bytes, o), + "UInt32" => (int)BitConverter.ToUInt32(bytes, o), + "Single" => BitConverter.ToSingle(bytes, o), + "Int64" => (object)BitConverter.ToInt64(bytes, o), + "UInt64" => (object)(long)BitConverter.ToUInt64(bytes, o), + "Double" => (object)(float)BitConverter.ToDouble(bytes, o), // float-only subset + _ => null, + }; + } + return true; + } +} + +// Simple stack-type tag (what the lowerer tracks per eval-stack slot). +// Placed at namespace level so HostBinding.cs can use it in FastCallDelegate. +// Vt = a host value type stored as contiguous bytes in numFrame, occupying +// ceil(byteSize/4) consecutive logical slot indices. Only the first slot is +// referenced; the rest are filler. byteSize and Type live in parallel +// LoweredMethod tables. See PLAN_FLAT_STRUCTS.md. +// O is first so default(SType) == SType.O. Anything that holds an SType field +// without initializing it (e.g. HostBinding.Entry.FlatReturnSType) gets the +// "no specific numeric type, use refFrame slot" default, which is what every +// caller wants. Changing this order will break any code that depends on the +// underlying byte values — none does today (no serialization, no (SType)0 casts). +internal enum SType : byte { O, I4, R4, Vt, I8, R8 } + + +// Typed return value from the Vm engine — eliminates boxing of primitive return values +// on script-to-script call paths. I4 covers both int and bool (bool stored as 0/1). +// Void (no-return) is represented by default(CallReturn): Type == I4, I4 == 0, O == null. +// The Type field disambiguates: I4 means no value or an int/bool; callers that need to +// know whether the callee was void check the calling method's IsVoid flag separately. +readonly struct CallReturn +{ + public readonly SType Type; + public readonly int I4; // valid when Type == I4 (includes bool as 0/1, and Void) + public readonly float R4; // valid when Type == R4 + public readonly long I8; // valid when Type == I8 + public readonly double R8; // valid when Type == R8 + public readonly object? O; // valid when Type == O or Vt + + CallReturn(SType t, int i4, float r4, long i8, double r8, object? o) + { Type = t; I4 = i4; R4 = r4; I8 = i8; R8 = r8; O = o; } + + public static CallReturn FromI4(int v) => new CallReturn(SType.I4, v, 0f, 0L, 0d, null); + public static CallReturn FromR4(float v) => new CallReturn(SType.R4, 0, v, 0L, 0d, null); + public static CallReturn FromI8(long v) => new CallReturn(SType.I8, 0, 0f, v, 0d, null); + public static CallReturn FromR8(double v) => new CallReturn(SType.R8, 0, 0f, 0L, v, null); + public static CallReturn FromO(object? v) => new CallReturn(SType.O, 0, 0f, 0L, 0d, v); +} +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptInterpreter.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptInterpreter.cs.meta new file mode 100644 index 0000000..11bde4e --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptInterpreter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 726e649c2ce1b774ca646a1e82fa5471 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptObject.cs b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptObject.cs new file mode 100644 index 0000000..19dc59b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptObject.cs @@ -0,0 +1,123 @@ +#nullable enable +using System; +using System.Collections.Generic; +namespace IlInterpreter.Interpreter +{ + +// Describes a script-defined class: maps field tokens to typed offsets. +internal sealed class ScriptTypeDescriptor +{ + // Non-nullable fields are always set by the descriptor-building pass in Parse; + // `= null!` marks that invariant. + public string Name = null!; + public int FieldCount; + // FieldDef metadata token → slot index in ScriptObject.Fields + // (kept for write-back path in call_host_byref; slot index = field index) + public Dictionary FieldSlots = null!; + // Per-field type tag (parallel to field declaration order 0..FieldCount-1) + public SType[] FieldTypes = null!; + // Per-field storage offset: + // I4/R4 fields: byte offset into ScriptObject.PrimBytes + // O fields: index into ScriptObject.RefSlots + // Vt fields: byte offset into ScriptObject.PrimBytes (inline storage) + public int[] FieldOffsets = null!; + public int PrimByteSize; // total size of PrimBytes array + public int RefSlotCount; // total length of RefSlots array + // Per-field struct layout, non-null only for SType.Vt fields. + // Length = FieldCount. Parallel to FieldTypes/FieldOffsets. + public HostBinding.StructLayout?[]? VtFieldLayouts; + // Per-field flag: true when field i is a SCRIPT-defined struct stored in an O slot (a value type + // masquerading as a ScriptObject reference). Non-null only when at least one such field exists. + // Parallel to FieldTypes/FieldOffsets. Used by Clone() to deep-copy nested value-type fields so a + // struct copy does not alias the source's nested structs (genuine reference fields stay shared). + public bool[]? FieldIsScriptStruct; + // Per-field descriptor of a script-struct field's own type (parallel to FieldTypes). Non-null entry + // only for a resolved script-struct field; used by ScriptObject.Create to recursively allocate the + // nested struct so a value-type field is never null (matching C#'s zero-init of value fields). + public ScriptTypeDescriptor?[]? FieldStructDescriptors; + // True when this type is a script-defined STRUCT (value type, not an enum, not a class). Used to + // zero-init the elements of `new T[n]` — a value-type array holds usable structs, not nulls. + public bool IsScriptStructValue; + + // Non-null when this script struct is BLITTABLE (no reference fields, transitively) and is + // represented FLAT: locals/args/returns live as raw bytes in Vt frame slots (the flat image is + // identical to the PrimBytes image), and only O-boundary crossings materialize a boxed + // ScriptObject via the layout's marshallers. Synthesized by the parser's flat-resolution pass. + public HostBinding.StructLayout? FlatLayout; +} + +// An instance of a script-defined class. +// Primitives (I4, R4) live in PrimBytes at their FieldOffsets[i] byte offset. +// References (O, boxed Vt) live in RefSlots at their FieldOffsets[i] ref index. +internal sealed class ScriptObject +{ + // Create and Clone (the only construction sites) always set all three fields; + // `= null!` marks that invariant. + public ScriptTypeDescriptor Type = null!; + public byte[] PrimBytes = null!; // typed primitive storage (I4/R4/bool) + public object?[] RefSlots = null!; // reference fields only (O slots) + + // Allocate an instance of a script class/struct, recursively initializing nested SCRIPT-struct + // fields to fresh zeroed instances. A value-type field is never null in C# (`new Outer()` gives a + // usable `inner`), so `a.inner.v = x` must not dereference null. Recursion terminates because + // value-type containment is acyclic (a struct cannot contain itself by value). + public static ScriptObject Create(ScriptTypeDescriptor desc) + { + var o = new ScriptObject + { + Type = desc, + PrimBytes = new byte[desc.PrimByteSize], + RefSlots = new object?[desc.RefSlotCount], + }; + var subs = desc.FieldStructDescriptors; + if (subs != null) + { + var offs = desc.FieldOffsets; + for (int i = 0; i < subs.Length; i++) + if (subs[i] != null) + o.RefSlots[offs[i]] = Create(subs[i]!); + } + return o; + } + + // Value-copy for script-struct copy semantics. Genuine reference fields keep their reference + // shared (a struct copy copies the reference, not its target) — but a NESTED SCRIPT STRUCT is + // itself a value type stored in an O slot, so it must be deep-copied recursively, or + // `b = a; b.inner.v = x` would alias a.inner. Recursion terminates because struct nesting + // is acyclic. + public ScriptObject Clone() + { + var copy = new ScriptObject + { + Type = Type, + PrimBytes = PrimBytes == null ? null! : (byte[])PrimBytes.Clone(), + RefSlots = RefSlots == null ? null! : (object?[])RefSlots.Clone(), + }; + var isSc = Type?.FieldIsScriptStruct; + if (isSc != null && copy.RefSlots != null) + { + var offs = Type!.FieldOffsets; + for (int i = 0; i < isSc.Length; i++) + { + if (!isSc[i]) continue; + int ri = offs[i]; + if ((uint)ri < (uint)copy.RefSlots.Length && copy.RefSlots[ri] is ScriptObject so) + copy.RefSlots[ri] = so.Clone(); + } + } + return copy; + } +} + +// A script-created array of FLAT structs: one byte[] backing for all elements instead of one +// ScriptObject (3+ allocations) per element. Elements are memcpy'd in/out of Vt frame slots by +// ldelem_vt/stelem_vt. Host-ABI note: like the old object?[] representation, this cannot be +// passed to a host T[] parameter — unchanged limitation. +internal sealed class ScriptVtArray +{ + public HostBinding.StructLayout Layout = null!; + public byte[] Bytes = null!; + public int Length; + public int Stride; // element size rounded up to 4 +} +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptObject.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptObject.cs.meta new file mode 100644 index 0000000..cfc7253 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/ScriptObject.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 88d8c601d0ce53c42953bc95b8b0af6c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Unity.Pipeline.IlInterpreter.asmdef b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Unity.Pipeline.IlInterpreter.asmdef new file mode 100644 index 0000000..d4f4667 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Unity.Pipeline.IlInterpreter.asmdef @@ -0,0 +1,16 @@ +{ + "name": "Unity.Pipeline.IlInterpreter", + "rootNamespace": "", + "references": [], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": true, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [ + "UNITY_EDITOR || DEVELOPMENT_BUILD || ENABLE_RUNTIME_PIPELINE" + ], + "versionDefines": [], + "noEngineReferences": false +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Unity.Pipeline.IlInterpreter.asmdef.meta b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Unity.Pipeline.IlInterpreter.asmdef.meta new file mode 100644 index 0000000..e5310cb --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Unity.Pipeline.IlInterpreter.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 3352b3594156b1b49bc408b732c23df5 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Value.cs b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Value.cs new file mode 100644 index 0000000..4f68514 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Value.cs @@ -0,0 +1,19 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace IlInterpreter.Interpreter +{ + +// A single 4-byte slot of the Vm engine's unmanaged numeric frame. The slot's static SType +// (LoweredMethod.SlotTypes) tells the executor which field is live — there is no runtime tag. +// The dispatch loop reinterprets slots via byte* casts, so the backing memory stays native (no GC). +[StructLayout(LayoutKind.Explicit, Size = 4)] +internal struct Value +{ + [FieldOffset(0)] public int I4; // int, bool (0/1), char, short — sign/zero-extended + [FieldOffset(0)] public float R4; + [FieldOffset(0)] public uint U4; // bit-exact copies (mov, Vt span words) +} +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Value.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Value.cs.meta new file mode 100644 index 0000000..8730065 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Value.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 617b9a71d914e1842b16719af056ad77 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Vm.cs b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Vm.cs new file mode 100644 index 0000000..fabc23f --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Vm.cs @@ -0,0 +1,14 @@ +#nullable enable +using System; +using System.Collections.Generic; +namespace IlInterpreter +{ + +// VM intrinsics — always present, host-independent. Like syscalls / WASI imports. +// The interpreter intercepts calls to these methods; bodies exist only so the +// methods can be referenced from script source at compile time. +static class Vm +{ + public static void Log(string message) { } +} +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Vm.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Vm.cs.meta new file mode 100644 index 0000000..e09b8b2 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/Vm.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 95648017851331b429ece1d370bdee8a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/VmEngine.cs b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/VmEngine.cs new file mode 100644 index 0000000..b2cf216 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/VmEngine.cs @@ -0,0 +1,1979 @@ +#nullable enable +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +// Use the Unsafe bundled with the package (renamed with a "UnityPipeline." prefix), not the BCL or editor copy. +using Unsafe = UnityPipeline.System.Runtime.CompilerServices.Unsafe; + +#if !NET5_0_OR_GREATER +// SkipLocalsInit polyfill for the Unity (Mono/netstandard) build — the compiler keys on the +// attribute's full name, so a local declaration works like the BCL one. +namespace System.Runtime.CompilerServices +{ + [AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct + | AttributeTargets.Interface | AttributeTargets.Constructor | AttributeTargets.Method + | AttributeTargets.Property | AttributeTargets.Event, Inherited = false)] + internal sealed class SkipLocalsInitAttribute : Attribute { } +} +#endif + +namespace IlInterpreter.Interpreter +{ + +#if ILINTERPRETER_OPSTATS +// Opcode histogram for the bench harness (IlInterpreter/tests/IlInterpreter.BenchStats). +static class VmOpStats +{ + public static readonly long[] Counts = new long[512]; + public static void Reset() => Array.Clear(Counts, 0, Counts.Length); +} +#endif + +sealed partial class ScriptInterpreter +{ + // The execution engine. Runs lowered IR over a native (unmanaged) Value frame instead of a + // managed byte[] — no GC for the frame, no per-dispatch `fixed` pin on the numeric stack. + // SkipLocalsInit: Run() is reentered on every reentrant Invoke; without this the JIT + // zero-fills its whole frame (including the 128-byte stackalloc continuation stack) per + // call — a major chunk of Mono's 5x call overhead vs CoreCLR. Every local and stackalloc + // slot below is definitely-assigned before use, so dropping .locals init is safe. + [System.Runtime.CompilerServices.SkipLocalsInit] + sealed unsafe class Vm : IDisposable + { + internal const int NumSlots = 256 * 1024; // Value slots (4 bytes each); also the lowering frame cap + internal const int RefSlots = 128 * 1024; + + // Both arenas are indexed by bp+slot, but the reference arena (_ref, RefSlots) is smaller + // than the numeric one (_num, NumSlots). A frame that fits the numeric arena can still + // overrun _ref via its RefClearLen reference slots, so every frame entry must bound BOTH. + // bp is cumulative across reentrant Invokes and nested script calls. + static bool FrameFits(int bp, LoweredMethod lm) => + (long)bp + lm.FrameSize <= NumSlots && (long)bp + lm.RefClearLen <= RefSlots; + + // Cached array Types for the ldelem/stelem exact-type dispatch. typeof(byte[]) folds to a + // constant on Mono, but IL2CPP re-resolves the array class through a metadata hashtable per + // typeof site — hoisting to static readonly makes per-element dispatch a Type ref-compare. + static readonly Type T_byteA = typeof(byte[]), T_sbyteA = typeof(sbyte[]), + T_shortA = typeof(short[]), T_ushortA = typeof(ushort[]), + T_charA = typeof(char[]), T_boolA = typeof(bool[]), + T_intA = typeof(int[]), T_uintA = typeof(uint[]), T_floatA = typeof(float[]), + T_longA = typeof(long[]), T_ulongA = typeof(ulong[]), T_doubleA = typeof(double[]); + + readonly ScriptInterpreter _owner; + readonly IFrameAllocator _alloc; + readonly Value* _num; // unmanaged numeric/Vt frame + readonly object?[] _ref; // managed reference frame (GC roots) + readonly int[] _steps = new int[1]; + bool _disposed; + + // Frame base for the NEXT Invoke: 0 at top level, bumped to the current frame's top while + // a call executes, so a reentrant Invoke (a host call that woven-dispatches back into this + // same VM) runs above the live frame instead of clobbering it at 0. + int _base; + + // Saved caller state for the iterative script-call stack: call_script/newobj_script push + // one of these and jump ip to the callee's blob region instead of recursing into Run() + // (a recursive call of the giant dispatch method cost ~120ns on Mono). Shared across + // reentrant Runs: each Run treats _framesTop at its entry as the floor, and + // Invoke*/InvokeTyped restore _framesTop in their finally. + struct SavedFrame + { + public ParsedMethod M; // caller method + public int Ip; // blob-absolute resume ip (after the call op) + public int Bp; // caller frame base + public int RetDst; // caller slot for the callee's return; -1 = discard + public int ContSp; // caller's finally-continuation stack top + // Caller slot to receive the callee's (mutated) flat-struct `this` bytes on return + // (copy-in/copy-out byref semantics for struct instance methods/ctors); -1 = none. + public int VtThisWb; + } + const int MaxCallDepth = 4096; + readonly SavedFrame[] _frames = new SavedFrame[MaxCallDepth]; + int _framesTop; + + // Poison mode (ILINTERPRETER_POISON_FRAMES=1, tests/CI only): fill the numeric frame with + // 0xCD before every top-level call so a never-written cell reads loud garbage instead of + // a plausible zero. Frame-typing bugs are silent on Mono/CoreCLR's zeroed pages but + // corrupt IL2CPP players running on recycled memory; poisoning makes every environment + // behave like the worst case. + static readonly bool s_PoisonFrames = + Environment.GetEnvironmentVariable("ILINTERPRETER_POISON_FRAMES") == "1"; + + // Execution value-trace (ILINTERPRETER_TRACE=1, dev diagnosis only): dump each IR op with its + // IL offset and the current value of its first operand/dst slot, so a divergence can be + // localized to the first step where a slot goes wrong — the value-flow view that otherwise + // has to be hand-instrumented. One well-predicted branch per op when off; zero formatting. + static readonly bool s_Trace = + Environment.GetEnvironmentVariable("ILINTERPRETER_TRACE") == "1"; + + void PoisonNumFrame() => Unsafe.InitBlockUnaligned((byte*)_num, 0xCD, (uint)(NumSlots * sizeof(Value))); + + // Formats one dispatch step for ILINTERPRETER_TRACE: IL offset + op + its operand slots' + // CURRENT values (state entering the op — a source read here is the value the op consumes; + // a dst read is its pre-op value, whose result shows up when the next op reads it). Words + // that aren't frame slots (immediates/tokens/targets) fall back to their raw int. + static void TraceStep(int ip, Op irop, uint* irP, int irLen, byte* numF, + object?[] refStack, SType[] slotT, int bp, LoweredMethod lm, ParsedMethod method) + { + int rel = ip - lm.IrStart; + int ilOff = (uint)rel < (uint)lm.IrToIlOffset.Length ? lm.IrToIlOffset[rel] : 0; + string Slot(int w) + { + if ((uint)w >= (uint)slotT.Length) return w.ToString(); + return slotT[w] switch + { + SType.I4 => $"s{w}={*(int*)(numF + w * 4)}", + SType.R4 => $"s{w}={*(float*)(numF + w * 4)}f", + _ => $"s{w}=<{refStack[bp + w] ?? "null"}>", + }; + } + string a = ip + 1 < irLen ? Slot((int)irP[ip + 1]) : ""; + string b = ip + 2 < irLen ? Slot((int)irP[ip + 2]) : ""; + string c = ip + 3 < irLen ? Slot((int)irP[ip + 3]) : ""; + string args = ""; + if (irop == Op.call_host || irop == Op.call_host_byref) + { + int argc = (int)irP[ip + 4]; + var sb = new System.Text.StringBuilder(" args=["); + for (int k = 0; k < argc; k++) { if (k > 0) sb.Append(", "); sb.Append(Slot((int)irP[ip + 5 + k])); } + sb.Append(']'); + args = sb.ToString(); + } + Console.Error.WriteLine($"[exec] {method.Name} IL+0x{ilOff:X4} {irop} [{a} | {b} | {c}]{args}"); + } + + public Vm(ScriptInterpreter owner) + { + _owner = owner; + _alloc = owner._allocator; + _num = (Value*)_alloc.Alloc(NumSlots * sizeof(Value)); + _ref = new object?[RefSlots]; + } + + public void Dispose() + { + if (_disposed) return; + _disposed = true; + _alloc.Free(_num); + } + + // Public entry: place args at the current frame base and run — the only boxing boundary. + // _base is 0 at the top level and the live frame's top during a reentrant call, so nested + // invocations never overwrite an in-progress frame. + public object? Invoke(ParsedMethod method, object?[] args) + { + var asm = _owner._parsed + ?? throw new ScriptRuntimeException("No script loaded — call Load() first"); + _steps[0] = _owner.StepLimit; + if (s_PoisonFrames && _base == 0) PoisonNumFrame(); + int bp = _base, saved = _base, savedTop = _framesTop; + _base = bp + method.Lowered.FrameSize; + try { return Box(method, Run(method, args, asm, bp)); } + finally { _base = saved; _framesTop = savedTop; } + } + + // Zero-allocation typed entries — no object?[], no arg boxing. The result is boxed once + // only if the method returns a primitive. + public object? InvokeTyped(ParsedMethod method) + { + var asm = _owner._parsed ?? throw new ScriptRuntimeException("No script loaded — call Load() first"); + _steps[0] = _owner.StepLimit; + if (s_PoisonFrames && _base == 0) PoisonNumFrame(); + var lm = method.Lowered; + int bp = _base, saved = _base, savedTop = _framesTop; + _base = bp + lm.FrameSize; + try + { + if (!FrameFits(bp, lm)) throw new ScriptRuntimeException("Script frame overflow"); + if (lm.RefClearLen > 0) Array.Clear(_ref, bp, lm.RefClearLen); + if (!method.IsStatic && _owner._instance != null) _ref[bp + (lm.ArgSlot != null ? lm.ArgSlot[0] : 0)] = _owner._instance; + return Box(method, Run(method, null, asm, bp)); + } + finally { _base = saved; _framesTop = savedTop; } + } + + // Run an instance method with an EXPLICIT receiver instead of the script singleton — + // the ScriptEnumerator bridge pumping an iterator state machine (receiver = the state + // machine ScriptObject). Mirrors InvokeTyped(); reentrancy-safe via _base. + public object? InvokeReceiver(ParsedMethod method, object receiver) + { + var asm = _owner._parsed ?? throw new ScriptRuntimeException("No script loaded — call Load() first"); + _steps[0] = _owner.StepLimit; + if (s_PoisonFrames && _base == 0) PoisonNumFrame(); + var lm = method.Lowered; + int bp = _base, saved = _base, savedTop = _framesTop; + _base = bp + lm.FrameSize; + try + { + if (!FrameFits(bp, lm)) throw new ScriptRuntimeException("Script frame overflow"); + if (lm.RefClearLen > 0) Array.Clear(_ref, bp, lm.RefClearLen); + _ref[bp + (lm.ArgSlot != null ? lm.ArgSlot[0] : 0)] = receiver; + return Box(method, Run(method, null, asm, bp)); + } + finally { _base = saved; _framesTop = savedTop; } + } + + public object? InvokeTyped(ParsedMethod method, T1 a1) + { + var asm = _owner._parsed ?? throw new ScriptRuntimeException("No script loaded — call Load() first"); + _steps[0] = _owner.StepLimit; + if (s_PoisonFrames && _base == 0) PoisonNumFrame(); + var lm = method.Lowered; + int bp = _base, saved = _base, savedTop = _framesTop; + _base = bp + lm.FrameSize; + try + { + if (!FrameFits(bp, lm)) throw new ScriptRuntimeException("Script frame overflow"); + if (lm.RefClearLen > 0) Array.Clear(_ref, bp, lm.RefClearLen); + byte* num = (byte*)_num; + int s = 0; + if (!method.IsStatic && _owner._instance != null) { _ref[bp + (lm.ArgSlot != null ? lm.ArgSlot[0] : 0)] = _owner._instance; s = 1; } + WriteTypedArg(num, _ref, lm.SlotTypes, bp, lm.ArgSlot != null && s < lm.ArgSlot.Length ? lm.ArgSlot[s] : s, a1); + return Box(method, Run(method, null, asm, bp)); + } + finally { _base = saved; _framesTop = savedTop; } + } + + public object? InvokeTyped(ParsedMethod method, T1 a1, T2 a2) + { + var asm = _owner._parsed ?? throw new ScriptRuntimeException("No script loaded — call Load() first"); + _steps[0] = _owner.StepLimit; + if (s_PoisonFrames && _base == 0) PoisonNumFrame(); + var lm = method.Lowered; + int bp = _base, saved = _base, savedTop = _framesTop; + _base = bp + lm.FrameSize; + try + { + if (!FrameFits(bp, lm)) throw new ScriptRuntimeException("Script frame overflow"); + if (lm.RefClearLen > 0) Array.Clear(_ref, bp, lm.RefClearLen); + byte* num = (byte*)_num; + int s = 0; + if (!method.IsStatic && _owner._instance != null) { _ref[bp + (lm.ArgSlot != null ? lm.ArgSlot[0] : 0)] = _owner._instance; s = 1; } + WriteTypedArg(num, _ref, lm.SlotTypes, bp, lm.ArgSlot != null && s < lm.ArgSlot.Length ? lm.ArgSlot[s] : s, a1); s++; + WriteTypedArg(num, _ref, lm.SlotTypes, bp, lm.ArgSlot != null && s < lm.ArgSlot.Length ? lm.ArgSlot[s] : s, a2); + return Box(method, Run(method, null, asm, bp)); + } + finally { _base = saved; _framesTop = savedTop; } + } + + public object? InvokeTyped(ParsedMethod method, T1 a1, T2 a2, T3 a3) + { + var asm = _owner._parsed ?? throw new ScriptRuntimeException("No script loaded — call Load() first"); + _steps[0] = _owner.StepLimit; + if (s_PoisonFrames && _base == 0) PoisonNumFrame(); + var lm = method.Lowered; + int bp = _base, saved = _base, savedTop = _framesTop; + _base = bp + lm.FrameSize; + try + { + if (!FrameFits(bp, lm)) throw new ScriptRuntimeException("Script frame overflow"); + if (lm.RefClearLen > 0) Array.Clear(_ref, bp, lm.RefClearLen); + byte* num = (byte*)_num; + int s = 0; + if (!method.IsStatic && _owner._instance != null) { _ref[bp + (lm.ArgSlot != null ? lm.ArgSlot[0] : 0)] = _owner._instance; s = 1; } + WriteTypedArg(num, _ref, lm.SlotTypes, bp, lm.ArgSlot != null && s < lm.ArgSlot.Length ? lm.ArgSlot[s] : s, a1); s++; + WriteTypedArg(num, _ref, lm.SlotTypes, bp, lm.ArgSlot != null && s < lm.ArgSlot.Length ? lm.ArgSlot[s] : s, a2); s++; + WriteTypedArg(num, _ref, lm.SlotTypes, bp, lm.ArgSlot != null && s < lm.ArgSlot.Length ? lm.ArgSlot[s] : s, a3); + return Box(method, Run(method, null, asm, bp)); + } + finally { _base = saved; _framesTop = savedTop; } + } + + static object? Box(ParsedMethod method, CallReturn cr) + { + if (method.IsVoid) return null; + // A bool-returning method stores its result as I4 but must box as bool — the lowerer + // picks the ret op from the eval-stack slot type, so a bool value that flowed through an + // I4 slot (e.g. a host op_Equality result now typed I4) would otherwise box as int and + // fault a caller's (bool) cast. + if (cr.Type == SType.I4 && method.ReturnIsBool) return cr.I4 != 0; + return cr.Type switch + { + SType.I4 => (object?)cr.I4, SType.R4 => (object?)cr.R4, + SType.I8 => cr.I8, SType.R8 => cr.R8, + _ => cr.O, + }; + } + + // Boxed value → I4 slot bits, covering the whole I4-mapped family: a delegate adapter (or + // host callback) hands args boxed as their REAL type — char/byte/short/enum — and an + // int/bool-only check silently wrote 0 (found by the delegate arg-type matrix). + static int CoerceBoxedI4(object? a) => a switch + { + int i => i, bool b => b ? 1 : 0, + char c => c, byte by => by, sbyte sb => sb, short sh => sh, ushort us => us, + uint u => unchecked((int)u), + Enum => unchecked((int)Convert.ToInt64(a)), + _ => 0, + }; + + static float CoerceBoxedR4(object? a) => + a is float f ? f : a is int i ? i : a is double d ? (float)d : CoerceBoxedI4(a); + + // Boxed value → I8, covering everything the interpreter maps to a 64-bit slot plus the + // narrower families (a host return or delegate arg can arrive boxed as any of them). + static long CoerceBoxedI8(object? a) => a switch + { + long l => l, ulong u => unchecked((long)u), + int i => i, uint u4 => u4, + bool b => b ? 1L : 0L, char c => c, + byte by => by, sbyte sb => sb, short sh => sh, ushort us => us, + float f => (long)f, double d => (long)d, + Enum => Convert.ToInt64(a), + _ => 0L, + }; + + static double CoerceBoxedR8(object? a) => a switch + { + double d => d, float f => f, + long l => l, ulong u => u, + int i => i, uint u4 => u4, + _ => CoerceBoxedI8(a), + }; + + // Writes arg `val` at the absolute frame position bp+slot (slot type indexed + // frame-relative), so a reentrant call writes into its own frame region. + static void WriteTypedArg(byte* num, object?[] r, SType[] t, int bp, int slot, T val) + { + if (slot < t.Length && t[slot] == SType.I4) + { + int iv = typeof(T) == typeof(int) ? Unsafe.As(ref val) + : typeof(T) == typeof(bool) ? (Unsafe.As(ref val) ? 1 : 0) + : CoerceBoxedI4(val); + *(int*)(num + (bp + slot) * 4) = iv; + } + else if (slot < t.Length && t[slot] == SType.R4) + { + float fv = typeof(T) == typeof(float) ? Unsafe.As(ref val) + : typeof(T) == typeof(int) ? (float)Unsafe.As(ref val) + : CoerceBoxedR4(val); + *(float*)(num + (bp + slot) * 4) = fv; + } + else if (slot < t.Length && t[slot] == SType.I8) + { + Unsafe.WriteUnaligned(num + (bp + slot) * 4, CoerceBoxedI8(val)); + } + else if (slot < t.Length && t[slot] == SType.R8) + { + Unsafe.WriteUnaligned(num + (bp + slot) * 4, CoerceBoxedR8(val)); + } + else + { + r[bp + slot] = (object?)val; + } + } + + CallReturn Run(ParsedMethod method, object?[]? args, ParsedAssembly asm, int bp) + { + var lm = method.Lowered; + // Frame overflow guard for the top-level entries (Invoke*/InvokeTyped) and for reentrant + // host-callback invokes that stack frames at a high bp. Without it a frame overrunning + // either arena writes past the backing block. Bounds both the numeric and reference + // arenas; FrameSize/RefClearLen are also capped at lowering. + if (!FrameFits(bp, lm)) + throw new ScriptRuntimeException("Script frame overflow"); + var ir = asm.IrBlob!; // all methods' IR, blob-absolute branch targets + var slotT = lm.SlotTypes; + var refStack = _ref; + byte* numF = (byte*)(_num + bp); // frame base; slot s lives at numF + s*4 + bool trace = s_Trace; // hoist the debug-trace gate out of the per-op path + + // Copy args into their frame slots (only on the outermost call). Arg index maps + // through lm.ArgSlot when flat-struct args shift the layout. + if (args != null) + { + if (lm.RefClearLen > 0) Array.Clear(refStack, bp, lm.RefClearLen); + var argSlots = lm.ArgSlot; + for (int i = 0; i < args.Length && i < method.ArgCount; i++) + { + object? a = args[i]; + int si = argSlots != null && i < argSlots.Length ? argSlots[i] : i; + var st = si < slotT.Length ? slotT[si] : SType.O; + if (st == SType.I4) + *(int*)(numF + si * 4) = CoerceBoxedI4(a); + else if (st == SType.R4) + *(float*)(numF + si * 4) = CoerceBoxedR4(a); + else if (st == SType.I8) + Unsafe.WriteUnaligned(numF + si * 4, CoerceBoxedI8(a)); + else if (st == SType.R8) + Unsafe.WriteUnaligned(numF + si * 4, CoerceBoxedR8(a)); + else if (st == SType.Vt) + UnboxVt(numF, si, lm.StructLayouts![si]!, a); // boxed ScriptObject (or null → zero) + else + refStack[bp + si] = a; + } + } + + int ip = lm.IrStart; + var steps = _steps; + + // Continuation stack for lowered try/finally: `leave` pushes the addresses to visit + // after each finally handler (outer handlers, then the leave target); each handler's + // br_cont (endfinally) pops the next. Shared by every frame of this Run (script calls + // save/restore their contSp watermark in SavedFrame), so ContMax bounds the TOTAL + // pending-finally depth across the whole script call stack. + const int ContMax = 256; + int* contStack = stackalloc int[ContMax]; + int contSp = 0; + + // Floor of the iterative call stack for THIS Run. Frames below it belong to outer + // (reentrant) Runs. Invoke*/InvokeTyped restore _framesTop on exit, including when + // an exception unwinds past us. + int frameBase = _framesTop; + var frames = _frames; + + fixed (uint* irP = ir) + { + while (true) + { + if (--steps[0] < 0) + { + int rel = ip - lm.IrStart; + int ilOff = (uint)rel < (uint)lm.IrToIlOffset.Length ? lm.IrToIlOffset[rel] : 0; + throw new ScriptRuntimeException($"Script exceeded step limit{At(method, ilOff)}"); + } + + var irop = (Op)irP[ip]; + if (trace) TraceStep(ip, irop, irP, ir.Length, numF, refStack, slotT, bp, lm, method); +#if ILINTERPRETER_OPSTATS + VmOpStats.Counts[(int)irop]++; +#endif + switch (irop) + { + case Op.nop: ip++; break; + + case Op.mov: + { + int dst = (int)irP[ip + 1], src = (int)irP[ip + 2]; + var st = slotT[src]; + var dt = slotT[dst]; + // Wide slots first: an 8-byte copy (or typed conversion) — the narrow + // matrix below would copy half the value. + if (dt == SType.I8) + { Unsafe.WriteUnaligned(numF + dst * 4, RdI8(numF, refStack, slotT, src, bp)); ip += 3; break; } + if (dt == SType.R8) + { Unsafe.WriteUnaligned(numF + dst * 4, RdR8(numF, refStack, slotT, src, bp)); ip += 3; break; } + if (st == SType.I8) + { + long wv = Unsafe.ReadUnaligned(numF + src * 4); + if (dt == SType.I4) *(int*)(numF + dst * 4) = unchecked((int)wv); + else if (dt == SType.R4) *(float*)(numF + dst * 4) = wv; + else refStack[bp + dst] = wv; + ip += 3; break; + } + if (st == SType.R8) + { + double wd = Unsafe.ReadUnaligned(numF + src * 4); + if (dt == SType.I4) *(int*)(numF + dst * 4) = (int)wd; + else if (dt == SType.R4) *(float*)(numF + dst * 4) = (float)wd; + else refStack[bp + dst] = wd; + ip += 3; break; + } + if (st != SType.O && dt != SType.O) + *(int*)(numF + dst * 4) = *(int*)(numF + src * 4); + else if (st == SType.O && dt == SType.O) + refStack[bp + dst] = refStack[bp + src]; + else if (st == SType.I4) + refStack[bp + dst] = *(int*)(numF + src * 4); + else if (st == SType.R4) + refStack[bp + dst] = *(float*)(numF + src * 4); + else if (dt == SType.I4) + { + // Full boxed-I4 family, not just int/bool: a byref write-back can + // leave a boxed enum/char/uint in the O slot (Enum.TryParse out). + *(int*)(numF + dst * 4) = CoerceBoxedI4(refStack[bp + src]); + } + else + { + *(float*)(numF + dst * 4) = CoerceBoxedR4(refStack[bp + src]); + } + ip += 3; break; + } + + case Op.clone_sc: + { + int dst = (int)irP[ip + 1], src = (int)irP[ip + 2]; + var v = refStack[bp + src]; + refStack[bp + dst] = v is ScriptObject so ? so.Clone() : v; + ip += 3; break; + } + + case Op.ldc_i4: + { + int dst = (int)irP[ip + 1]; + *(int*)(numF + dst * 4) = (int)irP[ip + 2]; + ip += 3; break; + } + case Op.ldc_r4: + { + int dst = (int)irP[ip + 1]; + uint raw = irP[ip + 2]; *(float*)(numF + dst * 4) = Unsafe.As(ref raw); + ip += 3; break; + } + case Op.ldnull: + refStack[bp + (int)irP[ip + 1]] = null; + ip += 2; break; + case Op.ldstr: + { + int dst = (int)irP[ip + 1]; + refStack[bp + dst] = lm.Strings[(int)irP[ip + 2]]; + ip += 3; break; + } + + case Op.add_i4: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; int v1=RdI4(numF,refStack,slotT,s1,bp); int v2=RdI4(numF,refStack,slotT,s2,bp); *(int*)(numF+d*4)=v1+v2; ip+=4; break; } + case Op.add_i4_nn: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; *(int*)(numF+d*4)=*(int*)(numF+s1*4)+*(int*)(numF+s2*4); ip+=4; break; } + case Op.sub_i4: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; int v1=RdI4(numF,refStack,slotT,s1,bp); int v2=RdI4(numF,refStack,slotT,s2,bp); *(int*)(numF+d*4)=v1-v2; ip+=4; break; } + case Op.sub_i4_nn: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; *(int*)(numF+d*4)=*(int*)(numF+s1*4)-*(int*)(numF+s2*4); ip+=4; break; } + case Op.mul_i4: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; int v1=RdI4(numF,refStack,slotT,s1,bp); int v2=RdI4(numF,refStack,slotT,s2,bp); *(int*)(numF+d*4)=v1*v2; ip+=4; break; } + case Op.mul_i4_nn: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; *(int*)(numF+d*4)=*(int*)(numF+s1*4) * *(int*)(numF+s2*4); ip+=4; break; } + case Op.div_i4: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; int v1=RdI4(numF,refStack,slotT,s1,bp); int v2=RdI4(numF,refStack,slotT,s2,bp); *(int*)(numF+d*4)=v1/v2; ip+=4; break; } + case Op.div_i4_nn: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; *(int*)(numF+d*4)=*(int*)(numF+s1*4) / *(int*)(numF+s2*4); ip+=4; break; } + case Op.rem_i4: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; int v1=RdI4(numF,refStack,slotT,s1,bp); int v2=RdI4(numF,refStack,slotT,s2,bp); *(int*)(numF+d*4)=v1%v2; ip+=4; break; } + case Op.rem_i4_nn: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; *(int*)(numF+d*4)=*(int*)(numF+s1*4)%*(int*)(numF+s2*4); ip+=4; break; } + case Op.neg_i4: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; int v=RdI4(numF,refStack,slotT,s,bp); *(int*)(numF+d*4)=-v; ip+=3; break; } + case Op.neg_i4_n: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; *(int*)(numF+d*4)=-*(int*)(numF+s*4); ip+=3; break; } + + case Op.add_r4: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; float v1=RdR4(numF,refStack,slotT,s1,bp); float v2=RdR4(numF,refStack,slotT,s2,bp); *(float*)(numF+d*4)=v1+v2; ip+=4; break; } + case Op.add_r4_nn: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; *(float*)(numF+d*4)=*(float*)(numF+s1*4)+*(float*)(numF+s2*4); ip+=4; break; } + case Op.sub_r4: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; float v1=RdR4(numF,refStack,slotT,s1,bp); float v2=RdR4(numF,refStack,slotT,s2,bp); *(float*)(numF+d*4)=v1-v2; ip+=4; break; } + case Op.sub_r4_nn: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; *(float*)(numF+d*4)=*(float*)(numF+s1*4)-*(float*)(numF+s2*4); ip+=4; break; } + case Op.mul_r4: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; float v1=RdR4(numF,refStack,slotT,s1,bp); float v2=RdR4(numF,refStack,slotT,s2,bp); *(float*)(numF+d*4)=v1*v2; ip+=4; break; } + case Op.mul_r4_nn: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; *(float*)(numF+d*4)=*(float*)(numF+s1*4) * *(float*)(numF+s2*4); ip+=4; break; } + case Op.div_r4: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; float v1=RdR4(numF,refStack,slotT,s1,bp); float v2=RdR4(numF,refStack,slotT,s2,bp); *(float*)(numF+d*4)=v1/v2; ip+=4; break; } + case Op.div_r4_nn: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; *(float*)(numF+d*4)=*(float*)(numF+s1*4) / *(float*)(numF+s2*4); ip+=4; break; } + case Op.rem_r4: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; float v1=RdR4(numF,refStack,slotT,s1,bp); float v2=RdR4(numF,refStack,slotT,s2,bp); *(float*)(numF+d*4)=v1%v2; ip+=4; break; } + case Op.rem_r4_nn: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; *(float*)(numF+d*4)=*(float*)(numF+s1*4)%*(float*)(numF+s2*4); ip+=4; break; } + case Op.neg_r4: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; float v=RdR4(numF,refStack,slotT,s,bp); *(float*)(numF+d*4)=-v; ip+=3; break; } + case Op.neg_r4_n: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; *(float*)(numF+d*4)=-*(float*)(numF+s*4); ip+=3; break; } + + case Op.and_i4: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; int v1=RdI4(numF,refStack,slotT,s1,bp); int v2=RdI4(numF,refStack,slotT,s2,bp); *(int*)(numF+d*4)=v1&v2; ip+=4; break; } + case Op.and_i4_nn: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; *(int*)(numF+d*4)=*(int*)(numF+s1*4)&*(int*)(numF+s2*4); ip+=4; break; } + case Op.or_i4: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; int v1=RdI4(numF,refStack,slotT,s1,bp); int v2=RdI4(numF,refStack,slotT,s2,bp); *(int*)(numF+d*4)=v1|v2; ip+=4; break; } + case Op.or_i4_nn: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; *(int*)(numF+d*4)=*(int*)(numF+s1*4)|*(int*)(numF+s2*4); ip+=4; break; } + case Op.xor_i4: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; int v1=RdI4(numF,refStack,slotT,s1,bp); int v2=RdI4(numF,refStack,slotT,s2,bp); *(int*)(numF+d*4)=v1^v2; ip+=4; break; } + case Op.xor_i4_nn: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; *(int*)(numF+d*4)=*(int*)(numF+s1*4)^*(int*)(numF+s2*4); ip+=4; break; } + case Op.not_i4: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; int v=RdI4(numF,refStack,slotT,s,bp); *(int*)(numF+d*4)=~v; ip+=3; break; } + case Op.not_i4_n: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; *(int*)(numF+d*4)=~*(int*)(numF+s*4); ip+=3; break; } + case Op.shl_i4: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; int v1=RdI4(numF,refStack,slotT,s1,bp); int v2=RdI4(numF,refStack,slotT,s2,bp); *(int*)(numF+d*4)=v1<>v2; ip+=4; break; } + case Op.shr_i4_nn: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; *(int*)(numF+d*4)=*(int*)(numF+s1*4)>>*(int*)(numF+s2*4); ip+=4; break; } + case Op.shr_un_i4: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; int v1=RdI4(numF,refStack,slotT,s1,bp); int v2=RdI4(numF,refStack,slotT,s2,bp); *(int*)(numF+d*4)=(int)((uint)v1>>v2); ip+=4; break; } + case Op.shr_un_i4_nn: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; *(int*)(numF+d*4)=(int)((uint)*(int*)(numF+s1*4)>>*(int*)(numF+s2*4)); ip+=4; break; } + case Op.div_un_i4: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; int v1=RdI4(numF,refStack,slotT,s1,bp); int v2=RdI4(numF,refStack,slotT,s2,bp); *(int*)(numF+d*4)=(int)((uint)v1/(uint)v2); ip+=4; break; } + case Op.div_un_i4_nn: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; *(int*)(numF+d*4)=(int)((uint)*(int*)(numF+s1*4)/(uint)*(int*)(numF+s2*4)); ip+=4; break; } + case Op.rem_un_i4: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; int v1=RdI4(numF,refStack,slotT,s1,bp); int v2=RdI4(numF,refStack,slotT,s2,bp); *(int*)(numF+d*4)=(int)((uint)v1%(uint)v2); ip+=4; break; } + case Op.rem_un_i4_nn: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; *(int*)(numF+d*4)=(int)((uint)*(int*)(numF+s1*4)%(uint)*(int*)(numF+s2*4)); ip+=4; break; } + + // --- 64-bit family. Wide slots: Unsafe.Read/WriteUnaligned — a slot's + // byte offset is only 4-aligned. Operands read through Rd helpers so a + // stray I4/boxed operand coerces instead of reading garbage. + case Op.ldc_i8: { int d=(int)irP[ip+1]; ulong v=(ulong)irP[ip+2]|((ulong)irP[ip+3]<<32); Unsafe.WriteUnaligned(numF+d*4, unchecked((long)v)); ip+=4; break; } + case Op.ldc_r8: { int d=(int)irP[ip+1]; ulong v=(ulong)irP[ip+2]|((ulong)irP[ip+3]<<32); Unsafe.WriteUnaligned(numF+d*4, BitConverter.Int64BitsToDouble(unchecked((long)v))); ip+=4; break; } + case Op.add_i8: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, RdI8(numF,refStack,slotT,(int)irP[ip+2],bp) + RdI8(numF,refStack,slotT,(int)irP[ip+3],bp)); ip+=4; break; } + case Op.sub_i8: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, RdI8(numF,refStack,slotT,(int)irP[ip+2],bp) - RdI8(numF,refStack,slotT,(int)irP[ip+3],bp)); ip+=4; break; } + case Op.mul_i8: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, RdI8(numF,refStack,slotT,(int)irP[ip+2],bp) * RdI8(numF,refStack,slotT,(int)irP[ip+3],bp)); ip+=4; break; } + case Op.div_i8: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, RdI8(numF,refStack,slotT,(int)irP[ip+2],bp) / RdI8(numF,refStack,slotT,(int)irP[ip+3],bp)); ip+=4; break; } + case Op.rem_i8: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, RdI8(numF,refStack,slotT,(int)irP[ip+2],bp) % RdI8(numF,refStack,slotT,(int)irP[ip+3],bp)); ip+=4; break; } + case Op.div_un_i8: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, unchecked((long)((ulong)RdI8(numF,refStack,slotT,(int)irP[ip+2],bp) / (ulong)RdI8(numF,refStack,slotT,(int)irP[ip+3],bp)))); ip+=4; break; } + case Op.rem_un_i8: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, unchecked((long)((ulong)RdI8(numF,refStack,slotT,(int)irP[ip+2],bp) % (ulong)RdI8(numF,refStack,slotT,(int)irP[ip+3],bp)))); ip+=4; break; } + case Op.and_i8: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, RdI8(numF,refStack,slotT,(int)irP[ip+2],bp) & RdI8(numF,refStack,slotT,(int)irP[ip+3],bp)); ip+=4; break; } + case Op.or_i8: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, RdI8(numF,refStack,slotT,(int)irP[ip+2],bp) | RdI8(numF,refStack,slotT,(int)irP[ip+3],bp)); ip+=4; break; } + case Op.xor_i8: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, RdI8(numF,refStack,slotT,(int)irP[ip+2],bp) ^ RdI8(numF,refStack,slotT,(int)irP[ip+3],bp)); ip+=4; break; } + case Op.shl_i8: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, RdI8(numF,refStack,slotT,(int)irP[ip+2],bp) << RdI4(numF,refStack,slotT,(int)irP[ip+3],bp)); ip+=4; break; } + case Op.shr_i8: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, RdI8(numF,refStack,slotT,(int)irP[ip+2],bp) >> RdI4(numF,refStack,slotT,(int)irP[ip+3],bp)); ip+=4; break; } + case Op.shr_un_i8: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, unchecked((long)((ulong)RdI8(numF,refStack,slotT,(int)irP[ip+2],bp) >> RdI4(numF,refStack,slotT,(int)irP[ip+3],bp)))); ip+=4; break; } + case Op.neg_i8: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, -RdI8(numF,refStack,slotT,(int)irP[ip+2],bp)); ip+=3; break; } + case Op.not_i8: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, ~RdI8(numF,refStack,slotT,(int)irP[ip+2],bp)); ip+=3; break; } + case Op.add_r8: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, RdR8(numF,refStack,slotT,(int)irP[ip+2],bp) + RdR8(numF,refStack,slotT,(int)irP[ip+3],bp)); ip+=4; break; } + case Op.sub_r8: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, RdR8(numF,refStack,slotT,(int)irP[ip+2],bp) - RdR8(numF,refStack,slotT,(int)irP[ip+3],bp)); ip+=4; break; } + case Op.mul_r8: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, RdR8(numF,refStack,slotT,(int)irP[ip+2],bp) * RdR8(numF,refStack,slotT,(int)irP[ip+3],bp)); ip+=4; break; } + case Op.div_r8: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, RdR8(numF,refStack,slotT,(int)irP[ip+2],bp) / RdR8(numF,refStack,slotT,(int)irP[ip+3],bp)); ip+=4; break; } + case Op.rem_r8: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, RdR8(numF,refStack,slotT,(int)irP[ip+2],bp) % RdR8(numF,refStack,slotT,(int)irP[ip+3],bp)); ip+=4; break; } + case Op.neg_r8: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, -RdR8(numF,refStack,slotT,(int)irP[ip+2],bp)); ip+=3; break; } + case Op.ceq_i8: { int d=(int)irP[ip+1]; *(int*)(numF+d*4) = RdI8(numF,refStack,slotT,(int)irP[ip+2],bp) == RdI8(numF,refStack,slotT,(int)irP[ip+3],bp) ? 1 : 0; ip+=4; break; } + case Op.cgt_i8: { int d=(int)irP[ip+1]; *(int*)(numF+d*4) = RdI8(numF,refStack,slotT,(int)irP[ip+2],bp) > RdI8(numF,refStack,slotT,(int)irP[ip+3],bp) ? 1 : 0; ip+=4; break; } + case Op.clt_i8: { int d=(int)irP[ip+1]; *(int*)(numF+d*4) = RdI8(numF,refStack,slotT,(int)irP[ip+2],bp) < RdI8(numF,refStack,slotT,(int)irP[ip+3],bp) ? 1 : 0; ip+=4; break; } + case Op.cgt_un_i8: { int d=(int)irP[ip+1]; *(int*)(numF+d*4) = (ulong)RdI8(numF,refStack,slotT,(int)irP[ip+2],bp) > (ulong)RdI8(numF,refStack,slotT,(int)irP[ip+3],bp) ? 1 : 0; ip+=4; break; } + case Op.clt_un_i8: { int d=(int)irP[ip+1]; *(int*)(numF+d*4) = (ulong)RdI8(numF,refStack,slotT,(int)irP[ip+2],bp) < (ulong)RdI8(numF,refStack,slotT,(int)irP[ip+3],bp) ? 1 : 0; ip+=4; break; } + case Op.ceq_r8: { int d=(int)irP[ip+1]; *(int*)(numF+d*4) = RdR8(numF,refStack,slotT,(int)irP[ip+2],bp) == RdR8(numF,refStack,slotT,(int)irP[ip+3],bp) ? 1 : 0; ip+=4; break; } + case Op.cgt_r8: { int d=(int)irP[ip+1]; *(int*)(numF+d*4) = RdR8(numF,refStack,slotT,(int)irP[ip+2],bp) > RdR8(numF,refStack,slotT,(int)irP[ip+3],bp) ? 1 : 0; ip+=4; break; } + case Op.clt_r8: { int d=(int)irP[ip+1]; *(int*)(numF+d*4) = RdR8(numF,refStack,slotT,(int)irP[ip+2],bp) < RdR8(numF,refStack,slotT,(int)irP[ip+3],bp) ? 1 : 0; ip+=4; break; } + // Unordered: true when NaN participates — IL semantics for negated float branches. + case Op.cgt_un_r8: { int d=(int)irP[ip+1]; double a8=RdR8(numF,refStack,slotT,(int)irP[ip+2],bp), b8=RdR8(numF,refStack,slotT,(int)irP[ip+3],bp); *(int*)(numF+d*4) = (a8 > b8 || double.IsNaN(a8) || double.IsNaN(b8)) ? 1 : 0; ip+=4; break; } + case Op.clt_un_r8: { int d=(int)irP[ip+1]; double a8=RdR8(numF,refStack,slotT,(int)irP[ip+2],bp), b8=RdR8(numF,refStack,slotT,(int)irP[ip+3],bp); *(int*)(numF+d*4) = (a8 < b8 || double.IsNaN(a8) || double.IsNaN(b8)) ? 1 : 0; ip+=4; break; } + case Op.conv_i8_i4: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, (long)RdI4(numF,refStack,slotT,(int)irP[ip+2],bp)); ip+=3; break; } + case Op.conv_i8_u4: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, (long)(uint)RdI4(numF,refStack,slotT,(int)irP[ip+2],bp)); ip+=3; break; } + case Op.conv_i4_i8: { int d=(int)irP[ip+1]; *(int*)(numF+d*4) = unchecked((int)RdI8(numF,refStack,slotT,(int)irP[ip+2],bp)); ip+=3; break; } + case Op.conv_i8_r4: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, (long)RdR4(numF,refStack,slotT,(int)irP[ip+2],bp)); ip+=3; break; } + case Op.conv_r4_i8: { int d=(int)irP[ip+1]; *(float*)(numF+d*4) = RdI8(numF,refStack,slotT,(int)irP[ip+2],bp); ip+=3; break; } + case Op.conv_i8_r8: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, (long)RdR8(numF,refStack,slotT,(int)irP[ip+2],bp)); ip+=3; break; } + case Op.conv_r8_i8: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, (double)RdI8(numF,refStack,slotT,(int)irP[ip+2],bp)); ip+=3; break; } + case Op.conv_r8_r4: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, (double)RdR4(numF,refStack,slotT,(int)irP[ip+2],bp)); ip+=3; break; } + case Op.conv_r4_r8: { int d=(int)irP[ip+1]; *(float*)(numF+d*4) = (float)RdR8(numF,refStack,slotT,(int)irP[ip+2],bp); ip+=3; break; } + case Op.conv_r8_i4: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, (double)RdI4(numF,refStack,slotT,(int)irP[ip+2],bp)); ip+=3; break; } + case Op.conv_i4_r8: { int d=(int)irP[ip+1]; *(int*)(numF+d*4) = (int)RdR8(numF,refStack,slotT,(int)irP[ip+2],bp); ip+=3; break; } + case Op.conv_r8_u8: { int d=(int)irP[ip+1]; Unsafe.WriteUnaligned(numF+d*4, (double)(ulong)RdI8(numF,refStack,slotT,(int)irP[ip+2],bp)); ip+=3; break; } + case Op.brtrue_i8: { int cs=(int)irP[ip+1]; ip = RdI8(numF,refStack,slotT,cs,bp) != 0 ? (int)irP[ip+2] : ip+3; break; } + case Op.brfalse_i8: { int cs=(int)irP[ip+1]; ip = RdI8(numF,refStack,slotT,cs,bp) == 0 ? (int)irP[ip+2] : ip+3; break; } + + case Op.ceq_i4: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; int v1=RdI4(numF,refStack,slotT,s1,bp); int v2=RdI4(numF,refStack,slotT,s2,bp); *(int*)(numF+d*4)=v1==v2?1:0; ip+=4; break; } + case Op.ceq_i4_nn: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; *(int*)(numF+d*4)=*(int*)(numF+s1*4)==*(int*)(numF+s2*4)?1:0; ip+=4; break; } + case Op.cgt_i4: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; int v1=RdI4(numF,refStack,slotT,s1,bp); int v2=RdI4(numF,refStack,slotT,s2,bp); *(int*)(numF+d*4)=v1>v2?1:0; ip+=4; break; } + case Op.cgt_i4_nn: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; *(int*)(numF+d*4)=*(int*)(numF+s1*4)>*(int*)(numF+s2*4)?1:0; ip+=4; break; } + case Op.clt_i4: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; int v1=RdI4(numF,refStack,slotT,s1,bp); int v2=RdI4(numF,refStack,slotT,s2,bp); *(int*)(numF+d*4)=v1(uint)v2?1:0; ip+=4; break; } + case Op.cgt_un_i4_nn: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; *(int*)(numF+d*4)=(uint)*(int*)(numF+s1*4)>(uint)*(int*)(numF+s2*4)?1:0; ip+=4; break; } + case Op.clt_un_i4: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; int v1=RdI4(numF,refStack,slotT,s1,bp); int v2=RdI4(numF,refStack,slotT,s2,bp); *(int*)(numF+d*4)=(uint)v1<(uint)v2?1:0; ip+=4; break; } + case Op.clt_un_i4_nn: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; *(int*)(numF+d*4)=(uint)*(int*)(numF+s1*4)<(uint)*(int*)(numF+s2*4)?1:0; ip+=4; break; } + + case Op.ceq_r4: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; float v1=RdR4(numF,refStack,slotT,s1,bp); float v2=RdR4(numF,refStack,slotT,s2,bp); *(int*)(numF+d*4)=v1==v2?1:0; ip+=4; break; } + case Op.ceq_r4_nn: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; *(int*)(numF+d*4)=*(float*)(numF+s1*4)==*(float*)(numF+s2*4)?1:0; ip+=4; break; } + case Op.cgt_r4: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; float v1=RdR4(numF,refStack,slotT,s1,bp); float v2=RdR4(numF,refStack,slotT,s2,bp); *(int*)(numF+d*4)=v1>v2?1:0; ip+=4; break; } + case Op.cgt_r4_nn: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; *(int*)(numF+d*4)=*(float*)(numF+s1*4)>*(float*)(numF+s2*4)?1:0; ip+=4; break; } + case Op.clt_r4: { int d=(int)irP[ip+1],s1=(int)irP[ip+2],s2=(int)irP[ip+3]; float v1=RdR4(numF,refStack,slotT,s1,bp); float v2=RdR4(numF,refStack,slotT,s2,bp); *(int*)(numF+d*4)=v1=v2)?1:0; ip+=4; break; } + + // --- Operand-immediate forms (_nk) --- + case Op.add_i4_nk: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; *(int*)(numF+d*4)=*(int*)(numF+s*4)+(int)irP[ip+3]; ip+=4; break; } + case Op.add_r4_nk: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; uint k=irP[ip+3]; *(float*)(numF+d*4)=*(float*)(numF+s*4)+Unsafe.As(ref k); ip+=4; break; } + case Op.sub_i4_nk: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; *(int*)(numF+d*4)=*(int*)(numF+s*4)-(int)irP[ip+3]; ip+=4; break; } + case Op.sub_r4_nk: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; uint k=irP[ip+3]; *(float*)(numF+d*4)=*(float*)(numF+s*4)-Unsafe.As(ref k); ip+=4; break; } + case Op.mul_r4_nk: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; uint k=irP[ip+3]; *(float*)(numF+d*4)=*(float*)(numF+s*4)*Unsafe.As(ref k); ip+=4; break; } + case Op.clt_i4_nk: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; *(int*)(numF+d*4)=*(int*)(numF+s*4)<(int)irP[ip+3]?1:0; ip+=4; break; } + case Op.clt_r4_nk: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; uint k=irP[ip+3]; *(int*)(numF+d*4)=*(float*)(numF+s*4)(ref k)?1:0; ip+=4; break; } + case Op.cgt_i4_nk: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; *(int*)(numF+d*4)=*(int*)(numF+s*4)>(int)irP[ip+3]?1:0; ip+=4; break; } + case Op.cgt_r4_nk: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; uint k=irP[ip+3]; *(int*)(numF+d*4)=*(float*)(numF+s*4)>Unsafe.As(ref k)?1:0; ip+=4; break; } + case Op.ceq_i4_nk: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; *(int*)(numF+d*4)=*(int*)(numF+s*4)==(int)irP[ip+3]?1:0; ip+=4; break; } + case Op.mul_i4_nk: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; *(int*)(numF+d*4)=*(int*)(numF+s*4)*(int)irP[ip+3]; ip+=4; break; } + case Op.div_i4_nk: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; *(int*)(numF+d*4)=*(int*)(numF+s*4)/(int)irP[ip+3]; ip+=4; break; } + case Op.rem_i4_nk: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; *(int*)(numF+d*4)=*(int*)(numF+s*4)%(int)irP[ip+3]; ip+=4; break; } + case Op.and_i4_nk: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; *(int*)(numF+d*4)=*(int*)(numF+s*4)&(int)irP[ip+3]; ip+=4; break; } + case Op.or_i4_nk: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; *(int*)(numF+d*4)=*(int*)(numF+s*4)|(int)irP[ip+3]; ip+=4; break; } + case Op.xor_i4_nk: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; *(int*)(numF+d*4)=*(int*)(numF+s*4)^(int)irP[ip+3]; ip+=4; break; } + case Op.shl_i4_nk: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; *(int*)(numF+d*4)=*(int*)(numF+s*4)<<(int)irP[ip+3]; ip+=4; break; } + case Op.shr_i4_nk: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; *(int*)(numF+d*4)=*(int*)(numF+s*4)>>(int)irP[ip+3]; ip+=4; break; } + case Op.shr_un_i4_nk: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; *(int*)(numF+d*4)=(int)((uint)*(int*)(numF+s*4)>>(int)irP[ip+3]); ip+=4; break; } + case Op.div_r4_nk: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; uint k=irP[ip+3]; *(float*)(numF+d*4)=*(float*)(numF+s*4)/Unsafe.As(ref k); ip+=4; break; } + case Op.ceq_r4_nk: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; uint k=irP[ip+3]; *(int*)(numF+d*4)=*(float*)(numF+s*4)==Unsafe.As(ref k)?1:0; ip+=4; break; } + + // --- Fused compare-and-branch --- + case Op.blt_i4_nn: { int s1=(int)irP[ip+1],s2=(int)irP[ip+2]; int t=(int)irP[ip+3]; if (*(int*)(numF+s1*4) < *(int*)(numF+s2*4)) ip = t; else ip += 4; break; } + case Op.blt_i4_nk: { int s=(int)irP[ip+1]; int k=(int)irP[ip+2]; int t=(int)irP[ip+3]; if (*(int*)(numF+s*4) < k) ip = t; else ip += 4; break; } + case Op.bgt_r4_nn: { int s1=(int)irP[ip+1],s2=(int)irP[ip+2]; int t=(int)irP[ip+3]; if (*(float*)(numF+s1*4) > *(float*)(numF+s2*4)) ip = t; else ip += 4; break; } + case Op.bgt_r4_nk: { int s=(int)irP[ip+1]; uint kk=irP[ip+2]; int t=(int)irP[ip+3]; if (*(float*)(numF+s*4) > Unsafe.As(ref kk)) ip = t; else ip += 4; break; } + case Op.beq_i4_nn: { int s1=(int)irP[ip+1],s2=(int)irP[ip+2]; int t=(int)irP[ip+3]; if (*(int*)(numF+s1*4) == *(int*)(numF+s2*4)) ip = t; else ip += 4; break; } + case Op.beq_i4_nk: { int s=(int)irP[ip+1]; int k=(int)irP[ip+2]; int t=(int)irP[ip+3]; if (*(int*)(numF+s*4) == k) ip = t; else ip += 4; break; } + case Op.bne_i4_nn: { int s1=(int)irP[ip+1],s2=(int)irP[ip+2]; int t=(int)irP[ip+3]; if (*(int*)(numF+s1*4) != *(int*)(numF+s2*4)) ip = t; else ip += 4; break; } + case Op.bne_i4_nk: { int s=(int)irP[ip+1]; int k=(int)irP[ip+2]; int t=(int)irP[ip+3]; if (*(int*)(numF+s*4) != k) ip = t; else ip += 4; break; } + + // --- For-loop super-instruction --- + case Op.for_i4_nk: + { + int s=(int)irP[ip+1]; int limit=(int)irP[ip+2]; int t=(int)irP[ip+3]; + int v = *(int*)(numF+s*4) + 1; + *(int*)(numF+s*4) = v; + if (v < limit) ip = t; else ip += 4; + break; + } + + case Op.ceq_o: + { + int d=(int)irP[ip+1]; + var a=refStack[bp + (int)irP[ip+2]]; var b=refStack[bp + (int)irP[ip+3]]; + // C# `==` on reference/object operands is reference equality (value types go + // through op_Equality, a host call). Object.Equals would value-compare two + // distinct boxes of the same primitive as equal — diverging from C#. + *(int*)(numF+d*4)=ReferenceEquals(a,b)?1:0; ip+=4; break; + } + case Op.cgt_un_o: + { + int d=(int)irP[ip+1]; + *(int*)(numF+d*4)=refStack[bp + (int)irP[ip+2]] != null ? 1 : 0; ip+=4; break; + } + + case Op.br: ip = (int)irP[ip + 1]; break; + case Op.push_cont: + { + if (contSp >= ContMax) { int il=(uint)(ip-lm.IrStart)<(uint)lm.IrToIlOffset.Length?lm.IrToIlOffset[ip-lm.IrStart]:0; throw new ScriptRuntimeException($"finally nesting exceeds {ContMax}{At(method, il)}"); } + contStack[contSp++] = (int)irP[ip + 1]; + ip += 2; break; + } + case Op.br_cont: + { + if (contSp == 0) { int il=(uint)(ip-lm.IrStart)<(uint)lm.IrToIlOffset.Length?lm.IrToIlOffset[ip-lm.IrStart]:0; throw new ScriptRuntimeException($"endfinally with no pending continuation{At(method, il)}"); } + ip = contStack[--contSp]; + break; + } + case Op.brtrue_i4: + { + int cond=(int)irP[ip+1]; int target=(int)irP[ip+2]; + ip = *(int*)(numF+cond*4) != 0 ? target : ip + 3; break; + } + case Op.brfalse_i4: + { + int cond=(int)irP[ip+1]; int target=(int)irP[ip+2]; + ip = *(int*)(numF+cond*4) == 0 ? target : ip + 3; break; + } + case Op.brtrue_o: + { + int cond=(int)irP[ip+1]; int target=(int)irP[ip+2]; + // Pure REFERENCE test. Verified IL only puts references (or boxes) in + // an O-typed condition, and a box is non-null no matter its value — + // value-testing here made `(object)0 == null` true and flipped isinst + // results whose matched box held 0/false (found by fuzzing). Value-typed + // conditions run through brtrue_i4/brfalse_i4 instead. + ip = refStack[bp + cond] != null ? target : ip + 3; break; + } + case Op.brfalse_o: + { + int cond=(int)irP[ip+1]; int target=(int)irP[ip+2]; + // Pure reference test — see brtrue_o. + ip = refStack[bp + cond] == null ? target : ip + 3; break; + } + + case Op.conv_i4_r4: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; int sv=RdI4(numF,refStack,slotT,s,bp); *(float*)(numF+d*4)=(float)sv; ip+=3; break; } + case Op.conv_r4_i4: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; float sv=RdR4(numF,refStack,slotT,s,bp); *(int*)(numF+d*4)=(int)sv; ip+=3; break; } + case Op.conv_i4_i1: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; int sv=RdI4(numF,refStack,slotT,s,bp); *(int*)(numF+d*4)=(int)(sbyte)sv; ip+=3; break; } + case Op.conv_i4_u1: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; int sv=RdI4(numF,refStack,slotT,s,bp); *(int*)(numF+d*4)=(int)(byte)sv; ip+=3; break; } + case Op.conv_i4_i2: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; int sv=RdI4(numF,refStack,slotT,s,bp); *(int*)(numF+d*4)=(int)(short)sv; ip+=3; break; } + case Op.conv_i4_u2: { int d=(int)irP[ip+1],s=(int)irP[ip+2]; int sv=RdI4(numF,refStack,slotT,s,bp); *(int*)(numF+d*4)=(int)(ushort)sv; ip+=3; break; } + + // A ret either leaves Run (call stack at this Run's floor) or pops the caller + // frame: read the return value from the CALLEE frame first, switch locals back + // to the caller, then store into the caller's RetDst slot. A primitive return + // into an O dst stays null; an O return into a numeric dst reads 0. + case Op.ret_void: + { + if (_framesTop == frameBase) return default; + var f = frames[--_framesTop]; + byte* wbSrc = null; int wbSize = 0; + if (f.VtThisWb >= 0) + { + int thisSlot = lm.ArgSlot != null ? lm.ArgSlot[0] : 0; + wbSrc = numF + thisSlot * 4; wbSize = lm.StructLayouts![thisSlot]!.Size; + } + method = f.M; lm = method.Lowered; slotT = lm.SlotTypes; bp = f.Bp; + numF = (byte*)(_num + bp); ip = f.Ip; contSp = f.ContSp; + _base = bp + lm.FrameSize; + if (wbSize > 0) Buffer.MemoryCopy(wbSrc, numF + f.VtThisWb * 4, wbSize, wbSize); + if (f.RetDst != -1) + { + var st = slotT[f.RetDst]; + if (st == SType.I4) *(int*)(numF + f.RetDst * 4) = 0; + else if (st == SType.R4) *(float*)(numF + f.RetDst * 4) = 0f; + else refStack[bp + f.RetDst] = null; + } + break; + } + case Op.ret_i4: + { + int s=(int)irP[ip+1]; var t=slotT[s]; + int v=t==SType.I4?*(int*)(numF+s*4):t==SType.R4?(int)*(float*)(numF+s*4):CoerceBoxedI4(refStack[bp + s]); + if (_framesTop == frameBase) return CallReturn.FromI4(v); + var f = frames[--_framesTop]; + byte* wbSrc = null; int wbSize = 0; + if (f.VtThisWb >= 0) + { + int thisSlot = lm.ArgSlot != null ? lm.ArgSlot[0] : 0; + wbSrc = numF + thisSlot * 4; wbSize = lm.StructLayouts![thisSlot]!.Size; + } + method = f.M; lm = method.Lowered; slotT = lm.SlotTypes; bp = f.Bp; + numF = (byte*)(_num + bp); ip = f.Ip; contSp = f.ContSp; + _base = bp + lm.FrameSize; + if (wbSize > 0) Buffer.MemoryCopy(wbSrc, numF + f.VtThisWb * 4, wbSize, wbSize); + if (f.RetDst != -1) + { + var st = slotT[f.RetDst]; + if (st == SType.I4) *(int*)(numF + f.RetDst * 4) = v; + else if (st == SType.R4) *(float*)(numF + f.RetDst * 4) = (float)v; + else if (st == SType.I8) Unsafe.WriteUnaligned(numF + f.RetDst * 4, (long)v); + else if (st == SType.R8) Unsafe.WriteUnaligned(numF + f.RetDst * 4, (double)v); + else refStack[bp + f.RetDst] = v; // O-typed dst: box, don't drop + } + break; + } + case Op.ret_r4: + { + int s=(int)irP[ip+1]; var t=slotT[s]; + float v=t==SType.R4?*(float*)(numF+s*4):t==SType.I4?(float)*(int*)(numF+s*4):CoerceBoxedR4(refStack[bp + s]); + if (_framesTop == frameBase) return CallReturn.FromR4(v); + var f = frames[--_framesTop]; + byte* wbSrc = null; int wbSize = 0; + if (f.VtThisWb >= 0) + { + int thisSlot = lm.ArgSlot != null ? lm.ArgSlot[0] : 0; + wbSrc = numF + thisSlot * 4; wbSize = lm.StructLayouts![thisSlot]!.Size; + } + method = f.M; lm = method.Lowered; slotT = lm.SlotTypes; bp = f.Bp; + numF = (byte*)(_num + bp); ip = f.Ip; contSp = f.ContSp; + _base = bp + lm.FrameSize; + if (wbSize > 0) Buffer.MemoryCopy(wbSrc, numF + f.VtThisWb * 4, wbSize, wbSize); + if (f.RetDst != -1) + { + var st = slotT[f.RetDst]; + if (st == SType.I4) *(int*)(numF + f.RetDst * 4) = (int)v; + else if (st == SType.R4) *(float*)(numF + f.RetDst * 4) = v; + else if (st == SType.I8) Unsafe.WriteUnaligned(numF + f.RetDst * 4, (long)v); + else if (st == SType.R8) Unsafe.WriteUnaligned(numF + f.RetDst * 4, (double)v); + else refStack[bp + f.RetDst] = v; // O-typed dst: box, don't drop + } + break; + } + case Op.ret_i8: + { + int s=(int)irP[ip+1]; + long v=RdI8(numF,refStack,slotT,s,bp); + if (_framesTop == frameBase) return CallReturn.FromI8(v); + var f = frames[--_framesTop]; + byte* wbSrc = null; int wbSize = 0; + if (f.VtThisWb >= 0) + { + int thisSlot = lm.ArgSlot != null ? lm.ArgSlot[0] : 0; + wbSrc = numF + thisSlot * 4; wbSize = lm.StructLayouts![thisSlot]!.Size; + } + method = f.M; lm = method.Lowered; slotT = lm.SlotTypes; bp = f.Bp; + numF = (byte*)(_num + bp); ip = f.Ip; contSp = f.ContSp; + _base = bp + lm.FrameSize; + if (wbSize > 0) Buffer.MemoryCopy(wbSrc, numF + f.VtThisWb * 4, wbSize, wbSize); + if (f.RetDst != -1) + { + var st = slotT[f.RetDst]; + if (st == SType.I8) Unsafe.WriteUnaligned(numF + f.RetDst * 4, v); + else if (st == SType.I4) *(int*)(numF + f.RetDst * 4) = unchecked((int)v); + else if (st == SType.R4) *(float*)(numF + f.RetDst * 4) = v; + else if (st == SType.R8) Unsafe.WriteUnaligned(numF + f.RetDst * 4, (double)v); + else refStack[bp + f.RetDst] = v; // O-typed dst: box as long + } + break; + } + case Op.ret_r8: + { + int s=(int)irP[ip+1]; + double v=RdR8(numF,refStack,slotT,s,bp); + if (_framesTop == frameBase) return CallReturn.FromR8(v); + var f = frames[--_framesTop]; + byte* wbSrc = null; int wbSize = 0; + if (f.VtThisWb >= 0) + { + int thisSlot = lm.ArgSlot != null ? lm.ArgSlot[0] : 0; + wbSrc = numF + thisSlot * 4; wbSize = lm.StructLayouts![thisSlot]!.Size; + } + method = f.M; lm = method.Lowered; slotT = lm.SlotTypes; bp = f.Bp; + numF = (byte*)(_num + bp); ip = f.Ip; contSp = f.ContSp; + _base = bp + lm.FrameSize; + if (wbSize > 0) Buffer.MemoryCopy(wbSrc, numF + f.VtThisWb * 4, wbSize, wbSize); + if (f.RetDst != -1) + { + var st = slotT[f.RetDst]; + if (st == SType.R8) Unsafe.WriteUnaligned(numF + f.RetDst * 4, v); + else if (st == SType.R4) *(float*)(numF + f.RetDst * 4) = (float)v; + else if (st == SType.I4) *(int*)(numF + f.RetDst * 4) = (int)v; + else if (st == SType.I8) Unsafe.WriteUnaligned(numF + f.RetDst * 4, (long)v); + else refStack[bp + f.RetDst] = v; // O-typed dst: box as double + } + break; + } + case Op.ret_vt: + { + int sV=(int)irP[ip+1]; + var vlay = lm.StructLayouts![sV]!; + byte* retSrc = numF + sV * 4; + if (_framesTop == frameBase) return CallReturn.FromO(vlay.BoxFromPtr(retSrc)); + var f = frames[--_framesTop]; + byte* wbSrc = null; int wbSize = 0; + if (f.VtThisWb >= 0) + { + int thisSlot = lm.ArgSlot != null ? lm.ArgSlot[0] : 0; + wbSrc = numF + thisSlot * 4; wbSize = lm.StructLayouts![thisSlot]!.Size; + } + method = f.M; lm = method.Lowered; slotT = lm.SlotTypes; bp = f.Bp; + numF = (byte*)(_num + bp); ip = f.Ip; contSp = f.ContSp; + _base = bp + lm.FrameSize; + if (wbSize > 0) Buffer.MemoryCopy(wbSrc, numF + f.VtThisWb * 4, wbSize, wbSize); + if (f.RetDst != -1) + { + var st = slotT[f.RetDst]; + // retSrc points into the (now-popped) callee frame region — still + // intact: nothing reuses it until the next call pushes past bp. + if (st == SType.Vt) Buffer.MemoryCopy(retSrc, numF + f.RetDst * 4, vlay.Size, vlay.Size); + else if (st == SType.O) refStack[bp + f.RetDst] = vlay.BoxFromPtr(retSrc); + else if (st == SType.I4) *(int*)(numF + f.RetDst * 4) = 0; + else *(float*)(numF + f.RetDst * 4) = 0f; + } + break; + } + case Op.throw_o: + { + // Script `throw`: unwinds exactly like a host-call throw — the shared + // exception path runs pending finally regions and maps the location. + object? ex = refStack[bp + (int)irP[ip + 1]]; + throw ex as Exception + ?? new ScriptRuntimeException("throw of a null or non-exception object"); + } + case Op.ret_o: + { + object? vo = refStack[bp + (int)irP[ip + 1]]; + if (_framesTop == frameBase) return CallReturn.FromO(vo); + var f = frames[--_framesTop]; + byte* wbSrc = null; int wbSize = 0; + if (f.VtThisWb >= 0) + { + int thisSlot = lm.ArgSlot != null ? lm.ArgSlot[0] : 0; + wbSrc = numF + thisSlot * 4; wbSize = lm.StructLayouts![thisSlot]!.Size; + } + method = f.M; lm = method.Lowered; slotT = lm.SlotTypes; bp = f.Bp; + numF = (byte*)(_num + bp); ip = f.Ip; contSp = f.ContSp; + _base = bp + lm.FrameSize; + if (wbSize > 0) Buffer.MemoryCopy(wbSrc, numF + f.VtThisWb * 4, wbSize, wbSize); + if (f.RetDst != -1) + { + // A numeric caller dst means the returned object is a boxed value + // (e.g. a host call's int/bool routed through an O-typed callee + // slot) — unbox it like WrObj; writing 0 would drop the value. + var st = slotT[f.RetDst]; + if (st == SType.I4) *(int*)(numF + f.RetDst * 4) = CoerceBoxedI4(vo); + else if (st == SType.R4) *(float*)(numF + f.RetDst * 4) = CoerceBoxedR4(vo); + else if (st == SType.I8) Unsafe.WriteUnaligned(numF + f.RetDst * 4, CoerceBoxedI8(vo)); + else if (st == SType.R8) Unsafe.WriteUnaligned(numF + f.RetDst * 4, CoerceBoxedR8(vo)); + else refStack[bp + f.RetDst] = vo; + } + break; + } + + // --- Script-class fields (flat typed storage in ScriptObject) --- + case Op.ldfld_sc_i4: { int dst=(int)irP[ip+1]; int o=(int)irP[ip+2]; int off=(int)irP[ip+3]; var so=(ScriptObject)refStack[bp+o]!; *(int*)(numF+dst*4)=Unsafe.ReadUnaligned(ref so.PrimBytes[off]); ip+=4; break; } + case Op.ldfld_sc_r4: { int dst=(int)irP[ip+1]; int o=(int)irP[ip+2]; int off=(int)irP[ip+3]; var so=(ScriptObject)refStack[bp+o]!; *(float*)(numF+dst*4)=Unsafe.ReadUnaligned(ref so.PrimBytes[off]); ip+=4; break; } + case Op.ldfld_sc_o: { int dst=(int)irP[ip+1]; int o=(int)irP[ip+2]; int off=(int)irP[ip+3]; var so=(ScriptObject)refStack[bp+o]!; refStack[bp+dst]=so.RefSlots[off]; ip+=4; break; } + case Op.stfld_sc_i4: { int o=(int)irP[ip+1]; int off=(int)irP[ip+2]; int s=(int)irP[ip+3]; var so=(ScriptObject)refStack[bp+o]!; Unsafe.WriteUnaligned(ref so.PrimBytes[off], RdI4(numF,refStack,slotT,s,bp)); ip+=4; break; } + case Op.stfld_sc_r4: { int o=(int)irP[ip+1]; int off=(int)irP[ip+2]; int s=(int)irP[ip+3]; var so=(ScriptObject)refStack[bp+o]!; Unsafe.WriteUnaligned(ref so.PrimBytes[off], RdR4(numF,refStack,slotT,s,bp)); ip+=4; break; } + case Op.stfld_sc_o: { int o=(int)irP[ip+1]; int off=(int)irP[ip+2]; int s=(int)irP[ip+3]; var so=(ScriptObject)refStack[bp+o]!; + // A described throw instead of a bare IndexOutOfRangeException: an OOB + // ref-slot index here means a lowering emitted a PrimBytes byte offset + // where a RefSlots index belongs (unit-mixing bug), and the naive store + // could silently corrupt a neighboring field instead of landing OOB. + if ((uint)off >= (uint)so.RefSlots.Length) { int il=(uint)(ip-lm.IrStart)<(uint)lm.IrToIlOffset.Length?lm.IrToIlOffset[ip-lm.IrStart]:0; throw new ScriptRuntimeException($"stfld_sc_o: ref-slot index {off} out of range for '{so.Type.Name}' ({so.RefSlots.Length} ref slots) — offset-unit bug in '{method.Name}'{At(method, il)}"); } + so.RefSlots[off]=RdObj(numF,refStack,slotT,s,bp); ip+=4; break; } + // Vt (flat host struct) field inline in ScriptObject.PrimBytes. Vt slots are + // addressed frame-relative (numF+slot*4; numF is already at this frame's base) — + // adding bp would double-apply the base and silently corrupt any nested call. + case Op.ldfld_sc_vt: + { + int dst=(int)irP[ip+1]; int o=(int)irP[ip+2]; int off=(int)irP[ip+3]; + var so=(ScriptObject)refStack[bp+o]!; int size=lm.StructLayouts![dst]!.Size; + byte* d=numF+dst*4; int c=0; + while (c+4<=size) { *(int*)(d+c)=Unsafe.ReadUnaligned(ref so.PrimBytes[off+c]); c+=4; } + while (c> 24) == 0x04) + { + // Primitive statics read from the UNBOXED store (miss -> 0). ldsfld_o + // (reference/long/double) reads the boxed store. See ScriptStaticsNum. + if (irop == Op.ldsfld_i4) + { + asm.ScriptStaticsNum.TryGetValue(tok, out var nv); + *(int*)(numF + dst * 4) = (int)nv; + } + else if (irop == Op.ldsfld_r4) + { + asm.ScriptStaticsNum.TryGetValue(tok, out var nv); + *(float*)(numF + dst * 4) = BitConverter.Int32BitsToSingle((int)nv); + } + else + { + asm.ScriptStatics.TryGetValue(tok, out var sv); + refStack[bp+dst]=sv; + } + } + else { int il=(uint)(ip-lm.IrStart)<(uint)lm.IrToIlOffset.Length?lm.IrToIlOffset[ip-lm.IrStart]:0; throw new ScriptRuntimeException($"Unknown static field token 0x{tok:X8}{At(method, il)}"); } + ip+=3; break; + } + case Op.stsfld_o: case Op.stsfld_i4: case Op.stsfld_r4: case Op.stsfld_struct: + { + int tokIdx=(int)irP[ip+1]; int s=(int)irP[ip+2]; + int tok=lm.Tokens[tokIdx]; + // Primitive SCRIPT statics store UNBOXED (raw bits) — no per-write heap box. + // The lowerer only emits stsfld_i4/r4 for script FieldDefs (never host fields). + if (irop == Op.stsfld_i4) + { asm.ScriptStaticsNum[tok] = RdI4(numF,refStack,slotT,s,bp); ip+=3; break; } + if (irop == Op.stsfld_r4) + { asm.ScriptStaticsNum[tok] = BitConverter.SingleToInt32Bits(RdR4(numF,refStack,slotT,s,bp)); ip+=3; break; } + object? val=RdObj(numF,refStack,slotT,s,bp); + if (asm.HostFields.TryGetValue(tok, out var shf)) shf.Set(null, val); + else if ((tok >> 24) == 0x04) asm.ScriptStatics[tok]=val; + else { int il=(uint)(ip-lm.IrStart)<(uint)lm.IrToIlOffset.Length?lm.IrToIlOffset[ip-lm.IrStart]:0; throw new ScriptRuntimeException($"Unknown static field token 0x{tok:X8}{At(method, il)}"); } + ip+=3; break; + } + + // --- Arrays (object?[] by default; typed backings via newarr_i4/r4/vt) --- + case Op.newarr: + { + int dst=(int)irP[ip+1]; int lenSlot=(int)irP[ip+2]; + int elemTokIdx=(int)irP[ip+3]; int fieldTokIdx=(int)irP[ip+4]; + // The length slot can be classified O (boxed int in refStack), not I4-flat, + // so read via RdI4 (honours the slot type). A raw *(int*)(numF+…) read + // returns poison when the value is actually boxed. + int len=RdI4(numF,refStack,slotT,lenSlot,bp); + // Typed primitive backing (bool[]/char[]/byte[]/…): a real runtime array + // so element reads box with the correct type and defaults are C#-zeroed. + var primType = lm.PrimArrayElemTypeByTokIdx?[elemTokIdx]; + if (primType != null) + { + var parr = System.Array.CreateInstance(primType, len); + if (fieldTokIdx != -1) + { + int es = primType.IsEnum ? 4 + : primType == typeof(long) || primType == typeof(ulong) || primType == typeof(double) ? 8 + : primType == typeof(bool) || primType == typeof(byte) || primType == typeof(sbyte) ? 1 : 2; + TryFillTypedArrayFromFieldBlob(parr, es, asm, lm.Tokens[fieldTokIdx]); + } + refStack[bp+dst]=parr; ip+=5; break; + } + var arr=new object?[len]; + if (fieldTokIdx != -1) TryFillArrayFromFieldBlob(arr, asm, lm.Tokens[elemTokIdx], lm.Tokens[fieldTokIdx]); + // A script-struct element type is a value type: `new T[n]` holds n zeroed + // structs, not nulls, so per-element field mutation (arr[i].x = …) works. + else if (asm.TypeDefToType.TryGetValue(lm.Tokens[elemTokIdx], out var ed) && ed.IsScriptStructValue) + for (int i=0;iint.MaxValue) + { int il2=(uint)(ip-lm.IrStart)<(uint)lm.IrToIlOffset.Length?lm.IrToIlOffset[ip-lm.IrStart]:0; throw new ScriptRuntimeException($"array dimensions exceeded the supported range (length {len}){At(method, il2)}"); } + refStack[bp+dst]=new ScriptVtArray + { Layout=elay, Bytes=new byte[(int)byteLen], Length=len, Stride=stride }; + ip+=5; break; + } + case Op.ldelem_vt: + { + int dst=(int)irP[ip+1]; int arrSlot=(int)irP[ip+2]; int idxSlot=(int)irP[ip+3]; + int idx=*(int*)(numF+idxSlot*4); + var arrObj=refStack[bp+arrSlot]; + var dlay=lm.StructLayouts![dst]!; + if (arrObj is ScriptVtArray sva) + { + if ((uint)idx >= (uint)sva.Length) + { int il2=(uint)(ip-lm.IrStart)<(uint)lm.IrToIlOffset.Length?lm.IrToIlOffset[ip-lm.IrStart]:0; throw new ScriptRuntimeException($"array index out of bounds{At(method, il2)}"); } + fixed (byte* srcB = sva.Bytes) + Buffer.MemoryCopy(srcB + idx * sva.Stride, numF + dst * 4, dlay.Size, dlay.Size); + } + else + { + // Boxed fallback (object?[] of ScriptObjects, or a host T[]). + object? ev; + try { ev = arrObj is object?[] oa ? oa[idx] : ((System.Array)arrObj!).GetValue(idx); } + catch (IndexOutOfRangeException) { int il2=(uint)(ip-lm.IrStart)<(uint)lm.IrToIlOffset.Length?lm.IrToIlOffset[ip-lm.IrStart]:0; throw new ScriptRuntimeException($"array index out of bounds{At(method, il2)}"); } + UnboxVt(numF, dst, dlay, ev); + } + ip+=4; break; + } + case Op.stelem_vt: + { + int arrSlot=(int)irP[ip+1]; int idxSlot=(int)irP[ip+2]; int srcS=(int)irP[ip+3]; + int idx=*(int*)(numF+idxSlot*4); + var arrObj=refStack[bp+arrSlot]; + var slay=lm.StructLayouts![srcS]!; + if (arrObj is ScriptVtArray sva) + { + if ((uint)idx >= (uint)sva.Length) + { int il2=(uint)(ip-lm.IrStart)<(uint)lm.IrToIlOffset.Length?lm.IrToIlOffset[ip-lm.IrStart]:0; throw new ScriptRuntimeException($"array index out of bounds{At(method, il2)}"); } + fixed (byte* dstB = sva.Bytes) + Buffer.MemoryCopy(numF + srcS * 4, dstB + idx * sva.Stride, slay.Size, slay.Size); + } + else + { + var v = BoxVt(numF, srcS, slay); + try { if (arrObj is object?[] oa) oa[idx]=v; else ((System.Array)arrObj!).SetValue(v, idx); } + catch (IndexOutOfRangeException) { int il2=(uint)(ip-lm.IrStart)<(uint)lm.IrToIlOffset.Length?lm.IrToIlOffset[ip-lm.IrStart]:0; throw new ScriptRuntimeException($"array index out of bounds{At(method, il2)}"); } + } + ip+=4; break; + } + // Script-created arrays are object?[] (int[]/float[] for the typed newarr variants); + // host members return real typed arrays. int[]/float[] hit the direct branches; + // reference-type arrays satisfy `is object?[]` by covariance; everything else falls + // back to System.Array (GetValue boxes, SetValue unboxes). + case Op.ldlen: + { + int dst=(int)irP[ip+1]; int s=(int)irP[ip+2]; + var aObj=refStack[bp+s]; + *(int*)(numF+dst*4) = aObj is ScriptVtArray svaL ? svaL.Length : ((System.Array)aObj!).Length; + ip+=3; break; + } + case Op.ldelem_o: case Op.ldelem_i4: case Op.ldelem_r4: case Op.ldelem_struct: + { + int dst=(int)irP[ip+1]; int arrSlot=(int)irP[ip+2]; int idxSlot=(int)irP[ip+3]; + int idx=*(int*)(numF+idxSlot*4); + var arrObj=refStack[bp+arrSlot]; + var dt=slotT[dst]; + if (arrObj is int[] ia && (uint)idx < (uint)ia.Length) + { + int ei=ia[idx]; + if (dt==SType.I4) *(int*)(numF+dst*4)=ei; + else if (dt==SType.R4) *(float*)(numF+dst*4)=(float)ei; + else if (dt==SType.I8) Unsafe.WriteUnaligned(numF+dst*4, (long)ei); + else if (dt==SType.R8) Unsafe.WriteUnaligned(numF+dst*4, (double)ei); + // CLR array covariance: Shape[] pattern-matches int[]. An O dst must + // box the element as its REAL type or Format holes render the number. + else refStack[bp+dst]=arrObj.GetType().GetElementType() is { IsEnum: true } eet2 + ? Enum.ToObject(eet2, ei) : ei; + } + else if (arrObj is long[] la8 && (uint)idx < (uint)la8.Length) + { + // Covers ulong[] via covariance — same 8-byte cells; the O-dst box + // must respect the REAL element type or ulongs print negative. + long el=la8[idx]; + if (dt==SType.I8) Unsafe.WriteUnaligned(numF+dst*4, el); + else if (dt==SType.I4) *(int*)(numF+dst*4)=unchecked((int)el); + else if (dt==SType.R4) *(float*)(numF+dst*4)=el; + else if (dt==SType.R8) Unsafe.WriteUnaligned(numF+dst*4, (double)el); + else refStack[bp+dst]=arrObj is ulong[] ? unchecked((ulong)el) : (object)el; + } + else if (arrObj is double[] da8 && (uint)idx < (uint)da8.Length) + { + double ed=da8[idx]; + if (dt==SType.R8) Unsafe.WriteUnaligned(numF+dst*4, ed); + else if (dt==SType.R4) *(float*)(numF+dst*4)=(float)ed; + else if (dt==SType.I4) *(int*)(numF+dst*4)=(int)ed; + else if (dt==SType.I8) Unsafe.WriteUnaligned(numF+dst*4, (long)ed); + else refStack[bp+dst]=ed; + } + else if (arrObj is float[] fa && (uint)idx < (uint)fa.Length) + { + float ef=fa[idx]; + if (dt==SType.R4) *(float*)(numF+dst*4)=ef; + else if (dt==SType.I4) *(int*)(numF+dst*4)=(int)ef; + else refStack[bp+dst]=ef; + } + // Sub-4-byte primitive arrays read into a numeric slot WITHOUT boxing (the + // fallback's Array.GetValue heap-allocs per element). Dispatch on the EXACT type, + // not `is`: (object)sbyte[] is byte[] is true, so a byte[] arm reads it unsigned. + else if (dt != SType.O + && arrObj is object arr && arr.GetType() is Type et + && (et == T_byteA || et == T_sbyteA || et == T_shortA + || et == T_ushortA || et == T_boolA || et == T_charA) + && (uint)idx < (uint)Unsafe.As(arr).Length) + { + int ei = + et == T_byteA ? (int)Unsafe.As(arr)[idx] : + et == T_sbyteA ? (int)Unsafe.As(arr)[idx] : + et == T_shortA ? (int)Unsafe.As(arr)[idx] : + et == T_ushortA ? (int)Unsafe.As(arr)[idx] : + et == T_charA ? (int)Unsafe.As(arr)[idx] : + (Unsafe.As(arr)[idx] ? 1 : 0); + if (dt==SType.I4) *(int*)(numF+dst*4)=ei; + else if (dt==SType.R4) *(float*)(numF+dst*4)=ei; + else if (dt==SType.I8) Unsafe.WriteUnaligned(numF+dst*4, (long)ei); + else Unsafe.WriteUnaligned(numF+dst*4, (double)ei); // R8 + } + else + { + object? ev; + try { ev = arrObj is object?[] oa ? oa[idx] : ((System.Array)arrObj!).GetValue(idx); } + catch (IndexOutOfRangeException) { int il=(uint)(ip-lm.IrStart)<(uint)lm.IrToIlOffset.Length?lm.IrToIlOffset[ip-lm.IrStart]:0; throw new ScriptRuntimeException($"array index out of bounds{At(method, il)}"); } + // Typed primitive arrays (bool[]/char[]/byte[]/…) box their element + // with the correct runtime type here; unbox every I4-mapped primitive. + // O dst keeps the correctly-typed box (constrained-callvirt receiver). + // (int) per arm: without it the switch's best-common-type over mixed + // signed/unsigned arms zero-extends sbyte/short (an sbyte -1 → 255). + if (dt==SType.I4) *(int*)(numF+dst*4)= ev switch + { + int ei => ei, bool eb => eb?1:0, char ec => (int)ec, + byte by => (int)by, sbyte sb => (int)sb, short sh => (int)sh, ushort us => (int)us, + uint eu => unchecked((int)eu), + Enum => unchecked((int)Convert.ToInt64(ev)), // host enum[] elements + _ => 0, + }; + else if (dt==SType.R4) *(float*)(numF+dst*4)=CoerceBoxedR4(ev); + else if (dt==SType.I8) Unsafe.WriteUnaligned(numF+dst*4, CoerceBoxedI8(ev)); + else if (dt==SType.R8) Unsafe.WriteUnaligned(numF+dst*4, CoerceBoxedR8(ev)); + else refStack[bp+dst]=ev; + } + ip+=4; break; + } + case Op.stelem_o: case Op.stelem_i4: case Op.stelem_r4: case Op.stelem_struct: + { + int arrSlot=(int)irP[ip+1]; int idxSlot=(int)irP[ip+2]; int s=(int)irP[ip+3]; + int idx=*(int*)(numF+idxSlot*4); + var arrObj=refStack[bp+arrSlot]; + var st2=slotT[s]; + // Dispatch on the exact array Type via cached-Type compares + Unsafe.As (no + // per-write isinst). Signed/unsigned pairs share layout, so one branch each. + // Fast writes guard (uint)idx(arrW).Length) + { Unsafe.As(arrW)[idx]=RdI4(numF,refStack,slotT,s,bp); ip+=4; break; } + } + else if (wt == T_floatA) + { + if ((uint)idx < (uint)Unsafe.As(arrW).Length) + { Unsafe.As(arrW)[idx]=RdR4(numF,refStack,slotT,s,bp); ip+=4; break; } + } + else if (wt == T_longA || wt == T_ulongA) + { + if ((uint)idx < (uint)Unsafe.As(arrW).Length) + { Unsafe.As(arrW)[idx]=RdI8(numF,refStack,slotT,s,bp); ip+=4; break; } + } + else if (wt == T_doubleA) + { + if ((uint)idx < (uint)Unsafe.As(arrW).Length) + { Unsafe.As(arrW)[idx]=RdR8(numF,refStack,slotT,s,bp); ip+=4; break; } + } + else if ((wt == T_boolA || wt == T_charA || wt == T_byteA || wt == T_sbyteA + || wt == T_shortA || wt == T_ushortA) + && (uint)idx < (uint)Unsafe.As(arrW).Length) + { + int val = RdI4(numF,refStack,slotT,s,bp); + if (wt == T_boolA) Unsafe.As(arrW)[idx] = val != 0; + else if (wt == T_charA) Unsafe.As(arrW)[idx] = (char)val; + else if (wt == T_byteA) Unsafe.As(arrW)[idx] = (byte)val; + else if (wt == T_sbyteA) Unsafe.As(arrW)[idx] = (sbyte)val; + else if (wt == T_shortA) Unsafe.As(arrW)[idx] = (short)val; + else Unsafe.As(arrW)[idx]= (ushort)val; + ip+=4; break; + } + } + // Fallback: object?[] element, a struct/enum-typed source, or an index the fast + // paths above declined (out of range) — box + SetValue, which keeps its own bounds + // check and throws a clean error. + { + // A Vt source slot lives in the numeric frame, not refStack; RdObj returns null + // for it, silently storing a default element. Box via the struct marshaller so + // both object?[] and real typed arrays receive the actual struct value. + var v = st2==SType.Vt ? BoxVt(numF, s, lm.StructLayouts![s]!) : RdObj(numF,refStack,slotT,s,bp); + // Enum arrays are real typed arrays; the source rides an I4 slot as a + // boxed int, which SetValue refuses — rebox as the element type. + if (arrObj?.GetType().GetElementType() is { IsEnum: true } eet && v is not Enum) + v = Enum.ToObject(eet, CoerceBoxedI4(v)); + try { if (arrObj is object?[] oa) oa[idx]=v; else ((System.Array)arrObj!).SetValue(v, idx); } + catch (IndexOutOfRangeException) { int il=(uint)(ip-lm.IrStart)<(uint)lm.IrToIlOffset.Length?lm.IrToIlOffset[ip-lm.IrStart]:0; throw new ScriptRuntimeException($"array index out of bounds{At(method, il)}"); } + } + ip+=4; break; + } + + // --- Script-to-script call (iterative: push caller frame, jump into callee) --- + case Op.call_script: + { + int dstSlot=(int)irP[ip+1]; int tokIdx=(int)irP[ip+2]; int argc=(int)irP[ip+3]; + var callee=lm.CalleeByTokIdx![tokIdx]!; + var clm=callee.Lowered; + int calleeBp=bp+lm.FrameSize; + if (!FrameFits(calleeBp, clm) || _framesTop >= MaxCallDepth) + throw new ScriptRuntimeException("Script call stack overflow"); + if (clm.RefClearLen > 0) Array.Clear(refStack, calleeBp, clm.RefClearLen); + var cst=clm.SlotTypes; + var cas=clm.ArgSlot; // arg index → callee frame slot (null = identity) + byte* cnum=(byte*)(_num+calleeBp); + int vtThisWb = -1; + for (int k=0;k= MaxCallDepth) + throw new ScriptRuntimeException("Script call stack overflow"); + if (clm.RefClearLen > 0) Array.Clear(refStack, ctorBp, clm.RefClearLen); + var cst=clm.SlotTypes; + var cas=clm.ArgSlot; + byte* cnum=(byte*)(_num+ctorBp); + refStack[ctorBp + (cas != null ? cas[0] : 0)]=obj; // 'this' (heap ctor: O slot) + for (int k=0;k boxed bool, not boxed int). + refStack[bp+dst] = tc switch + { + 0 => (object)RdI4(numF,refStack,slotT,s,bp), + 1 => RdI4(numF,refStack,slotT,s,bp) != 0, + 2 => (char)RdI4(numF,refStack,slotT,s,bp), + 3 => (byte)RdI4(numF,refStack,slotT,s,bp), + 4 => (sbyte)RdI4(numF,refStack,slotT,s,bp), + 5 => (short)RdI4(numF,refStack,slotT,s,bp), + 6 => (ushort)RdI4(numF,refStack,slotT,s,bp), + 8 => unchecked((uint)RdI4(numF,refStack,slotT,s,bp)), + 9 => RdI8(numF,refStack,slotT,s,bp), + 10 => unchecked((ulong)RdI8(numF,refStack,slotT,s,bp)), + 11 => RdR8(numF,refStack,slotT,s,bp), + _ => RdR4(numF,refStack,slotT,s,bp), + }; + ip+=4; break; + } + case Op.box_enum: + { + int dst=(int)irP[ip+1]; int s=(int)irP[ip+2]; int tokIdx=(int)irP[ip+3]; + int ev=RdI4(numF,refStack,slotT,s,bp); + refStack[bp+dst] = asm.TokenTypes.TryGetValue(lm.Tokens[tokIdx], out var et) + ? Enum.ToObject(et, ev) : (object)ev; + ip+=4; break; + } + case Op.initobj: + { + int dst=(int)irP[ip+1]; var lay=lm.StructLayouts![dst]; int size=lay!=null?lay.Size:4; + byte* d=numF+dst*4; for (int i=0;i()); + } + ip+=3; break; + } + case Op.unbox_any: case Op.castclass: + { + int dst=(int)irP[ip+1]; int s=(int)irP[ip+2]; int tokIdx=(int)irP[ip+3]; + int tok=lm.Tokens[tokIdx]; var val=refStack[bp+s]; + // Script TypeDef target (`(C0)(object)o`): exact-descriptor check — + // script classes have no inheritance, so identity IS the type test. + // Without this, castclass to a script type silently passed anything + // (found by fuzzing alongside the isinst case below). + if (val != null && irop==Op.castclass && asm.TypeDefToType.TryGetValue(tok, out var scd)) + { + if (!(val is ScriptObject vso && vso.Type == scd)) + { int il=(uint)(ip-lm.IrStart)<(uint)lm.IrToIlOffset.Length?lm.IrToIlOffset[ip-lm.IrStart]:0; throw new ScriptRuntimeException($"InvalidCastException{At(method, il)}: cannot cast to script type {scd.Name}"); } + } + else if (val != null && asm.TokenTypes.TryGetValue(tok, out var tt)) + { + if (irop==Op.castclass && !tt.IsInstanceOfType(val)) + { int il=(uint)(ip-lm.IrStart)<(uint)lm.IrToIlOffset.Length?lm.IrToIlOffset[ip-lm.IrStart]:0; throw new ScriptRuntimeException($"InvalidCastException{At(method, il)}: cannot cast {val.GetType().Name} to {tt.Name}"); } + // unbox.any is type-EXACT for value types: a boxed char can't unbox to + // int (C# throws InvalidCastException). Match that — the lenient RdI4 + // read would otherwise silently convert. (Nullable accepts a boxed U.) + if (irop==Op.unbox_any && tt.IsValueType) + { + var underlying = Nullable.GetUnderlyingType(tt) ?? tt; + if (val.GetType() != underlying) + { int il=(uint)(ip-lm.IrStart)<(uint)lm.IrToIlOffset.Length?lm.IrToIlOffset[ip-lm.IrStart]:0; throw new ScriptRuntimeException($"InvalidCastException{At(method, il)}: cannot unbox {val.GetType().Name} to {tt.Name}"); } + } + } + // Route through WrObj: an I4/R4 dst (unbox.any of a primitive) gets the + // unboxed value in the numeric frame; an O dst keeps the reference. + WrObj(numF, refStack, slotT, dst, val, bp); ip+=4; break; + } + case Op.isinst: + { + int dst=(int)irP[ip+1]; int s=(int)irP[ip+2]; int tokIdx=(int)irP[ip+3]; + int tok=lm.Tokens[tokIdx]; var val=refStack[bp+s]; + if (val==null) refStack[bp+dst]=null; + // Script TypeDef target (`o is C0`): exact-descriptor identity — covers + // script classes AND boxed script structs (found by fuzzing: threw + // "unallowed type" for `(object)o is C0`). + else if (asm.TypeDefToType.TryGetValue(tok, out var sisd)) refStack[bp+dst]=val is ScriptObject vso2 && vso2.Type == sisd ? val : null; + else if (asm.TokenTypes.TryGetValue(tok, out var tt)) refStack[bp+dst]=tt.IsInstanceOfType(val)?val:null; + else { int il=(uint)(ip-lm.IrStart)<(uint)lm.IrToIlOffset.Length?lm.IrToIlOffset[ip-lm.IrStart]:0; throw new ScriptRuntimeException($"isinst for unallowed type{At(method, il)}"); } + ip+=4; break; + } + case Op.ldtoken: + { + int dst=(int)irP[ip+1]; int tokIdx=(int)irP[ip+2]; int tok=lm.Tokens[tokIdx]; + if (!asm.TokenTypes.TryGetValue(tok, out var tt)) { int il=(uint)(ip-lm.IrStart)<(uint)lm.IrToIlOffset.Length?lm.IrToIlOffset[ip-lm.IrStart]:0; throw new ScriptRuntimeException($"ldtoken for unallowed type{At(method, il)}"); } + refStack[bp+dst]=tt; ip+=3; break; + } + case Op.switch_i4: + { + // Read the subject via RdI4 so an O-typed slot (a boxed int, e.g. a slow host + // call returning an enum) is honoured; a raw numF read yields 0 for a value + // that lives boxed in refFrame. + int valSlot=(int)irP[ip+1]; int n=(int)irP[ip+2]; int val=RdI4(numF,refStack,slotT,valSlot,bp); + ip = (uint)val < (uint)n ? (int)irP[ip+4+val] : (int)irP[ip+3]; + break; + } + + // --- Flat-struct (Vt) ops --- + case Op.ldfld_vt_vt: + { + int dst=(int)irP[ip+1]; int o=(int)irP[ip+2]; int off=(int)irP[ip+3]; + int size=lm.StructLayouts![dst]!.Size; + Buffer.MemoryCopy(numF+o*4+off, numF+dst*4, size, size); + ip+=4; break; + } + case Op.stfld_vt_vt: + { + int o=(int)irP[ip+1]; int off=(int)irP[ip+2]; int src2=(int)irP[ip+3]; + int size=lm.StructLayouts![src2]!.Size; + Buffer.MemoryCopy(numF+src2*4, numF+o*4+off, size, size); + ip+=4; break; + } + case Op.ldfld_vt_i4: { int dst=(int)irP[ip+1]; int o=(int)irP[ip+2]; int off=(int)irP[ip+3]; *(int*)(numF+dst*4)=*(int*)(numF+o*4+off); ip+=4; break; } + case Op.ldfld_vt_r4: { int dst=(int)irP[ip+1]; int o=(int)irP[ip+2]; int off=(int)irP[ip+3]; *(float*)(numF+dst*4)=*(float*)(numF+o*4+off); ip+=4; break; } + case Op.stfld_vt_i4: { int o=(int)irP[ip+1]; int off=(int)irP[ip+2]; int s=(int)irP[ip+3]; *(int*)(numF+o*4+off)=RdI4(numF,refStack,slotT,s,bp); ip+=4; break; } + case Op.stfld_vt_r4: { int o=(int)irP[ip+1]; int off=(int)irP[ip+2]; int s=(int)irP[ip+3]; *(float*)(numF+o*4+off)=RdR4(numF,refStack,slotT,s,bp); ip+=4; break; } + // Sub-4-byte flat fields (Color32.r-class): loads widen into the I4 dst + // cell, stores truncate. Byte pointers — no alignment assumptions. + case Op.ldfld_vt_u1: { int dst=(int)irP[ip+1]; int o=(int)irP[ip+2]; int off=(int)irP[ip+3]; *(int*)(numF+dst*4)=*(numF+o*4+off); ip+=4; break; } + case Op.ldfld_vt_i1: { int dst=(int)irP[ip+1]; int o=(int)irP[ip+2]; int off=(int)irP[ip+3]; *(int*)(numF+dst*4)=*(sbyte*)(numF+o*4+off); ip+=4; break; } + case Op.ldfld_vt_u2: { int dst=(int)irP[ip+1]; int o=(int)irP[ip+2]; int off=(int)irP[ip+3]; byte* p=numF+o*4+off; *(int*)(numF+dst*4)=(int)(uint)(p[0]|(p[1]<<8)); ip+=4; break; } + case Op.ldfld_vt_i2: { int dst=(int)irP[ip+1]; int o=(int)irP[ip+2]; int off=(int)irP[ip+3]; byte* p=numF+o*4+off; *(int*)(numF+dst*4)=(short)(p[0]|(p[1]<<8)); ip+=4; break; } + case Op.stfld_vt_b1: { int o=(int)irP[ip+1]; int off=(int)irP[ip+2]; int s=(int)irP[ip+3]; *(numF+o*4+off)=(byte)RdI4(numF,refStack,slotT,s,bp); ip+=4; break; } + case Op.stfld_vt_b2: { int o=(int)irP[ip+1]; int off=(int)irP[ip+2]; int s=(int)irP[ip+3]; int v=RdI4(numF,refStack,slotT,s,bp); byte* p=numF+o*4+off; p[0]=(byte)v; p[1]=(byte)(v>>8); ip+=4; break; } + case Op.mov_vt: + { + int dst=(int)irP[ip+1]; int s=(int)irP[ip+2]; int size=lm.StructLayouts![dst]!.Size; + byte* d=numF+dst*4; byte* src=numF+s*4; int c=0; + while (c+4<=size) { *(int*)(d+c)=*(int*)(src+c); c+=4; } + while (c helper + // (GetEnumerator on the state machine). Name the limitation. + int il=(uint)(ip-lm.IrStart)<(uint)lm.IrToIlOffset.Length?lm.IrToIlOffset[ip-lm.IrStart]:0; + string nm=asm.TokenNames.TryGetValue(tok, out var tn2)?tn2:"a host member"; + throw new ScriptRuntimeException( + $"called {nm} on a script-declared object — script types implementing " + + "host interfaces (e.g. IEnumerable iterator helpers) are not supported; " + + $"coroutines returning IEnumerator are{At(method, il)}"); + } + catch (Exception ex) + { int il=(uint)(ip-lm.IrStart)<(uint)lm.IrToIlOffset.Length?lm.IrToIlOffset[ip-lm.IrStart]:0; throw new ScriptRuntimeException($"{ex.GetType().Name}: {ex.Message}{At(method, il)}", ex); } + // A mutating instance member on a flat (Vt) receiver ran against a boxed + // copy — write the box back so property setters and mutating methods + // update the local. + if (recvSlot != -1 && slotT[recvSlot] == SType.Vt && hostEntry.ReceiverStruct != null && recv != null) + UnboxVt(numF, recvSlot, hostEntry.ReceiverStruct, recv); + if (dstSlot != -1) + { + // The lowerer may type the result slot I4/R4, so route the boxed return + // through WrObj — a direct refStack store would leave a numeric dst reading 0. + if (slotT[dstSlot]==SType.Vt) UnboxVt(numF, dstSlot, lm.StructLayouts![dstSlot]!, ret); + else WrObj(numF, refStack, slotT, dstSlot, ret, bp); + } + ip += 5 + argc; break; + } + case Op.call_host_byref: + { + int dstSlot=(int)irP[ip+1]; int recvSlot=(int)irP[ip+2]; int tokIdx=(int)irP[ip+3]; int argc=(int)irP[ip+4]; + int tok=lm.Tokens[tokIdx]; + var hostEntry=asm.HostCalls[tok]; + object? recv = recvSlot == -1 ? null + : hostEntry.ReceiverBox != ReceiverBoxKind.None && slotT[recvSlot] == SType.I4 + ? (hostEntry.ReceiverBox == ReceiverBoxKind.Char // box as char/bool, not int + ? (char)RdI4(numF, refStack, slotT, recvSlot, bp) + : RdI4(numF, refStack, slotT, recvSlot, bp) != 0) + : slotT[recvSlot]==SType.Vt && hostEntry.ReceiverStruct != null + ? BoxVt(numF, recvSlot, hostEntry.ReceiverStruct) + : RdObj(numF, refStack, slotT, recvSlot, bp); + // Exact-length buffer (ArgBuf, like the slow call_host path): the + // grow-only shared buffer kept its LARGEST length, and a later byref + // call with fewer params handed MethodInfo.Invoke an oversized array — + // TargetParameterCountException on the second invocation of any method + // whose small-arity byref call follows a larger one (found by fuzzing). + var hArgs = ArgBuf(argc); + for (int k=0;k(numF + s * 4)); + if (tt == SType.R8) return (int)Unsafe.ReadUnaligned(numF + s * 4); + // Vt slots live in the numeric frame; their refFrame entry is never cleared + // (RefClearLen covers only O slots) so it must not be read. + if (tt == SType.Vt) return 0; + // Unbox any boxed primitive the VM maps to I4 (box_prim can now produce boxed + // char/byte/short/…, not just int/bool). + var v = r[bp + s]; + return v switch + { + int ri => ri, bool rb => rb ? 1 : 0, char rc => rc, + byte rby => rby, sbyte rsb => rsb, short rsh => rsh, ushort rus => rus, + uint ru => unchecked((int)ru), + // A host caller (delegate adapter, Invoke) can hand an enum arg boxed as its real + // type into an O slot; reading it as I4 must see the underlying value, like the + // enum host-field fix did for ldfld. + Enum => unchecked((int)Convert.ToInt64(v)), + _ => 0, + }; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static float RdR4(byte* numF, object?[] r, SType[] t, int s, int bp) + { + var tt = t[s]; + if (tt == SType.R4) return *(float*)(numF + s * 4); + if (tt == SType.I4) return (float)*(int*)(numF + s * 4); + if (tt == SType.I8) return Unsafe.ReadUnaligned(numF + s * 4); + if (tt == SType.R8) return (float)Unsafe.ReadUnaligned(numF + s * 4); + if (tt == SType.Vt) return 0f; + return CoerceBoxedR4(r[bp + s]); + } + + // Read a slot as object? (boxes I4/R4). Used at the remaining boxing boundaries: + // host fields, array elements, O-typed stores. + // Host-call ARGUMENT read: like RdObj, but a flat (Vt) argument boxes through its slot + // layout. RdObj alone yields null for Vt slots, and MethodBase.Invoke silently turns a + // null arg into default(T) — zeroed struct fields (the bounds_autobind divergence). + static object? RdArg(byte* numF, object?[] r, SType[] t, int s, int bp, + HostBinding.StructLayout?[]? layouts) + { + if (t[s] == SType.Vt && layouts?[s] is { } lay) + return BoxVt(numF, s, lay); + return RdObj(numF, r, t, s, bp); + } + + static object? RdObj(byte* numF, object?[] r, SType[] t, int s, int bp) + { + var tt = t[s]; + if (tt == SType.I4) return *(int*)(numF + s * 4); + if (tt == SType.R4) return *(float*)(numF + s * 4); + // I8 boxes as long — like the I4 slot's int default, a ulong value loses its + // unsigned identity here; the explicit box path (box_prim tc 10) keeps it. + if (tt == SType.I8) return Unsafe.ReadUnaligned(numF + s * 4); + if (tt == SType.R8) return Unsafe.ReadUnaligned(numF + s * 4); + if (tt == SType.Vt) return null; + return r[bp + s]; + } + + static long RdI8(byte* numF, object?[] r, SType[] t, int s, int bp) + { + var tt = t[s]; + if (tt == SType.I8) return Unsafe.ReadUnaligned(numF + s * 4); + if (tt == SType.I4) return *(int*)(numF + s * 4); + if (tt == SType.R4) return (long)*(float*)(numF + s * 4); + if (tt == SType.R8) return (long)Unsafe.ReadUnaligned(numF + s * 4); + if (tt == SType.Vt) return 0L; + return CoerceBoxedI8(r[bp + s]); + } + + static double RdR8(byte* numF, object?[] r, SType[] t, int s, int bp) + { + var tt = t[s]; + if (tt == SType.R8) return Unsafe.ReadUnaligned(numF + s * 4); + if (tt == SType.R4) return *(float*)(numF + s * 4); + if (tt == SType.I4) return *(int*)(numF + s * 4); + if (tt == SType.I8) return Unsafe.ReadUnaligned(numF + s * 4); + if (tt == SType.Vt) return 0d; + return CoerceBoxedR8(r[bp + s]); + } + + // Write an object? into a slot, routing to the correct frame (unboxes I4/R4). + static void WrObj(byte* numF, object?[] r, SType[] t, int s, object? v, int bp) + { + var tt = t[s]; + // An I4 slot can receive any type the interpreter maps to I4 (Int32/Boolean/Char and the + // sub-int integrals). A host method returning char (String.get_Chars) or byte/short lands + // here boxed; recognizing only int/bool wrote 0 and dropped the value. (found by fuzzing.) + if (tt == SType.I4) *(int*)(numF + s * 4) = v switch + { + int vi => vi, + bool bv => bv ? 1 : 0, + char vc => vc, + byte vb => vb, + sbyte vsb => vsb, + short vsh => vsh, + ushort vus => vus, + uint vu => unchecked((int)vu), + // A byref out-param written back boxed as its real enum (Enum.TryParse) — the + // int/char family above dropped it to 0. Truncate like `(int)someEnum`. + Enum => unchecked((int)Convert.ToInt64(v)), + _ => 0, + }; + else if (tt == SType.R4) *(float*)(numF + s * 4) = CoerceBoxedR4(v); + else if (tt == SType.I8) Unsafe.WriteUnaligned(numF + s * 4, CoerceBoxedI8(v)); + else if (tt == SType.R8) Unsafe.WriteUnaligned(numF + s * 4, CoerceBoxedR8(v)); + else r[bp + s] = v; + } + + // Vt box/unbox via the registered pointer marshallers — straight off the unmanaged frame; + // the box allocation in BoxVt is the boundary's only alloc. + + static object BoxVt(byte* numF, int slot, HostBinding.StructLayout lay) + => lay.BoxFromPtr(numF + slot * 4); + + static void UnboxVt(byte* numF, int slot, HostBinding.StructLayout lay, object? boxed) + { + byte* dst = numF + slot * 4; + if (boxed == null) { for (int i = 0; i < lay.Size; i++) dst[i] = 0; return; } + lay.CopyToPtr(dst, boxed); + } + } +} +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/VmEngine.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/VmEngine.cs.meta new file mode 100644 index 0000000..b887898 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/IlInterpreter/VmEngine.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b14fe6feb7a4ab04e913f44be3fef0a5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Models.meta new file mode 100644 index 0000000..425d69a --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 68a343bc078aa5e459201276f7813b32 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/ArgProblem.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Models/ArgProblem.cs new file mode 100644 index 0000000..25bf38b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/ArgProblem.cs @@ -0,0 +1,101 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; + +namespace Unity.Pipeline +{ + /// + /// One machine-readable argument-binding defect, reported in /api/exec's + /// argProblems array. + /// + /// The vocabulary matches the unity CLI's own ArgProblemKind one-for-one, plus + /// , which needs the declared CLR type and so can + /// only come from the server. Field names mirror the CLI's record exactly, so neither side + /// needs a translation table. + /// + /// Deliberately machine-readable rather than pre-rendered English: the CLI renders AND + /// LOCALIZES these itself across 10 locales. A server sending prose would make + /// unity command the one surface that answers in English while the rest of the CLI + /// localizes. The envelope's errorDetails carries the English fallback for curl, MCP, + /// and for kinds a client has never heard of. + /// + public class ArgProblem + { + /// The kind of issue with provided argument. + [JsonProperty("kind")] + [JsonConverter(typeof(StringEnumConverter), true)] + public ArgProblemKind Kind { get; set; } + + /// The offending raw token, where the defect is about a token. + [JsonProperty("token", NullValueHandling = NullValueHandling.Ignore)] + public string Token { get; set; } + + /// The parameter name involved, where the defect is about a name. + [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] + public string Name { get; set; } + + /// A did-you-mean candidate for . + [JsonProperty("suggestion", NullValueHandling = NullValueHandling.Ignore)] + public string Suggestion { get; set; } + + /// Declared positional slots, for . + [JsonProperty("capacity", NullValueHandling = NullValueHandling.Ignore)] + public int? Capacity { get; set; } + + /// Positionals supplied, for . + [JsonProperty("given", NullValueHandling = NullValueHandling.Ignore)] + public int? Given { get; set; } + + /// + /// The declared CLR type name, for . Sent as + /// Int32-style short names, matching what the catalog's schema already reports. + /// + [JsonProperty("expectedType", NullValueHandling = NullValueHandling.Ignore)] + public string ExpectedType { get; set; } + } + + /// + /// Kinds of argument-binding defect. Serialized camelCase (unknownName) to match the + /// CLI's wire expectations; the C# spelling stays PascalCase per package convention. + /// + public enum ArgProblemKind + { + // Shape — schema-independent. + + /// + /// A flag with no name: --= or --=value. + /// + /// Not a bare --: the first one is the end-of-flags separator and is consumed + /// before any name parsing, and every later one is a positional. + /// + EmptyName, + + /// --key= with nothing after the =. + EmptyValue, + + /// A -x token in positional position (never a flag's value). + SingleDash, + + /// The same --key supplied more than once. + Duplicate, + + // Names — requires the declared-parameter array. + + /// --nope, or --group-by when the command declares group_by. + UnknownName, + + /// A bare key=value positional whose left side names a real parameter. + BareAssignment, + + /// More positionals than the command has parameter slots. + ExcessPositional, + + /// A positional whose slot was already filled by an explicit flag. + PositionalConflict, + + /// + /// A token the declared parameter type cannot accept. Detectable only by the server, + /// which has the real . + /// + TypeMismatch, + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/ArgProblem.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Models/ArgProblem.cs.meta new file mode 100644 index 0000000..e8a50c0 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/ArgProblem.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9735aca395c65e64ea689c065eee20c3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/AuthoringResult.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Models/AuthoringResult.cs new file mode 100644 index 0000000..ea23282 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/AuthoringResult.cs @@ -0,0 +1,42 @@ +using System; +using Newtonsoft.Json; + +namespace Unity.Pipeline.Models +{ + /// + /// Canonical identity of an object an authoring command created or acted on, returned as the + /// command result so an agent can reference it in a follow-up call (via ). + /// Asset objects carry assetPath/guid(/fileId); loaded/scene objects carry instanceId/hierarchyPath. + /// + [Serializable] + public class AuthoringResult + { + /// Canonical GlobalObjectId string for the object. + [JsonProperty("globalId")] + public string GlobalId { get; set; } + + /// Project-relative asset path, if the object is an asset. + [JsonProperty("assetPath")] + public string AssetPath { get; set; } + + /// Asset GUID, if the object is an asset. + [JsonProperty("guid")] + public string Guid { get; set; } + + /// Local file id within the asset, for sub-assets. + [JsonProperty("fileId")] + public long? FileId { get; set; } + + /// Instance id, if the object is loaded/in a scene. + [JsonProperty("instanceId")] + public ObjectId? InstanceId { get; set; } + + /// Scene hierarchy path, for scene objects. + [JsonProperty("hierarchyPath")] + public string HierarchyPath { get; set; } + + /// Object type name (e.g. "GameObject", "Material", "DefaultAsset"). + [JsonProperty("type")] + public string Type { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/AuthoringResult.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Models/AuthoringResult.cs.meta new file mode 100644 index 0000000..6875c3a --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/AuthoringResult.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6b92c58d435dcee4e8312f67b90af25c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/BaseResponse.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Models/BaseResponse.cs new file mode 100644 index 0000000..2d4c7c0 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/BaseResponse.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Unity.Pipeline.Models +{ + /// + /// Base class for all responses. Serve also as the base class for all errors. + /// + [Serializable] + public class BaseResponse + { + /// + /// Response message if no error + /// + [JsonProperty("message")] + public string Message { get; set; } + + /// + /// Machine-actionable warnings for the caller: things the server dropped, coerced, or + /// wants the agent to correct (e.g. an unrecognized option value), without failing the + /// request. Null when there is nothing to say, and omitted from the JSON in EVERY mode + /// (an empty warnings array carries no information — attribute-level gating, so this + /// holds on all endpoints and in verbose serialization too). (AUTHAPI-21) + /// + [JsonProperty("warnings", NullValueHandling = NullValueHandling.Ignore)] + public List Warnings { get; set; } + + /// + /// Error message if the command failed. + /// + [JsonProperty("error")] + public string Error { get; set; } + + /// + /// Additional error details for debugging. + /// + [JsonProperty("errorDetails")] + public string ErrorDetails { get; set; } + + /// + /// When was the response created. + /// + /// + /// On the /api/exec wire this is emitted only in verbose mode — the lean/verbose gating lives + /// in ExecResponseSerializer, NOT here, so every other serialization of this type + /// (status endpoints, logs, tests) keeps the field. (AUTHAPI-21) + /// + [JsonProperty("executedAt")] + public DateTime ExecutedAt { get; set; } + + /// + /// Create a failed execution response. + /// + /// Error message. + /// Additional error details for debugging. + /// A response with / set. + public static BaseResponse Failure(string error, string errorDetails) + { + return new BaseResponse + { + ExecutedAt = DateTime.UtcNow, + Error = error, + ErrorDetails = errorDetails + }; + } + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/BaseResponse.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Models/BaseResponse.cs.meta new file mode 100644 index 0000000..a5c363b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/BaseResponse.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 00ec05951f34dac4494abb6eb6c90026 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/CommandExecutionRequest.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Models/CommandExecutionRequest.cs new file mode 100644 index 0000000..9ac97b9 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/CommandExecutionRequest.cs @@ -0,0 +1,199 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Unity.Pipeline.Models +{ + /// + /// Request model for /api/exec endpoint. + /// Contains command name and parameters for remote command execution. + /// + [Serializable] + class CommandExecutionRequest + { + /// + /// Name of the command to execute. + /// Must match a registered [CliCommand] name. + /// + /// Optional, because and carry the name in + /// their first token instead; the server assigns it here before anything downstream reads + /// it. Exactly one of the three forms may be present - enforces + /// that. + /// + [JsonProperty("command")] + public string Command { get; set; } + + /// + /// An unparsed command line: the server tokenizes it (see + /// ) and then binds it. For clients that genuinely + /// hold raw text — MCP, a chat box, a pasted line. Mutually exclusive with + /// and . + /// + [JsonProperty("commandLine")] + public string CommandLine { get; set; } + + /// + /// Pre-split tokens, first of which is the command name. Preferred over + /// by any caller that already has argv — on POSIX a CLI never + /// holds the original command STRING, so making it re-quote tokens for the server to + /// re-split would be a lossy round-trip across two independently-versioned quoting + /// dialects. Mutually exclusive with and . + /// + [JsonProperty("argv")] + public List Argv { get; set; } + + /// + /// True when this request arrived in a raw form, so the reply should echo the bound + /// parameters back. [JsonIgnore] is MANDATORY — this type is serialized + /// (ExecResponseSerializer), and an internal flag must never reach the wire. + /// + [JsonIgnore] + public bool IsRawForm => CommandLine != null || Argv != null; + + /// + /// Parameters for the command execution. + /// Contains key-value pairs matching command parameter names. + /// + [JsonProperty("parameters")] + public JObject Parameters { get; set; } + + /// + /// Optional timeout for command execution in milliseconds. + /// Default: 60000 (60 seconds) + /// + [JsonProperty("timeout")] + public int? Timeout { get; set; } + + /// + /// Opt into the full response envelope. When false (default) the server returns a lean, + /// token-efficient reply — compact JSON, the envelope's own null keys omitted, and the + /// always-on metadata (executedAt, command, executionTimeMs) dropped; the command's + /// result payload keeps explicit nulls (see ). Set true to get + /// every envelope field back for debugging/correlation. (AUTHAPI-21) + /// + [JsonProperty("verbose")] + public bool Verbose { get; set; } + + /// + /// When true, drop null keys from the whole reply INCLUDING the command's result payload. + /// Off by default: an absent payload key would otherwise be indistinguishable from a + /// nonexistent or misspelled one. Opt in when the result schema is already known and the + /// nulls are pure bytes — e.g. bulk list reads where a null column repeats per item. + /// Orthogonal to (envelope metadata). (AUTHAPI-21) + /// + [JsonProperty("omitNulls")] + public bool OmitNulls { get; set; } + + /// + /// When true, run the command as a detached job (CLI-335): the response returns a job + /// id immediately and the client collects the result later via GET /api/job?id=…, + /// surviving its own HTTP timeout. Execution still queues through the server's + /// one-command-at-a-time exec gate. + /// + [JsonProperty("job")] + public bool Job { get; set; } + + /// + /// Create a new command execution request. + /// + public CommandExecutionRequest() + { + Parameters = new JObject(); + } + + /// + /// Create a command execution request with specified command and parameters. + /// + /// Name of the command to execute. + /// Parameters for the command execution. + public CommandExecutionRequest(string command, JObject parameters = null) + { + Command = command ?? throw new ArgumentNullException(nameof(command)); + Parameters = parameters ?? new JObject(); + } + + /// + /// Get a parameter value as the specified type. + /// Returns the default value if the parameter is not found or cannot be converted. + /// + /// The type to convert the parameter value to. + /// Parameter name. + /// Value to return if the parameter is missing or unconvertible. + /// The parameter's value, or . + public T GetParameter(string name, T defaultValue = default(T)) + { + if (Parameters == null || !Parameters.ContainsKey(name)) + return defaultValue; + + try + { + return Parameters[name].ToObject(); + } + catch + { + return defaultValue; + } + } + + /// + /// Check if a parameter exists in the request. + /// + /// Parameter name. + /// True if the parameter is present. + public bool HasParameter(string name) + { + return Parameters != null && Parameters.ContainsKey(name); + } + + /// + /// Validate the request structure. + /// + /// An error message, or null if the request is valid. + public string Validate() + { + // Exactly one of the three request forms. Counting them first keeps every + // combination -- including all three at once -- on one message. + var forms = 0; + if (Command != null) forms++; + if (CommandLine != null) forms++; + if (Argv != null) forms++; + + if (forms > 1) + return "Specify exactly one of 'command', 'commandLine' or 'argv'"; + + if (IsRawForm) + { + // Rejected, not ignored: a silently-dropped payload is indistinguishable from + // one that was never sent, which is the ambiguity the lean envelope already + // legislates against. + if (Parameters != null && Parameters.Count > 0) + return "'parameters' cannot be combined with 'commandLine' or 'argv'; the arguments belong in the command line itself"; + + if (Argv != null) + { + if (Argv.Count == 0) + return "'argv' must contain at least the command name"; + for (var i = 0; i < Argv.Count; i++) + if (Argv[i] == null) + return "'argv' must not contain null elements"; + if (string.IsNullOrWhiteSpace(Argv[0])) + return "'argv' must start with the command name"; + } + else if (string.IsNullOrWhiteSpace(CommandLine)) + { + return "'commandLine' must not be empty"; + } + } + else if (string.IsNullOrWhiteSpace(Command)) + { + return "Command name is required"; + } + + if (Timeout.HasValue && Timeout.Value <= 0) + return "Timeout must be a positive number"; + + return null; // No validation errors + } + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/CommandExecutionRequest.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Models/CommandExecutionRequest.cs.meta new file mode 100644 index 0000000..94629e6 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/CommandExecutionRequest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cb08d2e5232819b43bbec0549c02a689 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/CommandExecutionResponse.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Models/CommandExecutionResponse.cs new file mode 100644 index 0000000..f42d1b9 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/CommandExecutionResponse.cs @@ -0,0 +1,208 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Unity.Pipeline.Models +{ + /// + /// Response model for /api/exec endpoint. + /// Contains execution result and metadata for remote command execution. + /// + [Serializable] + public class CommandExecutionResponse : BaseResponse + { + /// + /// Whether the command executed successfully. + /// + [JsonProperty("success")] + public bool Success { get; set; } + + /// + /// Name of the command that was executed. + /// + [JsonProperty("command")] + public string Command { get; set; } + + + /// + /// Result returned by the command (if any). + /// + [JsonProperty("result")] + public object Result { get; set; } + + /// + /// Execution duration in milliseconds. + /// + /// + /// Like command and executedAt, emitted on the /api/exec wire only in verbose + /// mode — the gating lives in ExecResponseSerializer, not on this model. (AUTHAPI-21) + /// + [JsonProperty("executionTimeMs")] + public long? ExecutionTimeMs { get; set; } + + /// + /// Coarse machine-readable server state marker. Set to "busy" when the command was not + /// executed because the server's host cannot service it yet (e.g. the Editor is still + /// settling after a cold start). Omitted from the JSON on ordinary success/failure + /// responses, so existing envelopes are unchanged. + /// + [JsonProperty("status", NullValueHandling = NullValueHandling.Ignore)] + public string Status { get; set; } + + /// + /// True when the failure is transient and the same request is expected to succeed after a + /// short wait (poll /api/status until it reports "ready"). Omitted from the JSON on + /// ordinary success/failure responses. + /// + [JsonProperty("retryable", NullValueHandling = NullValueHandling.Ignore)] + public bool? Retryable { get; set; } + + /// + /// Stable, machine-readable failure discriminator (e.g. INVALID_COMMAND_ARGS). + /// + /// HTTP status cannot serve as the discriminator here: every /api/exec failure is 400, so + /// status alone cannot separate "your arguments are wrong" from "the command threw". + /// Spelled to match the unity CLI's own InvalidArgsCode literal, so neither side + /// needs a translation table. + /// + [JsonProperty("errorCode", NullValueHandling = NullValueHandling.Ignore)] + public string ErrorCode { get; set; } + + /// + /// Every argument-binding defect found, one entry each — the binder accumulates rather + /// than bailing, so a user fixing a command line sees all of its problems at once. + /// Machine-readable rather than prose, because the unity CLI renders and localizes + /// these itself; carries the English fallback for + /// clients that do not. + /// + [JsonProperty("argProblems", NullValueHandling = NullValueHandling.Ignore)] + public List ArgProblems { get; set; } + + /// + /// The resolved command's catalog entry, shaped like a /api/commands commands[] + /// element. Sent with an argument error so a client can render usage without a separate + /// schema request. Free to produce - the command is already resolved at that point. + /// + [JsonProperty("commandSchema", NullValueHandling = NullValueHandling.Ignore)] + public JObject CommandSchema { get; set; } + + /// + /// What the server bound from a raw command line. Set ONLY for argv/commandLine requests, + /// leaving the structured path's envelope unchanged. A client that does not bind locally + /// has no other way to report what the command actually received. + /// + [JsonProperty("parameters", NullValueHandling = NullValueHandling.Ignore)] + public JObject BoundParameters { get; set; } + + /// + /// Create the argument-binding failure response (sent with HTTP 400): the command was + /// resolved but its arguments could not be bound, so nothing executed. + /// + internal static CommandExecutionResponse CmdInvalidArgs(string cmd, string details, + List problems, JObject commandSchema) + { + return new CommandExecutionResponse + { + Command = cmd, + Success = false, + ExecutedAt = DateTime.UtcNow, + Error = "Invalid Command Arguments", + ErrorDetails = details, + ErrorCode = "INVALID_COMMAND_ARGS", + ArgProblems = problems, + CommandSchema = commandSchema + }; + } + + /// + /// The specific cause of a "busy" response, matching /api/status's own "status" values for + /// the same conditions ("settling", "blocked_by_dialog") — a caller can branch on this + /// directly instead of inferring the cause from whether "dialogs" happens to be populated. + /// Omitted from the JSON on ordinary success/failure responses. + /// + [JsonProperty("busyReason", NullValueHandling = NullValueHandling.Ignore)] + public string BusyReason { get; set; } + + /// + /// Dialogs (see EditorDialogEvents) that opened at or after this call started. Omitted + /// when none occurred, so existing envelopes are unchanged. Lets a caller learn "this + /// call took 40s because a dialog was shown" even without polling /api/dialog + /// concurrently. + /// + [JsonProperty("dialogsDuringExecution", NullValueHandling = NullValueHandling.Ignore)] + public List DialogsDuringExecution { get; set; } + + /// + /// Currently-open dialog(s) (see EditorDialogEvents), attached to a busy response when a + /// MainThreadRequired command was rejected because a modal dialog is blocking the main + /// thread. Omitted otherwise. + /// + [JsonProperty("dialogs", NullValueHandling = NullValueHandling.Ignore)] + public List Dialogs { get; set; } + + /// + /// Create a successful execution response. + /// + /// Name of the executed command. + /// The command's result payload. + /// How long the command took to execute, in milliseconds. + /// A successful response wrapping . + public static CommandExecutionResponse CmdSuccess(string command, object result = null, long? executionTimeMs = null) + { + return new CommandExecutionResponse + { + Success = true, + Command = command, + ExecutedAt = DateTime.UtcNow, + Result = result, + ExecutionTimeMs = executionTimeMs + }; + } + + /// + /// Create a failed execution response. + /// + /// Name of the executed command. + /// Error message. + /// Additional error details for debugging. + /// A failed response with / set. + public static CommandExecutionResponse CmdFailure(string cmd, string error, string errorDetails) + { + return new CommandExecutionResponse + { + Command = cmd, + Success = false, + ExecutedAt = DateTime.UtcNow, + Error = error, + ErrorDetails = errorDetails + }; + } + + /// + /// Create the retryable "server busy" response (sent with HTTP 503): the command was not + /// executed because the host cannot service it yet — distinguishable from a genuine + /// command failure via status/retryable so callers know to retry shortly instead of + /// guessing (AUTHAPI-35). is the specific cause ("settling", + /// "blocked_by_dialog", ...); omit it only for a generic/legacy busy state. + /// + /// Name of the command that could not be serviced yet. + /// Human-readable reason the host is busy. + /// The specific cause of the busy state, or null for a generic/legacy busy state. + /// A retryable "server busy" response. + public static CommandExecutionResponse CmdBusy(string cmd, string details, string busyReason = null) + { + return new CommandExecutionResponse + { + Command = cmd, + Success = false, + ExecutedAt = DateTime.UtcNow, + Error = "Server Busy", + ErrorDetails = details, + Status = "busy", + Retryable = true, + BusyReason = busyReason + }; + } + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/CommandExecutionResponse.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Models/CommandExecutionResponse.cs.meta new file mode 100644 index 0000000..1303e89 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/CommandExecutionResponse.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1911e492692621e4998635d7ddce0489 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/ConsoleGroundTruth.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Models/ConsoleGroundTruth.cs new file mode 100644 index 0000000..33dbd03 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/ConsoleGroundTruth.cs @@ -0,0 +1,63 @@ +using System; +using Newtonsoft.Json; + +namespace Unity.Pipeline.Models +{ + /// + /// Editor ground truth about the console, sampled on the main thread and served alongside + /// buffered entries so a client can tell whether the buffer agrees with the Editor console + /// without a second round trip. Null when served from a player build, which has no Editor + /// console. + /// + [Serializable] + public class ConsoleGroundTruth + { + /// When the sample was taken (UTC). + [JsonProperty("sampledUtc")] + public DateTime SampledUtc { get; set; } + + /// + /// How long ago the sample was taken. Sampling runs on the main thread, so it stops while + /// the Editor is blocked compiling or importing; a large age means the rest of this object + /// describes an older state of the console. + /// + [JsonProperty("ageMs")] + public long AgeMs { get; set; } + + /// + /// True while the project has editor compile errors. Read from + /// EditorUtility.scriptCompilationFailed, which is native state independent of the + /// log callback and of any domain reload, so it stays true for as long as the errors do. + /// + [JsonProperty("compilationFailed")] + public bool CompilationFailed { get; set; } + + /// True while script compilation is in progress. + [JsonProperty("compiling")] + public bool Compiling { get; set; } + + /// + /// Errors the Editor console holds. This is a console-lifetime total, so comparing it with + /// shows whether the buffer is missing entries the + /// console still displays. + /// + [JsonProperty("consoleErrors")] + public int ConsoleErrors { get; set; } + + /// Warnings the Editor console holds. + [JsonProperty("consoleWarnings")] + public int ConsoleWarnings { get; set; } + + /// Informational entries the Editor console holds. + [JsonProperty("consoleLogs")] + public int ConsoleLogs { get; set; } + + /// + /// True once the buffer has been backfilled from the Editor console's own store. False + /// means that backfill is unavailable on this Editor version, which is a benign explanation + /// for the buffer holding fewer entries than and friends report. + /// + [JsonProperty("seeded")] + public bool Seeded { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/ConsoleGroundTruth.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Models/ConsoleGroundTruth.cs.meta new file mode 100644 index 0000000..8ee528c --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/ConsoleGroundTruth.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 10d7f65f989380a4aa80b77361180394 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/ConsoleLogEntry.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Models/ConsoleLogEntry.cs new file mode 100644 index 0000000..f4910c3 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/ConsoleLogEntry.cs @@ -0,0 +1,63 @@ +using System; +using Newtonsoft.Json; + +namespace Unity.Pipeline.Models +{ + /// + /// A single captured Unity console entry, as returned by the console command. + /// + [Serializable] + public class ConsoleLogEntry + { + /// + /// Monotonic sequence number assigned when the entry was captured. Acts as the cursor for + /// incremental ("--follow") retrieval: pass the highest seq seen back as the since + /// parameter to get only newer entries. Never reused, and increasing for the life of the + /// buffer (including across domain reloads, since the buffer is persisted). + /// + [JsonProperty("seq")] + public long Seq { get; set; } + + /// + /// When the entry was captured (UTC). + /// + [JsonProperty("timestampUtc")] + public DateTime TimestampUtc { get; set; } + + /// + /// Normalized severity: "log", "warn", or "error". Unity's Error/Exception/Assert log types + /// all map to "error"; Warning maps to "warn"; Log maps to "log". + /// + [JsonProperty("level")] + public string Level { get; set; } + + /// + /// Unity's own name for the entry ("Log", "Warning", + /// "Error", "Assert", "Exception"), keeping the distinction that + /// collapses. + /// + [JsonProperty("logType")] + public string LogType { get; set; } + + /// + /// The log message text. + /// + [JsonProperty("message")] + public string Message { get; set; } + + /// + /// The stack trace associated with the entry, if any. Empty for most plain logs. + /// + [JsonProperty("stackTrace")] + public string StackTrace { get; set; } + + /// + /// True when the entry was read from the Editor console's own store rather than captured + /// live. Its is when it was read, not when it was logged, and + /// its position relative to live-captured entries reflects the read, not the original + /// chronology. + /// + [JsonProperty("seeded")] + public bool Seeded { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/ConsoleLogEntry.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Models/ConsoleLogEntry.cs.meta new file mode 100644 index 0000000..b375237 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/ConsoleLogEntry.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: bd1bd665815e523ee0da6504d78923df diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/ConsoleLogResponse.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Models/ConsoleLogResponse.cs new file mode 100644 index 0000000..1ebde66 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/ConsoleLogResponse.cs @@ -0,0 +1,102 @@ +using System; +using Newtonsoft.Json; + +namespace Unity.Pipeline.Models +{ + /// + /// Response model for the console command: a page of captured console entries plus + /// the cursor needed to fetch the next page. + /// + [Serializable] + public class ConsoleLogResponse + { + /// + /// The matching entries, oldest first, after applying the level filter, since cursor, + /// and tail limit. + /// + [JsonProperty("entries")] + public ConsoleLogEntry[] Entries { get; set; } + + /// + /// The highest currently held in the buffer (regardless of + /// the level filter). A "--follow" client passes this back as since on the next poll + /// so it resumes exactly where it left off, even if the only new entries were filtered out. + /// Only meaningful paired with : sequence numbers restart from zero + /// with the capture session, so a cursor from an earlier session names different entries. + /// + [JsonProperty("cursor")] + public long Cursor { get; set; } + + /// + /// Identifies the capture session belongs to. A "--follow" client + /// passes this back as since_session alongside since; a cursor from a + /// different session is refused rather than silently misapplied. + /// + [JsonProperty("session")] + public string Session { get; set; } + + /// + /// Number of entries returned in . + /// + [JsonProperty("returned")] + public int Returned { get; set; } + + /// + /// True when the requested since cursor pointed at entries that have already been + /// evicted from the bounded buffer, meaning the consumer missed some entries. Lets a + /// "--follow" client warn about a gap instead of silently skipping output. Also true + /// whenever is. + /// + [JsonProperty("dropped")] + public bool Dropped { get; set; } + + /// + /// True when the requested cursor could not be honored — it came from another session, or + /// it was past the current counter — so the cursor was ignored and the tail returned + /// instead. A "--follow" client should adopt and + /// and treat the returned entries as a fresh start. + /// + [JsonProperty("reset")] + public bool Reset { get; set; } + + /// + /// How many entries of each severity the buffer currently holds, before the level filter + /// and tail limit. Compare with and + /// friends to see whether the buffer is missing entries the Editor console still shows. + /// + [JsonProperty("counts")] + public ConsoleLevelCounts Counts { get; set; } + + /// + /// Editor ground truth about the console at the time it was last sampled. Null in a player + /// build, and before the first sample after an Editor load. + /// + [JsonProperty("groundTruth")] + public ConsoleGroundTruth GroundTruth { get; set; } + } + + /// + /// Entry counts per severity retained in the buffer, before the level filter and tail + /// limit are applied. Compare with the Editor console's own totals in + /// to see whether the buffer is missing entries the console + /// still shows. + /// + [Serializable] + public class ConsoleLevelCounts + { + /// + /// Retained entries at error severity. Unity's Error, Exception and Assert log types all + /// count here. + /// + [JsonProperty("error")] + public int Error { get; set; } + + /// Retained entries at warning severity. + [JsonProperty("warn")] + public int Warn { get; set; } + + /// Retained entries at informational severity. + [JsonProperty("log")] + public int Log { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/ConsoleLogResponse.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Models/ConsoleLogResponse.cs.meta new file mode 100644 index 0000000..3ac7c4c --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/ConsoleLogResponse.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 3382b91cda66d80db6ab090f9fbeac16 diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/EvalResponse.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Models/EvalResponse.cs new file mode 100644 index 0000000..2628d17 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/EvalResponse.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace Unity.Pipeline.Models +{ + /// + /// Response from code evaluation commands containing results, output, and diagnostics. + /// + [Serializable] + class EvalResponse :CommandExecutionResponse + { + /// + /// Console output captured during execution. + /// + [JsonProperty("output")] + public string Output { get; set; } + + /// + /// Compilation diagnostics (errors, warnings) from Roslyn. + /// + [JsonProperty("diagnostics")] + public List Diagnostics { get; set; } = new List(); + + /// + /// Create a successful evaluation response. + /// + /// The evaluated expression's result. + /// Console output captured during execution. + /// How long execution took, in milliseconds. + /// Compilation diagnostics (errors, warnings) from Roslyn. + /// A successful response wrapping . + public static EvalResponse EvalSuccess(object result, string output = null, long executionTimeMs = 0, List diagnostics = null) + { + return new EvalResponse + { + Success = true, + Command = "eval", + Result = result, + Output = output, + ExecutionTimeMs = executionTimeMs, + Diagnostics = diagnostics ?? new List(), + ExecutedAt = DateTime.UtcNow + }; + } + + /// + /// Create a failed evaluation response. + /// + /// Error message. + /// Additional error details for debugging. + /// How long execution took, in milliseconds. + /// Compilation diagnostics (errors, warnings) from Roslyn. + /// A failed response. + public static EvalResponse EvalFailure(string error, string errorDetails = null, long executionTimeMs = 0, List diagnostics = null) + { + return new EvalResponse + { + Success = false, + Command = "eval", + Error = error, + ErrorDetails = errorDetails, + ExecutionTimeMs = executionTimeMs, + Diagnostics = diagnostics ?? new List(), + ExecutedAt = DateTime.UtcNow + }; + } + } + + /// + /// Compilation diagnostic information from Roslyn. + /// + [Serializable] + public class DiagnosticInfo + { + /// + /// Severity level: "error", "warning", "info". + /// + [JsonProperty("severity")] + public string Severity { get; set; } + + /// + /// Diagnostic message text. + /// + [JsonProperty("message")] + public string Message { get; set; } + + /// + /// Line number (0-based). + /// + [JsonProperty("line")] + public int Line { get; set; } + + /// + /// Column number (0-based). + /// + [JsonProperty("column")] + public int Column { get; set; } + + /// + /// Diagnostic identifier (e.g., "CS1002"). + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// User source file the diagnostic maps to through a #line directive, or null when + /// the compiled source carries no mapping (eval snippets, generated scaffolding). + /// + [JsonProperty("file", NullValueHandling = NullValueHandling.Ignore)] + public string File { get; set; } + + /// + /// 1-based line in ; null when is null. + /// + [JsonProperty("fileLine", NullValueHandling = NullValueHandling.Ignore)] + public int? FileLine { get; set; } + + /// + /// Trimmed text of the compiled source line the diagnostic points at. For code reload that + /// is the generated override source, which is what actually failed to compile. + /// + [JsonProperty("source", NullValueHandling = NullValueHandling.Ignore)] + public string Source { get; set; } + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/EvalResponse.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Models/EvalResponse.cs.meta new file mode 100644 index 0000000..3ee6d5b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/EvalResponse.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7f93e07b346878148b61c36fd3ece752 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/InstanceDescriptor.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Models/InstanceDescriptor.cs new file mode 100644 index 0000000..4c2e15f --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/InstanceDescriptor.cs @@ -0,0 +1,273 @@ +using System; +using System.IO; +using System.Diagnostics; +using Newtonsoft.Json; +using UnityEngine; +using Unity.Pipeline.Security; +#if UNITY_6000_5_OR_NEWER +using Unity.Scripting.LifecycleManagement; +#endif + +namespace Unity.Pipeline.Models +{ + /// + /// Manages instance descriptor files for CLI discovery. + /// Written to Library/Pipeline/.unity-pipeline-port (under the project's git-ignored Library + /// folder) for CLI tools to find running Editor instances. + /// + [Serializable] +#if UNITY_6000_5_OR_NEWER + [NoAutoStaticsCleanup] +#endif + class InstanceDescriptor + { + private const string DescriptorFileName = ".unity-pipeline-port"; + + /// + /// Corrective guidance surfaced via when the Editor is interactive and + /// wasn't launched with -automated (UUM-149977). Read by every client before it can even + /// connect (see ), unlike a console warning which was logged once per + /// server instance and nobody watches anyway. + /// + private const string AutomationInfoMessage = + "This editor has not been opened in automated mode and therefore could get stuck on modal dialogs. Human intervention may be required."; + + /// + /// Process ID of the Unity Editor + /// + [JsonProperty("pid")] + public int Pid { get; set; } + + /// + /// HTTP port the pipeline server is listening on + /// + [JsonProperty("port")] + public int Port { get; set; } + + /// + /// Full path to the Unity project + /// + [JsonProperty("projectPath")] + public string ProjectPath { get; set; } + + /// + /// Name of the Unity project + /// + [JsonProperty("projectName")] + public string ProjectName { get; set; } + + /// + /// Unity Editor version string + /// + [JsonProperty("unityVersion")] + public string UnityVersion { get; set; } + + /// + /// Editor mode: "editor", "batchmode" + /// + [JsonProperty("mode")] + public string Mode { get; set; } + + /// + /// When the Editor instance was started + /// + [JsonProperty("startedAt")] + public DateTime StartedAt { get; set; } + + /// + /// Last heartbeat timestamp + /// + [JsonProperty("lastHeartbeat")] + public DateTime LastHeartbeat { get; set; } + + /// + /// Security token for code evaluation commands + /// + [JsonProperty("evalToken")] + public string EvalToken { get; set; } + + /// + /// Corrective guidance for the client, e.g. warning that this instance could get stuck on + /// a modal dialog. Null when there is nothing to say (launched with -automated, or + /// batchmode — which can't show modals regardless, see ) — omitted from + /// the JSON entirely, same convention as . Read this + /// before issuing commands: it's the one piece of state every client sees, since reading + /// the descriptor is a mandatory first step just to connect (UUM-149977). There is no + /// separate "automated" flag: it would only ever disagree with a null/non-null `Info` for + /// batchmode instances, and that distinction carries no information — batchmode can't show + /// modal dialogs either way. + /// + [JsonProperty("info", NullValueHandling = NullValueHandling.Ignore)] + public string Info { get; set; } + + /// + /// Optional wire features this server understands (e.g. exec.argv), mirrored from + /// so the two carriers cannot drift. + /// + /// Carried in the descriptor because every client already reads this file locally to + /// obtain the eval token, so negotiation costs no extra request. A descriptor with NO + /// capabilities key at all comes from a server too old to have the field, and a client + /// must then assume it supports none of these features. + /// + [JsonProperty("capabilities", NullValueHandling = NullValueHandling.Ignore)] + public string[] Capabilities { get; set; } + + /// + /// Create instance descriptor for current Editor session + /// + /// Port the server is listening on. + /// Whether the Editor was launched with -automated. + /// A populated descriptor for this Editor session. + public static InstanceDescriptor CreateCurrent(int port, bool automated) + { + try + { + var projectPath = Path.GetDirectoryName(Application.dataPath); + var projectName = Path.GetFileName(projectPath); + var pid = Process.GetCurrentProcess().Id; + var unityVersion = Application.unityVersion; + var isBatchMode = Application.isBatchMode; + + // Generate eval token at server startup for CLI auto-discovery + var evalToken = SecurityTokenManager.GetOrCreateToken(); + + return new InstanceDescriptor + { + Capabilities = BasePipelineServer.Capabilities, + Pid = pid, + Port = port, + ProjectPath = projectPath, + ProjectName = projectName, + UnityVersion = unityVersion, + Mode = isBatchMode ? "batchmode" : "editor", + StartedAt = DateTime.UtcNow, + LastHeartbeat = DateTime.UtcNow, + EvalToken = evalToken, + // Only in an interactive Editor: batchmode (CI, upm-pvp, UTR) can't show modal + // popups, so the guidance would be pure noise there. + Info = (!automated && !isBatchMode) ? AutomationInfoMessage : null + }; + } + catch (Exception ex) + { + UnityEngine.Debug.LogError($"CreateCurrent failed: {ex.Message}"); + UnityEngine.Debug.LogError($"Stack trace: {ex.StackTrace}"); + throw; + } + } + + /// + /// Serializes descriptor writes. Heartbeat rewrites can now run concurrently (requests + /// are processed in parallel since the /api/progress work); a torn concurrent write + /// would leave clients reading half a descriptor. + /// + private static readonly object m_WriteGate = new object(); + + /// + /// Write instance descriptor to project root + /// + /// The descriptor to write. + public static void WriteToProjectRoot(InstanceDescriptor descriptor) + { + lock (m_WriteGate) + { + WriteToProjectRootLocked(descriptor); + } + } + + private static void WriteToProjectRootLocked(InstanceDescriptor descriptor) + { + try + { + var filePath = GetDescriptorFilePath(descriptor.ProjectPath); + var isNewFile = !File.Exists(filePath); + // The descriptor lives under Library/Pipeline, which may not exist yet. + Directory.CreateDirectory(Path.GetDirectoryName(filePath)); + var json = JsonConvert.SerializeObject(descriptor, Formatting.Indented); + File.WriteAllText(filePath, json); + + // The descriptor carries the auth token; keep it readable only by the current user. + // Applied once on creation (heartbeat rewrites preserve the existing permissions). + if (isNewFile) + FilePermissions.RestrictToCurrentUser(filePath); + } + catch (Exception ex) + { + UnityEngine.Debug.LogError($"WriteToProjectRoot failed: {ex.Message}"); + UnityEngine.Debug.LogError($"Descriptor: {descriptor?.ProjectPath}, PID: {descriptor?.Pid}"); + throw; + } + } + + /// + /// Read instance descriptor from project root + /// + /// Absolute path to the Unity project. + /// The descriptor, or null if missing/corrupted. + public static InstanceDescriptor ReadFromProjectRoot(string projectPath) + { + var filePath = GetDescriptorFilePath(projectPath); + + if (!File.Exists(filePath)) + return null; + + try + { + var json = File.ReadAllText(filePath); + return JsonConvert.DeserializeObject(json); + } + catch + { + // Invalid or corrupted file + return null; + } + } + + /// + /// Remove instance descriptor from project root + /// + /// Absolute path to the Unity project. + public static void RemoveFromProjectRoot(string projectPath) + { + var filePath = GetDescriptorFilePath(projectPath); + + if (File.Exists(filePath)) + { + try + { + File.Delete(filePath); + } + catch + { + // Ignore cleanup errors + } + } + } + + /// + /// Update heartbeat timestamp in existing descriptor file + /// + /// Absolute path to the Unity project. + public static void UpdateHeartbeat(string projectPath) + { + var descriptor = ReadFromProjectRoot(projectPath); + if (descriptor != null) + { + descriptor.LastHeartbeat = DateTime.UtcNow; + WriteToProjectRoot(descriptor); + } + } + + /// + /// Absolute path to the editor descriptor file for a project: the git-ignored + /// Library/Pipeline folder under the project root. Kept in one place so discovery code + /// and tests can't drift from where this class itself reads/writes. + /// + /// Absolute path to the Unity project. + /// The descriptor file's absolute path. + public static string GetDescriptorFilePath(string projectPath) + { + return Path.Combine(projectPath, "Library", "Pipeline", DescriptorFileName); + } + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/InstanceDescriptor.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Models/InstanceDescriptor.cs.meta new file mode 100644 index 0000000..c86575b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/InstanceDescriptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c19a2cde67d600341b17d8056b8393e2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/ObjectRef.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Models/ObjectRef.cs new file mode 100644 index 0000000..b2ab3f3 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/ObjectRef.cs @@ -0,0 +1,60 @@ +using System; +using Newtonsoft.Json; + +namespace Unity.Pipeline.Models +{ + /// + /// Agent-supplied handle that references an existing Unity object — an asset or a + /// loaded/scene object. Supply ONE form; + /// tries them in order: globalId, path, guid (+ optional fileId), instanceId, hierarchyPath. + /// + [Serializable] + [JsonConverter(typeof(ObjectRefConverter))] + public class ObjectRef + { + /// Canonical GlobalObjectId string (addresses assets and scene objects uniformly). + [JsonProperty("globalId")] + public string GlobalId { get; set; } + + /// Project-relative asset path, e.g. "Assets/Foo/Bar.prefab". + [JsonProperty("path")] + public string Path { get; set; } + + /// Asset GUID. + [JsonProperty("guid")] + public string Guid { get; set; } + + /// Local file id, used with to address a sub-asset. + [JsonProperty("fileId")] + public long? FileId { get; set; } + + /// Instance id of a loaded/scene object. + [JsonProperty("instanceId")] + public ObjectId? InstanceId { get; set; } + + /// Scene hierarchy path, e.g. "/Root/Child/Leaf". + [JsonProperty("hierarchyPath")] + public string HierarchyPath { get; set; } + + /// True when none of the reference forms above are set. + [JsonIgnore] + public bool IsEmpty => + string.IsNullOrEmpty(GlobalId) && + string.IsNullOrEmpty(Path) && + string.IsNullOrEmpty(Guid) && + InstanceId == null && + string.IsNullOrEmpty(HierarchyPath); + + /// The reference in its most specific set form, for diagnostics/logging. + /// The formatted string. + public override string ToString() + { + if (!string.IsNullOrEmpty(GlobalId)) return GlobalId; + if (!string.IsNullOrEmpty(Path)) return Path; + if (!string.IsNullOrEmpty(Guid)) return FileId.HasValue ? $"guid:{Guid}:{FileId}" : $"guid:{Guid}"; + if (InstanceId.HasValue) return $"instanceId:{InstanceId}"; + if (!string.IsNullOrEmpty(HierarchyPath)) return HierarchyPath; + return ""; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/ObjectRef.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Models/ObjectRef.cs.meta new file mode 100644 index 0000000..e436c15 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/ObjectRef.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e970b2bf3a890d743bea6785f8af3765 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/ObjectRefConverter.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Models/ObjectRefConverter.cs new file mode 100644 index 0000000..2e70544 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/ObjectRefConverter.cs @@ -0,0 +1,199 @@ +using System; +using System.IO; +using System.Text.RegularExpressions; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Unity.Pipeline.Models +{ + /// + /// JSON converter for that accepts BOTH a structured object + /// (all six fields via their JSON property names) AND a single canonical string handle. + /// + /// The MCP tool schemas intentionally expose object-reference parameters as plain strings, so an + /// agent typically passes e.g. "target": "/Player" or "target": "GlobalObjectId_V1-...". + /// Without this converter, Newtonsoft's ToObject<ObjectRef>() (used by + /// BasePipelineServer.ExtractCommandParameters) gets a JValue(string), returns null, and the + /// command fails Required-parameter validation. This converter coerces the string into the matching + /// field, mirroring the priority order of ObjectResolver.TryResolve and ObjectRef.ToString(). + /// + /// Registered on the class itself via [JsonConverter(typeof(ObjectRefConverter))] so it applies + /// everywhere an is (de)serialized — no server or command changes required. + /// + class ObjectRefConverter : JsonConverter + { + private static readonly Regex s_GuidWithFileId = new Regex(@"^guid:([0-9a-fA-F]+):([0-9]+)$", RegexOptions.Compiled); + private static readonly Regex s_GuidOnly = new Regex(@"^guid:([0-9a-fA-F]+)$", RegexOptions.Compiled); + private static readonly Regex s_InstanceId = new Regex(@"^instanceId:(-?[0-9]+)$", RegexOptions.Compiled); + private static readonly Regex s_PlainInt = new Regex(@"^-?[0-9]+$", RegexOptions.Compiled); + private static readonly Regex s_Hex32 = new Regex(@"^[0-9a-fA-F]{32}$", RegexOptions.Compiled); + + /// Read an from a structured object, a canonical string, or a bare instance id. + /// The JSON reader. + /// The declared property type. + /// The existing value, if any. + /// Whether is valid. + /// The active serializer. + /// The parsed reference, or null for a JSON null. + public override ObjectRef ReadJson(JsonReader reader, Type objectType, ObjectRef existingValue, + bool hasExistingValue, JsonSerializer serializer) + { + var token = JToken.Load(reader); + switch (token.Type) + { + case JTokenType.Null: + return null; + case JTokenType.String: + return FromString((string)token); + case JTokenType.Integer: + // A bare JSON number is treated as an instance id (e.g. "target": 48184). + return new ObjectRef { InstanceId = token.ToObject() }; + case JTokenType.Object: + return FromObject((JObject)token); + default: + return null; + } + } + + /// Write an as a structured JSON object. + /// The JSON writer. + /// The reference to write, or null. + /// The active serializer. + public override void WriteJson(JsonWriter writer, ObjectRef value, JsonSerializer serializer) + { + if (value == null) + { + writer.WriteNull(); + return; + } + + // Write a standard JSON object (matching the [JsonProperty] names on ObjectRef). Done + // manually rather than via serializer.Serialize to avoid re-entering this converter. + writer.WriteStartObject(); + writer.WritePropertyName("globalId"); + writer.WriteValue(value.GlobalId); + writer.WritePropertyName("path"); + writer.WriteValue(value.Path); + writer.WritePropertyName("guid"); + writer.WriteValue(value.Guid); + writer.WritePropertyName("fileId"); + if (value.FileId.HasValue) writer.WriteValue(value.FileId.Value); else writer.WriteNull(); + writer.WritePropertyName("instanceId"); + // Route the id through ObjectIdConverter so it serializes as its raw numeric form + // (the 64-bit EntityId on 6000.4+, the int below). Not this converter — no recursion. + if (value.InstanceId.HasValue) serializer.Serialize(writer, value.InstanceId.Value); else writer.WriteNull(); + writer.WritePropertyName("hierarchyPath"); + writer.WriteValue(value.HierarchyPath); + writer.WriteEndObject(); + } + + /// + /// Map a structured JSON object to an ObjectRef by reading each field directly (rather than + /// ToObject<ObjectRef>(), which would recurse back into this converter). + /// + /// Keys are matched case-INSENSITIVELY: agents commonly vary the casing (e.g. "instanceID" for + /// instanceId, "fileID" for fileId), and because this custom converter bypasses Newtonsoft's + /// default case-insensitive property binding, an exact-case lookup would otherwise drop the + /// field and yield an empty (silently unresolved) handle. + /// + private static ObjectRef FromObject(JObject jo) + { + return new ObjectRef + { + GlobalId = Str(jo, "globalId"), + Path = Str(jo, "path"), + Guid = Str(jo, "guid"), + FileId = Long(jo, "fileId"), + InstanceId = ObjId(jo, "instanceId"), + HierarchyPath = Str(jo, "hierarchyPath"), + }; + } + + /// Find a property value by name, ignoring case (Newtonsoft's JObject lookup is case-sensitive). + private static JToken Get(JObject jo, string key) + { + foreach (var p in jo.Properties()) + { + if (string.Equals(p.Name, key, StringComparison.OrdinalIgnoreCase)) + return p.Value; + } + + return null; + } + + private static string Str(JObject jo, string key) + { + var t = Get(jo, key); + return t == null || t.Type == JTokenType.Null ? null : t.Value(); + } + + private static ObjectId? ObjId(JObject jo, string key) + { + var t = Get(jo, key); + return t == null || t.Type == JTokenType.Null ? (ObjectId?)null : t.ToObject(); + } + + private static long? Long(JObject jo, string key) + { + var t = Get(jo, key); + return t == null || t.Type == JTokenType.Null ? (long?)null : t.Value(); + } + + /// + /// Parse a single canonical string handle into the matching field. Priority order matches + /// ObjectResolver.TryResolve / ObjectRef.ToString(); a bare name falls back to + /// the hierarchy path (the most common agent input). + /// + internal static ObjectRef FromString(string s) + { + if (string.IsNullOrWhiteSpace(s)) + return null; + + s = s.Trim(); + + if (s.StartsWith("GlobalObjectId_V1", StringComparison.Ordinal)) + return new ObjectRef { GlobalId = s }; + + // "Assets/..." and "Packages/..." (and the bare roots) are asset paths that + // AssetDatabase.LoadMainAssetAtPath can resolve; everything else falls through to the + // hierarchy-path fallback at the end. + if (s.StartsWith("Assets/", StringComparison.Ordinal) + || s.StartsWith("Packages/", StringComparison.Ordinal) + || s == "Assets" || s == "Packages") + return new ObjectRef { Path = s }; + + var guidFile = s_GuidWithFileId.Match(s); + if (guidFile.Success && long.TryParse(guidFile.Groups[2].Value, out var fileId)) + return new ObjectRef { Guid = guidFile.Groups[1].Value, FileId = fileId }; + + var guidOnly = s_GuidOnly.Match(s); + if (guidOnly.Success) + return new ObjectRef { Guid = guidOnly.Groups[1].Value }; + + var inst = s_InstanceId.Match(s); + if (inst.Success && ObjectId.TryParse(inst.Groups[1].Value, out var prefixedId)) + return new ObjectRef { InstanceId = prefixedId }; + + // A plain integer is an instance id. On 6000.0-6000.3 negative ids are valid (unsaved scene + // objects); on 6000.4+ the id is the unsigned 64-bit EntityId, so a leading '-' won't parse + // and falls through to the hierarchy-path handling below. + if (s_PlainInt.IsMatch(s) && ObjectId.TryParse(s, out var plainId)) + return new ObjectRef { InstanceId = plainId }; + + // Exactly 32 hex chars with no other prefix is a bare asset GUID. + if (s_Hex32.IsMatch(s)) + return new ObjectRef { Guid = s }; + + // A relative string with a file extension (e.g. "Materials/Floor.mat", "Enemy.prefab") is + // most likely an authoring-root-relative asset path — route it to Path so the resolver can + // normalize it under the authoring root. A leading "/" always means a scene hierarchy path, + // and an extension-less string ("Player", "Root/Child") stays one. Dotted GameObject names + // ("Cube.001") land here too, but the resolver falls back to a hierarchy lookup for those. + if (!s.StartsWith("/", StringComparison.Ordinal) && Path.HasExtension(s)) + return new ObjectRef { Path = s }; + + // Leading-"/" canonical paths and bare names resolve as a scene hierarchy path. + return new ObjectRef { HierarchyPath = s }; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/ObjectRefConverter.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Models/ObjectRefConverter.cs.meta new file mode 100644 index 0000000..0b538de --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/ObjectRefConverter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e31382a242c2a084e97ba76716798aa3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/RuntimeInstanceDescriptor.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Models/RuntimeInstanceDescriptor.cs new file mode 100644 index 0000000..cbe7107 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/RuntimeInstanceDescriptor.cs @@ -0,0 +1,251 @@ +using System; +using Newtonsoft.Json; +using UnityEngine; +using Unity.Pipeline.Config; +using System.IO; +using Unity.Pipeline.Security; +#if UNITY_6000_5_OR_NEWER +using Unity.Scripting.LifecycleManagement; +#endif + +namespace Unity.Pipeline.Models +{ + /// + /// Instance descriptor for runtime Unity Player builds with Pipeline server. + /// Different from Editor InstanceDescriptor to reflect runtime context and security. + /// + [Serializable] +#if UNITY_6000_5_OR_NEWER + [NoAutoStaticsCleanup] +#endif + class RuntimeInstanceDescriptor + { + private const string RuntimeDescriptorFileName = ".unity-pipeline-runtime-port"; + + /// + /// Process ID of the Unity Player application + /// + [JsonProperty("pid")] + public int Pid { get; set; } + + /// + /// HTTP port the pipeline server is listening on (7900-7999 range) + /// + [JsonProperty("port")] + public int Port { get; set; } + + /// + /// Unity runtime platform (Windows, macOS, Linux, etc.) + /// + [JsonProperty("platform")] + public string Platform { get; set; } + + /// + /// Unity Player version string + /// + [JsonProperty("unityVersion")] + public string UnityVersion { get; set; } + + /// + /// Unique build identifier + /// + [JsonProperty("buildGuid")] + public string BuildGuid { get; set; } + + /// + /// When the runtime instance was started + /// + [JsonProperty("startedAt")] + public DateTime StartedAt { get; set; } + + /// + /// Last heartbeat timestamp + /// + [JsonProperty("lastHeartbeat")] + public DateTime LastHeartbeat { get; set; } + + /// + /// Working directory where the application is running + /// + [JsonProperty("workingDirectory")] + public string WorkingDirectory { get; set; } + + /// + /// Security token used to authorize requests to this runtime server. + /// + [JsonProperty("evalToken")] + public string EvalToken { get; set; } + + /// + /// Optional wire features this server understands (e.g. exec.argv), mirrored from + /// so the two carriers cannot drift. + /// + /// Carried in the descriptor because every client already reads this file locally to + /// obtain the eval token, so negotiation costs no extra request. A descriptor with NO + /// capabilities key at all comes from a server too old to have the field, and a client + /// must then assume it supports none of these features. + /// + [JsonProperty("capabilities", NullValueHandling = NullValueHandling.Ignore)] + public string[] Capabilities { get; set; } + + /// + /// Create runtime instance descriptor for current Player application. + /// + /// Port the runtime server is listening on. + /// The runtime pipeline configuration (currently unused, reserved for future fields). + /// A populated descriptor for this Player instance. + public static RuntimeInstanceDescriptor CreateCurrent(int port, RuntimePipelineConfig config) + { + try + { + var pid = System.Diagnostics.Process.GetCurrentProcess().Id; + var unityVersion = Application.unityVersion; + var platform = Application.platform.ToString(); + var buildGuid = Application.buildGUID; + var workingDir = Directory.GetCurrentDirectory(); + + var token = SecurityTokenManager.GetOrCreateToken(); + + return new RuntimeInstanceDescriptor + { + Capabilities = BasePipelineServer.Capabilities, + Pid = pid, + Port = port, + Platform = platform, + UnityVersion = unityVersion, + BuildGuid = buildGuid, + StartedAt = DateTime.UtcNow, + LastHeartbeat = DateTime.UtcNow, + WorkingDirectory = workingDir, + EvalToken = token + }; + } + catch (Exception ex) + { + UnityEngine.Debug.LogError($"Pipeline: CreateCurrent failed: {ex.Message}"); + throw; + } + } + + /// + /// Serializes descriptor writes so concurrent heartbeat rewrites (e.g. overlapping + /// /api/status probes) can't leave a torn file on disk. Mirrors InstanceDescriptor's + /// m_WriteGate. + /// + private static readonly object m_WriteGate = new object(); + + /// + /// Write runtime instance descriptor to working directory. + /// + /// The descriptor to write. + public static void WriteToWorkingDirectory(RuntimeInstanceDescriptor descriptor) + { + lock (m_WriteGate) + { + try + { + var filePath = GetDescriptorFilePath(); + var isNewFile = !File.Exists(filePath); + var json = JsonConvert.SerializeObject(descriptor, Formatting.Indented); + + File.WriteAllText(filePath, json); + + // The descriptor carries the auth token; keep it readable only by the current user. + // Applied once on creation (heartbeat rewrites preserve the existing permissions). + if (isNewFile) + FilePermissions.RestrictToCurrentUser(filePath); + + System.Console.WriteLine($"Pipeline: Runtime descriptor written to {filePath}"); + } + catch (Exception ex) + { + UnityEngine.Debug.LogError($"Pipeline: Failed to write runtime descriptor: {ex.Message}"); + throw; + } + } + } + + /// + /// Read runtime instance descriptor from working directory. + /// + /// The descriptor, or null if missing/corrupted. + public static RuntimeInstanceDescriptor ReadFromWorkingDirectory() + { + var filePath = GetDescriptorFilePath(); + + if (!File.Exists(filePath)) + return null; + + try + { + var json = File.ReadAllText(filePath); + return JsonConvert.DeserializeObject(json); + } + catch (Exception ex) + { + UnityEngine.Debug.LogWarning($"Pipeline: Failed to read runtime descriptor: {ex.Message}"); + return null; + } + } + + /// + /// Remove runtime instance descriptor from working directory. + /// + public static void RemoveFromWorkingDirectory() + { + var filePath = GetDescriptorFilePath(); + + if (File.Exists(filePath)) + { + try + { + File.Delete(filePath); + } + catch (Exception ex) + { + UnityEngine.Debug.LogWarning($"Pipeline: Failed to remove runtime descriptor: {ex.Message}"); + } + } + } + + /// + /// Update heartbeat timestamp in existing descriptor file. + /// + public static void UpdateHeartbeat() + { + try + { + var descriptor = ReadFromWorkingDirectory(); + if (descriptor != null) + { + descriptor.LastHeartbeat = DateTime.UtcNow; + WriteToWorkingDirectory(descriptor); + } + } + catch (Exception ex) + { + UnityEngine.Debug.LogWarning($"Pipeline: Failed to update runtime heartbeat: {ex.Message}"); + } + } + + /// + /// Test-only override of the detected platform, so the Android branch below is reachable + /// without a real device. Null (the default) uses the real . + /// + internal static RuntimePlatform? OverridePlatform; + + internal static string GetDescriptorFilePath() + { + var platform = OverridePlatform ?? Application.platform; + + // On Android, Application.dataPath points inside the read-only, system-owned APK + // install directory (e.g. ".../base.apk") — the app cannot write there. persistentDataPath + // is the one location Unity guarantees is writable on Android (UUM-151968). + var workingDir = platform == RuntimePlatform.Android + ? Application.persistentDataPath + : new FileInfo($"{Application.dataPath}/..").FullName; + + return Path.Combine(workingDir, RuntimeDescriptorFileName); + } + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/RuntimeInstanceDescriptor.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Models/RuntimeInstanceDescriptor.cs.meta new file mode 100644 index 0000000..6c7a30e --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/RuntimeInstanceDescriptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a7787403e02096545b7798cd3d5d076d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/StatusResponse.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Models/StatusResponse.cs new file mode 100644 index 0000000..9eb853e --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/StatusResponse.cs @@ -0,0 +1,62 @@ +using System; +using Newtonsoft.Json; + +namespace Unity.Pipeline.Models +{ + /// + /// Response model for /api/status endpoint. + /// Provides Editor state information for CLI tools and automation scripts. + /// + [Serializable] + public class StatusResponse + { + /// + /// Current Editor status: "ready", "compiling", "busy" + /// + [JsonProperty("status")] + public string Status { get; set; } + + /// + /// Whether Unity is currently compiling scripts + /// + [JsonProperty("compiling")] + public bool Compiling { get; set; } + + /// + /// Whether a domain reload is in progress + /// + [JsonProperty("domainReloadInProgress")] + public bool DomainReloadInProgress { get; set; } + + /// + /// Current play mode state: "stopped", "playing", "paused" + /// + [JsonProperty("playMode")] + public string PlayMode { get; set; } + + /// + /// Timestamp of last heartbeat update + /// + [JsonProperty("lastHeartbeat")] + public DateTime LastHeartbeat { get; set; } + + /// + /// Full path to the Unity project + /// + [JsonProperty("projectPath")] + public string ProjectPath { get; set; } + + /// + /// Unity Editor version string + /// + [JsonProperty("unityVersion")] + public string UnityVersion { get; set; } + + /// + /// The dialog currently blocking the main thread, present only when + /// is "blocked_by_dialog". + /// + [JsonProperty("dialog", NullValueHandling = NullValueHandling.Ignore)] + public object Dialog { get; set; } + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/StatusResponse.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Models/StatusResponse.cs.meta new file mode 100644 index 0000000..12a903d --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/StatusResponse.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 86f7bba2bb7101544a486545cb8e2f70 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/TestExecutionResponse.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Models/TestExecutionResponse.cs new file mode 100644 index 0000000..d64991d --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/TestExecutionResponse.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using Unity.Pipeline.Models; + +namespace Unity.Pipeline +{ + /// + /// Response for test execution commands, containing summary and detailed results + /// + [Serializable] + class TestExecutionResponse : CommandExecutionResponse + { + /// Aggregate pass/fail/skip counts for the run. + public TestSummary Summary { get; set; } + /// Per-test results. + public List Results { get; set; } + /// Total run duration, in seconds. + public double Duration { get; set; } + /// Path to poll for status when the run was started in async mode. + public string StatusPath { get; set; } // For async mode + /// Which suite was run: EditMode, PlayMode, or All. + public string Mode { get; set; } // EditMode, PlayMode, or All + /// The test filter that was applied, if any. + public string FilterApplied { get; set; } // What filter was used, if any + + /// Create an empty response with initialized collections. + public TestExecutionResponse() + { + Results = new List(); + Summary = new TestSummary(); + } + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/TestExecutionResponse.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Models/TestExecutionResponse.cs.meta new file mode 100644 index 0000000..29f2d39 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/TestExecutionResponse.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 27c96238399817b4c8ffb66925bcbc6f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/TestResult.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Models/TestResult.cs new file mode 100644 index 0000000..83d4790 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/TestResult.cs @@ -0,0 +1,22 @@ +using System; + +namespace Unity.Pipeline +{ + /// + /// Individual test result information + /// + [Serializable] + class TestResult + { + /// Fully-qualified test name. + public string FullName { get; set; } + /// Outcome: Passed, Failed, Skipped, or Inconclusive. + public string Status { get; set; } // Passed, Failed, Skipped, Inconclusive + /// How long the test took, in seconds. + public double Duration { get; set; } + /// Failure message, if any. + public string Message { get; set; } + /// Failure stack trace, if any. + public string StackTrace { get; set; } + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/TestResult.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Models/TestResult.cs.meta new file mode 100644 index 0000000..80f8419 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/TestResult.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7ccc266e8f58db84dab523cd4dabc489 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/TestSummary.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Models/TestSummary.cs new file mode 100644 index 0000000..443c1a8 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/TestSummary.cs @@ -0,0 +1,32 @@ +using System; + +namespace Unity.Pipeline +{ + /// + /// Summary statistics for test execution + /// + [Serializable] + class TestSummary + { + /// Total number of tests run. + public int Total { get; set; } + /// Number of tests that passed. + public int Passed { get; set; } + /// Number of tests that failed. + public int Failed { get; set; } + /// Number of tests skipped. + public int Skipped { get; set; } + /// Number of tests that ran but produced no pass/fail verdict. + public int Inconclusive { get; set; } + + /// Create a zeroed summary. + public TestSummary() + { + Total = 0; + Passed = 0; + Failed = 0; + Skipped = 0; + Inconclusive = 0; + } + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Models/TestSummary.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Models/TestSummary.cs.meta new file mode 100644 index 0000000..7bbaa28 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Models/TestSummary.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: df11040e7d969ff4fa8aaa417c44bd44 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport.meta b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport.meta new file mode 100644 index 0000000..21bb235 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4a339d7263cb1ac4f879d79c8e7fe3ca +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/CodeReloadStatusOverlay.cs b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/CodeReloadStatusOverlay.cs new file mode 100644 index 0000000..c1acbab --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/CodeReloadStatusOverlay.cs @@ -0,0 +1,120 @@ +using UnityEngine; +using Unity.Pipeline.CodeReload; + +namespace Unity.Pipeline +{ + /// + /// Minimal on-screen code-reload status for players: what is happening now (compiling → applied, + /// or failed) and how many method overrides are active. Deliberately IMGUI — no canvas, + /// EventSystem or render-pipeline dependency, and it is development-only anyway (the body + /// compiles out of release players; the type itself stays so AddComponent call sites compile). + /// Added automatically by when its + /// reload-overlay flag is on. Hidden entirely while idle with no overrides. + /// + [DisallowMultipleComponent] + class CodeReloadStatusOverlay : MonoBehaviour + { +#if UNITY_EDITOR || DEVELOPMENT_BUILD || ENABLE_RUNTIME_PIPELINE + // How long the "applied" confirmation stays up before falling back to the count line. + private const int AppliedFlashMs = 3500; + // A "compiling…" with no follow-up payload or failure notice goes stale (editor died, + // connection dropped) — stop showing it after this. + private const int CompilingStaleMs = 15000; + private const float StatsPollSeconds = 1f; + private const int MaxMessageLength = 96; + + private int m_OverrideCount; + private int m_CallsPerSecond; + private long m_LastCallCount; + private float m_LastPollTime; + private float m_NextStatsPoll; + private GUIStyle m_Style; + + private void Update() + { + // GetStats() allocates; poll at 1 Hz instead of per frame. + if (Time.unscaledTime >= m_NextStatsPoll) + { + m_NextStatsPoll = Time.unscaledTime + StatsPollSeconds; + m_OverrideCount = CodeReloadRegistry.GetStats().ActiveOverrideCount; + + long calls = CodeReloadActivity.OverrideCallCount; + float elapsed = Time.unscaledTime - m_LastPollTime; + if (m_LastPollTime > 0 && elapsed > 0) + m_CallsPerSecond = (int)((calls - m_LastCallCount) / elapsed); + m_LastCallCount = calls; + m_LastPollTime = Time.unscaledTime; + } + } + + private void OnGUI() + { + var phase = CodeReloadActivity.Snapshot(out var message, out var ageMs); + + string activity = null; + Color activityColor = Color.white; + switch (phase) + { + case CodeReloadActivity.Phase.Compiling when ageMs < CompilingStaleMs: + activity = $"compiling {Truncate(message)}…"; + activityColor = new Color(1f, 0.8f, 0.25f); // amber + break; + case CodeReloadActivity.Phase.Applied when ageMs < AppliedFlashMs: + activity = Truncate(message); + activityColor = new Color(0.45f, 1f, 0.45f); // green + break; + case CodeReloadActivity.Phase.Failed: + activity = Truncate(message); // sticky until the next reload attempt + activityColor = new Color(1f, 0.45f, 0.45f); // red + break; + } + + if (activity == null && m_OverrideCount == 0) + return; // nothing to show + + m_Style ??= new GUIStyle(GUI.skin.label) { fontSize = 12, wordWrap = false }; + + var lines = activity != null + ? new[] { ($"CodeReload: {activity}", activityColor), (CountLine(), Color.white) } + : new[] { (CountLine(), Color.white) }; + + float width = 0, height = 4; + foreach (var l in lines) + { + var s = m_Style.CalcSize(new GUIContent(l.Item1)); + if (s.x > width) width = s.x; + height += s.y; + } + + var box = new Rect(8, 8, width + 12, height + 4); + GUI.color = new Color(0f, 0f, 0f, 0.6f); + GUI.DrawTexture(box, Texture2D.whiteTexture); + + float y = box.y + 4; + foreach (var l in lines) + { + var size = m_Style.CalcSize(new GUIContent(l.Item1)); + var r = new Rect(box.x + 6, y, size.x, size.y); + // 1px shadow keeps it readable over bright scenes. + GUI.color = new Color(0f, 0f, 0f, 0.9f); + GUI.Label(new Rect(r.x + 1, r.y + 1, r.width, r.height), l.Item1, m_Style); + GUI.color = l.Item2; + GUI.Label(r, l.Item1, m_Style); + y += size.y; + } + GUI.color = Color.white; + } + + // "N overrides · 0 calls/s" is a diagnostic in itself: bound but never dispatched. + private string CountLine() => $"{m_OverrideCount} override(s) active · {m_CallsPerSecond} calls/s"; + + private static string Truncate(string s) + { + if (string.IsNullOrEmpty(s)) return ""; + int nl = s.IndexOf('\n'); + if (nl >= 0) s = s.Substring(0, nl); // failures can carry multi-line diagnostics + return s.Length <= MaxMessageLength ? s : s.Substring(0, MaxMessageLength) + "…"; + } +#endif + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/CodeReloadStatusOverlay.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/CodeReloadStatusOverlay.cs.meta new file mode 100644 index 0000000..cb29d33 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/CodeReloadStatusOverlay.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d38c4fa15aa73074793fc9d4f45cb451 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/FrameStatsSampler.cs b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/FrameStatsSampler.cs new file mode 100644 index 0000000..9561b1a --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/FrameStatsSampler.cs @@ -0,0 +1,225 @@ +using System; +using System.Collections.Generic; +using Unity.Profiling; +using UnityEngine; +#if UNITY_6000_5_OR_NEWER +using Unity.Scripting.LifecycleManagement; +#endif + +namespace Unity.Pipeline.Runtime.Telemetry +{ + /// + /// Samples per-frame timing on the main thread so the runtime telemetry command can report fps and + /// frame-time statistics over a rolling window. + /// + /// A Player build has no Editor profiler window to read from and no EditorApplication.update + /// to drive sampling, so owns one shared instance and feeds it + /// every frame from its Update. The sampler is deliberately allocation-free on the hot path: + /// each frame time is written into a fixed ring buffer and only reduced to a + /// on demand when a telemetry request arrives (far rarer than the frame rate). + /// + /// Sampling uses Time.unscaledDeltaTime so reported fps reflects real wall-clock frame pacing + /// independent of Time.timeScale — a paused or slow-motion game still reports its true fps. + /// +#if UNITY_6000_5_OR_NEWER + [NoAutoStaticsCleanup] +#endif + sealed class FrameStatsSampler : IDisposable + { + /// + /// The process-wide sampler fed by the active . Null when no + /// driver is present (e.g. EditMode tests, or a Player build without Pipeline enabled). Telemetry consumers + /// must treat a null sampler as "frame stats unavailable" rather than failing — memory and counter + /// data that do not depend on per-frame sampling can still be reported without it. + /// + public static FrameStatsSampler Shared { get; set; } + + private readonly float[] m_FrameTimesMs; + private int m_Head; + private int m_Count; + private float m_LastFrameTimeMs; + + // ProfilerRecorders pull counters straight from the profiler stream. They are started lazily on + // the first snapshot (creation must happen on the main thread) and disposed with the sampler. + // Recorders that do not resolve on this platform/Unity version report Valid == false and are + // simply skipped when building a snapshot. + private readonly List m_Counters = new List(); + private bool m_CountersStarted; + + private struct CounterRecorder + { + public string Name; + public ProfilerRecorder Recorder; + } + + /// Number of frames the rolling window can hold. + public int Capacity => m_FrameTimesMs.Length; + + /// Number of frames currently recorded (ramps up to ). + public int SampleCount => m_Count; + + /// Create a sampler with the given rolling-window size. + /// Number of frames the rolling window holds (minimum 1). + public FrameStatsSampler(int windowFrames = 120) + { + if (windowFrames < 1) + windowFrames = 1; + m_FrameTimesMs = new float[windowFrames]; + } + + /// + /// Record one completed frame. Call once per frame from the main thread. + /// is the unscaled delta time of the frame just completed + /// (typically Time.unscaledDeltaTime). + /// + /// Unscaled delta time of the frame just completed. + public void Sample(float deltaSeconds) + { + var ms = deltaSeconds * 1000f; + m_LastFrameTimeMs = ms; + m_FrameTimesMs[m_Head] = ms; + m_Head = (m_Head + 1) % m_FrameTimesMs.Length; + if (m_Count < m_FrameTimesMs.Length) + m_Count++; + + // FrameTimingManager only yields data for frames in which timings were captured, so the + // capture call has to happen on the per-frame path, not when a snapshot is requested. + FrameTimingManager.CaptureFrameTimings(); + } + + /// + /// Reduce the current window to an immutable snapshot. Must be called on the main thread (it reads + /// profiler recorders and the frame timing manager). + /// + /// A point-in-time snapshot of the current window. + public FrameStatsSnapshot GetSnapshot() + { + var snap = new FrameStatsSnapshot(); + + if (m_Count > 0) + { + float sum = 0f, min = float.MaxValue, max = 0f; + for (int i = 0; i < m_Count; i++) + { + var v = m_FrameTimesMs[i]; + sum += v; + if (v < min) min = v; + if (v > max) max = v; + } + + var avg = sum / m_Count; + snap.Available = true; + snap.SampleWindow = m_Count; + snap.AverageFrameTimeMs = avg; + snap.MinFrameTimeMs = min; + snap.MaxFrameTimeMs = max; + snap.LastFrameTimeMs = m_LastFrameTimeMs; + snap.Fps = avg > 0f ? 1000f / avg : 0f; + } + + ReadFrameTimingManager(snap); + ReadCounters(snap); + return snap; + } + + // CPU/GPU frame time from FrameTimingManager. Only populated when the platform reports timings + // (requires "Frame Timing Stats" in Player settings / -enable-frame-timing-stats); otherwise the + // snapshot's GpuTimingAvailable stays false rather than reporting misleading zeros. + private static void ReadFrameTimingManager(FrameStatsSnapshot snap) + { + var timings = new FrameTiming[1]; + var captured = FrameTimingManager.GetLatestTimings(1, timings); + if (captured > 0) + { + snap.GpuTimingAvailable = true; + snap.CpuFrameTimeMs = timings[0].cpuFrameTime; + snap.GpuFrameTimeMs = timings[0].gpuFrameTime; + } + } + + private void ReadCounters(FrameStatsSnapshot snap) + { + EnsureCountersStarted(); + var counters = new Dictionary(); + foreach (var c in m_Counters) + { + if (c.Recorder.Valid) + counters[c.Name] = c.Recorder.LastValue; + } + snap.Counters = counters; + } + + private void EnsureCountersStarted() + { + if (m_CountersStarted) + return; + m_CountersStarted = true; + + // Common render/memory counters. Stat names that do not exist on the running platform resolve + // to invalid recorders and are filtered out at snapshot time. + TryAddCounter("DrawCalls", ProfilerCategory.Render, "Draw Calls Count"); + TryAddCounter("SetPassCalls", ProfilerCategory.Render, "SetPass Calls Count"); + TryAddCounter("Triangles", ProfilerCategory.Render, "Triangles Count"); + TryAddCounter("Vertices", ProfilerCategory.Render, "Vertices Count"); + TryAddCounter("GcAllocInFrame", ProfilerCategory.Memory, "GC Allocated In Frame"); + } + + private void TryAddCounter(string reportedName, ProfilerCategory category, string statName) + { + m_Counters.Add(new CounterRecorder + { + Name = reportedName, + Recorder = ProfilerRecorder.StartNew(category, statName) + }); + } + + /// Dispose the underlying profiler recorders. + public void Dispose() + { + foreach (var c in m_Counters) + { + if (c.Recorder.Valid) + c.Recorder.Dispose(); + } + m_Counters.Clear(); + m_CountersStarted = false; + } + } + + /// + /// Immutable point-in-time reduction of 's rolling window plus the + /// counters/frame-timing read at snapshot time. Serialized as the frame-stats portion of the runtime + /// telemetry response. + /// + [Serializable] + class FrameStatsSnapshot + { + /// True when at least one frame has been sampled (i.e. a manager is feeding the sampler). + public bool Available { get; set; } + + /// Number of frames included in the averages. + public int SampleWindow { get; set; } + + /// Frames per second derived from the average frame time over the window. + public float Fps { get; set; } + + /// Average frame time over the window, in milliseconds. + public float AverageFrameTimeMs { get; set; } + /// Minimum frame time over the window, in milliseconds. + public float MinFrameTimeMs { get; set; } + /// Maximum frame time over the window, in milliseconds. + public float MaxFrameTimeMs { get; set; } + /// Most recently sampled frame's time, in milliseconds. + public float LastFrameTimeMs { get; set; } + + /// True when FrameTimingManager returned CPU/GPU timings for a recent frame. + public bool GpuTimingAvailable { get; set; } + /// CPU frame time from FrameTimingManager, in milliseconds. Only valid when is true. + public double CpuFrameTimeMs { get; set; } + /// GPU frame time from FrameTimingManager, in milliseconds. Only valid when is true. + public double GpuFrameTimeMs { get; set; } + + /// Valid profiler counters by reported name (e.g. DrawCalls, Triangles). + public Dictionary Counters { get; set; } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/FrameStatsSampler.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/FrameStatsSampler.cs.meta new file mode 100644 index 0000000..4fd085d --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/FrameStatsSampler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0e2b7696d6f845cba4f7c776006707d1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineBootstrap.cs b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineBootstrap.cs new file mode 100644 index 0000000..ded5be1 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineBootstrap.cs @@ -0,0 +1,67 @@ +using System.Collections.Generic; +using Unity.Pipeline.Config; +using UnityEngine; + +namespace Unity.Pipeline +{ + /// + /// Creates the runtime Pipeline driver automatically when a Player boots (or Play Mode is + /// entered in the Editor) — no scene setup required. Reads RuntimePipelineConfig (JSON-backed + /// in the Editor, a build-baked Resources asset in a Player) and the build-baked + /// RuntimePipelineBuildInfo from Resources; does nothing if no config exists or the config + /// has the server disabled. + /// + public static class RuntimePipelineBootstrap + { + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] + static void RuntimeBootstrap() + { + Bootstrap(); + } + + /// + /// The driver created by , or null if it has not run yet (or created + /// nothing because there was no usable config). Reachable for tests and manual control. + /// + public static RuntimePipelineDriver Instance { get; internal set; } + + /// + /// Core bootstrap logic, split out from the attributed entry point so tests can invoke it + /// directly instead of waiting for a real domain/Player boot. Returns the created driver, + /// or null if the server should not start (no config asset, or disabled). Idempotent: a + /// second call returns the existing rather than creating a duplicate. + /// + /// The created (or already-existing) driver, or null if the server should not start. + public static RuntimePipelineDriver Bootstrap() + { + if (Instance != null) + return Instance; + + var config = RuntimePipelineConfig.Load(); + if (config == null || !config.enableInBuilds) + { +#if UNITY_EDITOR + // The runtime server is a player-build feature, but in-editor code reload still + // needs the [CodeReload] targets registered for this Play session — the driver + // would do it in Awake; with no driver, do it here so a save can bind. + RuntimePipelineDriver.RegisterDiscoveredCodeReloadMethods(); +#endif + return null; + } + + var buildInfo = RuntimePipelineBuildInfo.Load(); + IReadOnlyList roots = buildInfo != null + ? (IReadOnlyList)buildInfo.allowedReloadRoots + : System.Array.Empty(); + // Empty when there's no build info (e.g. play mode never built): the driver then rejects + // every push, which is the correct strict default outside a real signed build. + string pushPublicKey = buildInfo != null ? buildInfo.pushPublicKey : ""; + + var go = new GameObject("Pipeline Runtime Driver") { hideFlags = HideFlags.DontSave }; + var driver = go.AddComponent(); + driver.Initialize(config, roots, pushPublicKey); + Instance = driver; + return driver; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineBootstrap.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineBootstrap.cs.meta new file mode 100644 index 0000000..e49ee49 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineBootstrap.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: da4d1b70b51a29841938b3c1361b8300 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineBuildInfo.cs b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineBuildInfo.cs new file mode 100644 index 0000000..dd24060 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineBuildInfo.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace Unity.Pipeline.Config +{ + /// + /// Build-only, generated companion to : holds the absolute, + /// machine-specific code-reload roots baked in by PipelineRuntimeBuildProcessor. Created fresh + /// before each build and deleted immediately after — never checked into source control, since + /// its contents are meaningless outside the machine that produced them. Absent outside of a + /// real build (e.g. Editor Play Mode without ever having built) is not an error; + /// RuntimePipelineBootstrap simply has no roots to allow in that case. + /// + public class RuntimePipelineBuildInfo : ScriptableObject + { + /// Resource name this asset must be saved under inside a Resources folder for to find it. + public const string ResourceName = "RuntimePipelineBuildInfo"; + + /// Absolute paths of the project's Assets folder and every loaded package, baked in at build time. + public List allowedReloadRoots = new List(); + + /// Public half of the project's push-signing key (from Library/Pipeline/signing.key). + /// A player build rejects every code-reload push not signed by the matching private key; empty + /// means reject all pushes (strict policy — there is deliberately no unsigned fallback). + public string pushPublicKey = ""; + + /// Load the asset from Resources, or null if this is not a real build. + /// The build-time-baked info, or null if this is not a real build. + public static RuntimePipelineBuildInfo Load() => Resources.Load(ResourceName); + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineBuildInfo.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineBuildInfo.cs.meta new file mode 100644 index 0000000..3aa9184 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineBuildInfo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bffff28fa8e3a084d86374beef94b84d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineConfig.cs b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineConfig.cs new file mode 100644 index 0000000..fccaef0 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineConfig.cs @@ -0,0 +1,222 @@ +using System; +#if UNITY_EDITOR +using System.IO; +#endif +using UnityEngine; + +namespace Unity.Pipeline.Config +{ + /// + /// Configuration for Pipeline server functionality in Unity Player builds. Authored settings + /// live in a JSON file under ProjectSettings/ (see /) — + /// never as an asset under Assets/, so nothing about this package appears in the user's + /// Project window. At real Player build time, PipelineRuntimeBuildProcessor bakes the current + /// settings into a transient Resources asset (deleted again after the build) so the Player + /// can find them via Resources.Load. + /// + public class RuntimePipelineConfig : ScriptableObject + { + /// Master switch. The server only starts when true. Off by default for safety. + [Tooltip("Enable Pipeline HTTP server in Player builds. SECURITY WARNING: Only enable in development/QA builds, never production without proper security measures.")] + public bool enableInBuilds = false; + + /// Listen port. 0 auto-assigns from 7900-7999. + [Header("Server")] + [Tooltip("HTTP port for Pipeline server. Use 0 for auto-assignment from range 7900-7999.")] + public int port = 0; + + /// Per-request timeout, in milliseconds. + [Tooltip("Request timeout in milliseconds. Higher values allow longer-running commands.")] + [Range(1000, 60000)] + public int requestTimeoutMs = 30000; + + /// Log remote requests for auditing. + [Header("Runtime Behavior")] + [Tooltip("Enable detailed logging of all remote requests for security auditing.")] + public bool enableAuditLogging = true; + + /// Start the server automatically when the Player boots (or Play Mode is entered). + [Tooltip("Start the server automatically when the Player boots (or Play Mode is entered).")] + public bool autoStart = true; + + /// Dispatcher work items processed per frame. + [Tooltip("Maximum work items the dispatcher processes per frame to maintain performance.")] + [Range(1, 50)] + public int maxWorkItemsPerFrame = 10; + + // Plain int field (not [Range]) so the Inspector shows a text field rather than an + // unusable 0-65535 slider; the bound is still enforced here, same pattern as + // EditorPipelineManager.OnValidate's m_WatchdogIntervalSeconds clamp. + private void OnValidate() + { + port = Mathf.Clamp(port, 0, 65535); + } + + /// Resource name the build-time-generated transient asset is saved under for to find in a Player build. + public const string ResourceName = "RuntimePipelineConfig"; + +#if UNITY_EDITOR + /// Project-relative path of the authored settings file (never under Assets/). + private const string SettingsFilePath = "ProjectSettings/Packages/com.unity.pipeline/RuntimePipelineConfig.json"; +#endif + + /// + /// Load the current settings, or null if none exist yet. In the Editor (including Play + /// Mode) this reads the authored ProjectSettings/ JSON file directly; in a real Player + /// build it reads the build-time-generated transient Resources asset. + /// + /// The current settings, or null if none exist yet. + public static RuntimePipelineConfig Load() + { +#if UNITY_EDITOR + var path = GetAbsoluteSettingsPath(); + if (!File.Exists(path)) + return null; + + var config = CreateInstance(); + try + { + JsonUtility.FromJsonOverwrite(File.ReadAllText(path), config); + } + catch (Exception ex) + { + Debug.LogWarning($"Pipeline: could not read runtime settings at '{path}' ({ex.Message}); using no config. Delete the file to reset."); + DestroyImmediate(config); + return null; + } + return config; +#else + return Resources.Load(ResourceName); +#endif + } + +#if UNITY_EDITOR + private static int s_LiveMaxWorkItemsPerFrameCache = 10; + private static DateTime s_LiveMaxWorkItemsPerFrameCacheFileTime; + + /// + /// Cheap, per-frame-callable read of just maxWorkItemsPerFrame from the authored settings + /// file, for RuntimePipelineDriver.Update() to poll without paying Load()'s full + /// CreateInstance+JSON-parse cost every frame. Re-parses only when the file's last-write + /// time changes, so a Project Settings edit (including while in Play Mode) takes effect on + /// the very next frame, while an idle frame costs only a single file-timestamp check. + /// Editor-only: a Player's config is frozen at build time, so there is nothing to poll for. + /// + public static int GetLiveMaxWorkItemsPerFrame(int fallback) + { + var path = GetAbsoluteSettingsPath(); + if (!File.Exists(path)) + return fallback; + + var writeTime = File.GetLastWriteTimeUtc(path); + if (writeTime != s_LiveMaxWorkItemsPerFrameCacheFileTime) + { + var config = Load(); + if (config != null) + { + s_LiveMaxWorkItemsPerFrameCache = config.maxWorkItemsPerFrame; + DestroyImmediate(config); + } + s_LiveMaxWorkItemsPerFrameCacheFileTime = writeTime; + } + + return s_LiveMaxWorkItemsPerFrameCache; + } + + /// Persist this instance's current field values to the ProjectSettings/ JSON file. + public void Save() + { + var path = GetAbsoluteSettingsPath(); + Directory.CreateDirectory(Path.GetDirectoryName(path)); + var previousWrite = File.Exists(path) ? File.GetLastWriteTimeUtc(path) : DateTime.MinValue; + File.WriteAllText(path, JsonUtility.ToJson(this, true)); + + // GetLiveMaxWorkItemsPerFrame and the settings page detect changes by last-write time. + // Windows stamps writes with the system clock tick (~15 ms), so two saves in quick + // succession can share a stamp and the second one goes unnoticed. Make every save + // observable by moving the stamp forward when the file system did not. + if (File.GetLastWriteTimeUtc(path) <= previousWrite) + File.SetLastWriteTimeUtc(path, previousWrite.AddMilliseconds(1)); + } + + /// + /// Last-write-time of the authored settings file (UTC), or DateTime.MinValue if it doesn't + /// exist yet. Lets a long-lived caller (the Project Settings page) detect that the file + /// changed underneath it — e.g. a build's "Disable Pipeline" security-dialog choice, or a + /// set_runtime_pipeline_settings CLI call — without reloading from disk on every frame. + /// + public static DateTime GetSettingsFileWriteTimeUtc() + { + var path = GetAbsoluteSettingsPath(); + return File.Exists(path) ? File.GetLastWriteTimeUtc(path) : DateTime.MinValue; + } + + /// Delete the authored settings file, if any. For test cleanup only. + public static void DeleteSettingsFileForTesting() + { + var path = GetAbsoluteSettingsPath(); + if (File.Exists(path)) + File.Delete(path); + } + + private static string GetAbsoluteSettingsPath() + { + // Application.dataPath is ".../Assets"; ProjectSettings is a sibling directory. + var projectRoot = Path.GetDirectoryName(Application.dataPath); + return Path.Combine(projectRoot, SettingsFilePath); + } +#endif + + /// + /// Validate the configuration for correctness. + /// Called by build processor to ensure safe deployment. + /// + /// The validation result. + public ValidationResult Validate() + { + if (!enableInBuilds) + return ValidationResult.Success("Runtime Pipeline disabled"); + + // Port validation + if (port != 0 && (port < 7900 || port > 7999)) + { + return ValidationResult.Warning( + $"Port {port} is outside recommended runtime range 7900-7999. May conflict with Editor instances."); + } + + return ValidationResult.Success("Configuration is valid"); + } + } + + /// + /// Result from configuration validation. + /// + [Serializable] + public class ValidationResult + { + /// False only for results. + public bool IsValid { get; set; } + /// "success", "warning", or "error". + public string Level { get; set; } // "success", "warning", "error" + /// Human-readable validation message. + public string Message { get; set; } + + /// Create a successful validation result. + /// Human-readable message. + /// A valid, "success"-level result. + public static ValidationResult Success(string message = "Valid") => + new ValidationResult { IsValid = true, Level = "success", Message = message }; + + /// Create a valid-but-noteworthy validation result. + /// Human-readable message. + /// A valid, "warning"-level result. + public static ValidationResult Warning(string message) => + new ValidationResult { IsValid = true, Level = "warning", Message = message }; + + /// Create a failed validation result. + /// Human-readable message. + /// An invalid, "error"-level result. + public static ValidationResult Error(string message) => + new ValidationResult { IsValid = false, Level = "error", Message = message }; + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineConfig.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineConfig.cs.meta new file mode 100644 index 0000000..7f579c1 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineConfig.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0fd19cf31d54e3848a1075f001aed64f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineDriver.cs b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineDriver.cs new file mode 100644 index 0000000..7722f1b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineDriver.cs @@ -0,0 +1,664 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using Unity.Pipeline.Config; +using Unity.Pipeline.Commands; +using Unity.Pipeline.CodeReload; +using Unity.Pipeline.Runtime.Telemetry; +using UnityEngine; +#if (UNITY_EDITOR || DEVELOPMENT_BUILD || ENABLE_RUNTIME_PIPELINE) +using UnityEngine.Networking.PlayerConnection; +#endif + +namespace Unity.Pipeline +{ + /// + /// Drives the runtime Pipeline server. Created exactly once, in code, by + /// — never authored in a scene. Hidden from Add + /// Component (nothing to configure via the Inspector; see instead) + /// and guarded against stacking multiple instances on one GameObject, in case it's ever added + /// manually or via a script despite that. + /// + [AddComponentMenu("")] + [DisallowMultipleComponent] + public class RuntimePipelineDriver : MonoBehaviour + { + // Not yet exposed via RuntimePipelineConfig/the runtime settings page — always on. Wire up + // through m_Config alongside the other Runtime Behavior settings if a project needs to + // disable the overlay. + private const bool ShowReloadOverlay = true; + + private RuntimePipelineServer m_Server; + private RuntimePipelineConfig m_Config; + private IReadOnlyList m_AllowedReloadRoots = Array.Empty(); + + // Public half of the project's push-signing key. Baked at build time into the + // RuntimePipelineBuildInfo asset (from Library/Pipeline/signing.key in the editor) and + // supplied via Initialize — a player build rejects every code-reload push that is not signed + // by the matching private key; empty means "reject all pushes" (strict policy, no fallback). + private string m_PushPublicKey = ""; + private bool m_OwnsSampler; + + // Restored by StopServer so Play Mode exit doesn't leave the user's setting overridden. + private bool m_PreviousRunInBackground; + + // True only between something overriding Application.runInBackground (StartServer, or + // DrainPendingReloads reacting to a code-reload push that arrived with no HTTP server + // running) and StopServer restoring it. Both writers check this before saving + // m_PreviousRunInBackground, so whichever gets there first "owns" the saved value — the + // other must not clobber it with the already-overridden "true". Gating the restore on this + // (rather than m_Server.IsRunning) also means it still happens even if the listener already + // died on its own before StopServer runs — otherwise runInBackground would stay stuck on, + // reproducing a narrower version of the bug this ownership move fixed in the first place. + private bool m_RunInBackgroundOverridden; + + /// Get the runtime server instance if it's running. + public RuntimePipelineServer Server => m_Server; + + /// Whether the server is currently running. + public bool IsServerRunning => m_Server != null && m_Server.IsRunning; + + /// Get the actual port the server is running on. + public int ActualPort => m_Server?.Port ?? 0; + + /// The configuration this driver was initialized with. + public RuntimePipelineConfig Config => m_Config; + + /// Absolute roots this build may code reload source files from. Baked at build time. + public IReadOnlyList AllowedReloadRoots => m_AllowedReloadRoots; + + /// + /// Supply configuration and baked code-reload roots. Must be called once, immediately after + /// AddComponent (before the end of the current frame, i.e. before Start runs). + /// + /// The configuration to run with. + /// Absolute roots this build may code reload source files from. + /// Public half of the push-signing key pushes must be signed with; empty rejects all pushes. + public void Initialize(RuntimePipelineConfig config, IReadOnlyList allowedReloadRoots, + string pushPublicKey = "") + { + m_Config = config; + m_AllowedReloadRoots = allowedReloadRoots ?? Array.Empty(); + m_PushPublicKey = pushPublicKey ?? ""; + } + + /// Public half of the project push-signing key. Baked at build time. + public string PushPublicKey => m_PushPublicKey; + + void Awake() + { + // Persistent across scene loads; exactly one of these ever exists (created by + // RuntimePipelineBootstrap), so there is no duplicate-instance case to defend against. + // DontDestroyOnLoad only functions (and is only legal to call) in Play Mode; invoking it + // from an Edit Mode context (e.g. an EditMode test, or this driver created via eval) + // throws, which would otherwise abort the rest of Awake below. + if (Application.isPlaying) + DontDestroyOnLoad(gameObject); + + // Set up command discovery (the server owns its own dispatcher, initialized on Start). + CommandRegistry.SetDiscovery(null); // Triggers reflection-based discovery + + // Auto-discover and register reloadable methods. Code reload requires this driver to + // be present (it owns the communication workflow), so discovery lives here rather than in + // each gameplay script's Awake. + RegisterDiscoveredCodeReloadMethods(); + + // Own the process-wide frame-stats sampler. A Player has no profiler window or + // EditorApplication.update to drive sampling, so the driver feeds it from Update (below) and + // the runtime_status telemetry command reads FrameStatsSampler.Shared. Created here (rather than + // on server start) so fps history is already warm by the time an agent connects. Only claim + // ownership if nothing already created one — a second, transient driver (e.g. a test creating + // its own driver alongside one RuntimeInitializeOnLoadMethod already created) must not steal or + // later tear down a sibling driver's sampler. + if (FrameStatsSampler.Shared == null) + { + FrameStatsSampler.Shared = new FrameStatsSampler(); + m_OwnsSampler = true; + } + } + + void Start() + { + if (m_Config != null && m_Config.autoStart && m_Config.enableInBuilds) + { + StartServer(); + } + +#if (UNITY_EDITOR || DEVELOPMENT_BUILD || ENABLE_RUNTIME_PIPELINE) + // Independent of the HTTP server: code-reload IL pushed from the editor arrives over + // PlayerConnection (the Profiler's channel — no open port needed, tunnels over USB). + RegisterReloadReceiver(); + + if (ShowReloadOverlay && GetComponent() == null) + gameObject.AddComponent(); +#endif + } + + /// + /// Scan loaded user assemblies for methods tagged [CodeReload] and register them as reload targets. + /// + /// + /// Scan loaded user assemblies for [CodeReload] methods and register them as reload + /// targets. Runs from Awake; RuntimePipelineBootstrap also calls it in the Editor when the + /// runtime server is disabled and no driver is created. + /// + internal static void RegisterDiscoveredCodeReloadMethods() + { + const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic + | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly; + + int registered = 0; + + foreach (var assembly in PipelineUtils.GetLoadedAssemblies()) + { + if (!ShouldScanForCodeReload(assembly)) + continue; + + Type[] types; + try + { + types = assembly.GetTypes(); + } + catch (ReflectionTypeLoadException ex) + { + types = ex.Types; // best effort: keep the types that did load + } + + foreach (var type in types) + { + if (type == null) + continue; + + foreach (var method in type.GetMethods(flags)) + { + var reloadable = method.GetCustomAttribute(); + if (reloadable == null) + continue; + + // The weaver keys dispatch on TypeName.MethodName, so register with the + // default id (ignore any custom Id) to match. + CodeReloadRegistry.RegisterReloadableMethod( + method, new CodeReloadAttribute { RequireMainThread = reloadable.RequireMainThread }); + registered++; + } + } + } + + // The count only matters once someone tries to reload, so it joins the first-reload + // summary instead of the startup noise (this runs on every Play Mode entry). That holds + // for zero too: the summary prints on the first reload ATTEMPT, so a project that never + // reloads stays quiet, and one that does sees the stripping/attribute hint right next to + // the "target not registered" reasons. + CodeReloadRegistry.NoteForFirstReload($"{registered} reloadable method(s) registered" + + (registered == 0 + ? " (if methods were expected: are the [CodeReload] attributes in this build, and did the owning assembly survive stripping?)" + : "")); + } + + /// Skip engine/framework assemblies that cannot contain user code-reload methods. + private static bool ShouldScanForCodeReload(Assembly assembly) + { + if (assembly.IsDynamic) + return false; + + var name = assembly.GetName().Name; + if (string.IsNullOrEmpty(name)) + return false; + + foreach (var prefix in s_CodeReloadSkipPrefixes) + { + if (name.StartsWith(prefix, StringComparison.Ordinal)) + return false; + } + + return true; + } + + private static readonly string[] s_CodeReloadSkipPrefixes = + { + "System", "mscorlib", "netstandard", "Microsoft", "Mono.", "nunit", + "UnityEngine", "UnityEditor", "Unity.Collections", "Unity.Burst", + "Unity.Mathematics", "Newtonsoft", "log4net", "ICSharpCode", + }; + + /// + /// The maxWorkItemsPerFrame value actually governing the dispatcher right now — live from + /// the settings file in the Editor, frozen to the build-time value in a Player. Exposed + /// (rather than reading m_Config.maxWorkItemsPerFrame directly) so status reporting and + /// Update() can never disagree about which value is actually in effect. + /// + public int CurrentMaxWorkItemsPerFrame + { + get + { + var fallback = m_Config != null ? m_Config.maxWorkItemsPerFrame : 10; +#if UNITY_EDITOR + return RuntimePipelineConfig.GetLiveMaxWorkItemsPerFrame(fallback); +#else + return fallback; +#endif + } + } + + void Update() + { + // Feed the frame-stats sampler once per frame on the main thread. Uses unscaled delta so + // reported fps reflects real frame pacing regardless of Time.timeScale. + FrameStatsSampler.Shared?.Sample(Time.unscaledDeltaTime); + + // Pump this server's own dispatcher for main-thread operations (player builds have no + // EditorApplication.update to auto-pump it). + m_Server?.Dispatcher.ProcessWorkQueue(CurrentMaxWorkItemsPerFrame); + + // Drive the watchdog (player builds have no EditorApplication.update). No-op unless the + // server's watchdog is enabled and armed. + m_Server?.WatchdogTick(); + +#if (UNITY_EDITOR || DEVELOPMENT_BUILD || ENABLE_RUNTIME_PIPELINE) + DrainPendingReloads(); +#endif + } + + void OnApplicationQuit() + { + StopServer(); + } + + void OnDestroy() + { + StopServer(); + + if (RuntimePipelineBootstrap.Instance == this) + RuntimePipelineBootstrap.Instance = null; + + // Only the driver that actually created the shared sampler tears it down — see Awake(). + if (m_OwnsSampler) + { + FrameStatsSampler.Shared?.Dispose(); + FrameStatsSampler.Shared = null; + } +#if (UNITY_EDITOR || DEVELOPMENT_BUILD || ENABLE_RUNTIME_PIPELINE) + UnregisterReloadReceiver(); +#endif + } + +#if (UNITY_EDITOR || DEVELOPMENT_BUILD || ENABLE_RUNTIME_PIPELINE) + // ---- PlayerConnection code-reload receiver (editor pushes compiled override IL to this player) ---- + + // Pushes arrive on the connection message pump (not guaranteed main thread); enqueue here and + // apply in Update() where the interpreter + Unity APIs are safe to touch. + private readonly List m_PendingReloads = new List(); + private bool m_ReloadReceiverRegistered; + + // Push-signing session state. The nonce is fresh per receiver lifetime and announced to the + // editor via HandshakeMsg; every accepted push must be signed over it (see PushEnvelope). + private byte[] m_PushSessionNonce; + private PushVerifier m_PushVerifier; + + private void RegisterReloadReceiver() + { + try + { + PlayerConnection.instance.Register(PipelineCodeReloadConnect.ApplyReloadMsg, OnApplyReloadMessage); + PlayerConnection.instance.Register(PipelineCodeReloadConnect.ReloadPendingMsg, OnReloadPendingMessage); + PlayerConnection.instance.Register(PipelineCodeReloadConnect.ReloadFailedMsg, OnReloadFailedMessage); + PlayerConnection.instance.Register(PipelineCodeReloadConnect.RequestHandshakeMsg, OnRequestHandshakeMessage); + PlayerConnection.instance.RegisterConnection(OnPushPeerConnected); + m_ReloadReceiverRegistered = true; + + m_PushSessionNonce = PushEnvelope.CreateNonce(); +#if UNITY_EDITOR + // Editor play mode is not a network surface for pushes (they originate in this same + // process, and remote access goes through the token-authenticated HTTP server), so + // signing is not enforced here — see DrainPendingReloads. + CodeReloadRegistry.NoteForFirstReload("PlayerConnection receiver ready (editor play mode, push signing not enforced)"); +#else + if (!string.IsNullOrEmpty(m_PushPublicKey)) + { + m_PushVerifier = new PushVerifier(m_PushPublicKey, m_PushSessionNonce); + var fingerprint = PushEnvelope.Fingerprint(m_PushPublicKey); + if (PushEnvelope.VerifySelfTest(m_PushPublicKey, out var selfTestError)) + Debug.Log($"Pipeline: PlayerConnection code-reload receiver ready — signed pushes only (key {fingerprint}, verify self-test OK). Push IL from the editor via 'reload_file_player_interpreter'."); + else + Debug.LogError($"Pipeline: push-signature verify self-test FAILED on this platform ({selfTestError}) — every push will be rejected as CryptoUnavailable."); + } + else + { + // Strict policy: a receiver without a baked key accepts nothing. The only way to + // get here is a build whose RuntimePipelineBuildInfo carries no key (e.g. an older + // build, or one produced without the build processor running). + Debug.LogWarning("Pipeline: code-reload push receiver has NO baked signing key — all pushes will be rejected. " + + "Rebuild with the Pipeline build processor enabled (it generates the key and bakes the public half into RuntimePipelineBuildInfo)."); + } +#endif + SendPushHandshake(); // the editor may already be connected (e.g. autoconnect raced us) + } + catch (Exception ex) + { + Debug.LogWarning($"Pipeline: PlayerConnection register failed: {ex.Message}"); + } + } + + private void UnregisterReloadReceiver() + { + if (!m_ReloadReceiverRegistered) return; + try + { + PlayerConnection.instance.Unregister(PipelineCodeReloadConnect.ApplyReloadMsg, OnApplyReloadMessage); + PlayerConnection.instance.Unregister(PipelineCodeReloadConnect.ReloadPendingMsg, OnReloadPendingMessage); + PlayerConnection.instance.Unregister(PipelineCodeReloadConnect.ReloadFailedMsg, OnReloadFailedMessage); + PlayerConnection.instance.Unregister(PipelineCodeReloadConnect.RequestHandshakeMsg, OnRequestHandshakeMessage); + PlayerConnection.instance.UnregisterConnection(OnPushPeerConnected); + } + catch { } + m_ReloadReceiverRegistered = false; + } + + /// Announce this session (protocol version, expected key fingerprint, session nonce) + /// to the editor. Sent on receiver start, on every new connection, and on RequestHandshakeMsg. + private void SendPushHandshake() + { + try + { + var fingerprint = string.IsNullOrEmpty(m_PushPublicKey) ? "" : PushEnvelope.Fingerprint(m_PushPublicKey); + PlayerConnection.instance.Send(PipelineCodeReloadConnect.HandshakeMsg, + PipelineCodeReloadConnect.EncodeHandshake(PushEnvelope.ProtocolVersion, fingerprint, m_PushSessionNonce)); + } + catch { /* no connection yet — the connect callback will re-announce */ } + } + + // Both may fire on the connection thread; SendPushHandshake only touches immutable session state. + private void OnRequestHandshakeMessage(MessageEventArgs args) => SendPushHandshake(); + private void OnPushPeerConnected(int playerId) => SendPushHandshake(); + + private void OnApplyReloadMessage(MessageEventArgs args) + { + if (args?.data == null) return; + lock (m_PendingReloads) m_PendingReloads.Add(args.data); + } + + // Connection-thread handlers: CodeReloadActivity is thread-safe, no marshalling needed. + private void OnReloadPendingMessage(MessageEventArgs args) => + CodeReloadActivity.ReportCompileStarted(PipelineCodeReloadConnect.DecodeText(args?.data)); + + private void OnReloadFailedMessage(MessageEventArgs args) => + CodeReloadActivity.ReportFailed(PipelineCodeReloadConnect.DecodeText(args?.data)); + + private void DrainPendingReloads() + { + byte[][] batch; + lock (m_PendingReloads) + { + if (m_PendingReloads.Count == 0) return; + batch = m_PendingReloads.ToArray(); + m_PendingReloads.Clear(); + } + + // A player that received a code-reload push must keep ticking while unfocused, otherwise + // Update() (which drains + applies these pushes, and runs the reloaded code) pauses the + // moment the window loses focus. Force it on once, on first receipt — reusing StartServer/ + // StopServer's own save/restore bookkeeping (rather than writing Application.runInBackground + // directly) so OnDestroy's StopServer() still restores the user's original value even when + // the HTTP server itself was never started (PlayerConnection needs no open port). + if (!m_RunInBackgroundOverridden) + { + m_PreviousRunInBackground = Application.runInBackground; + Application.runInBackground = true; + m_RunInBackgroundOverridden = true; + Debug.Log("Pipeline: forced Application.runInBackground = true (code-reload push received)"); + } + + foreach (var data in batch) + { + bool ok = false; + string summary; + try + { + // ---- authentication gate (before anything touches the bytes) ---- + byte[] payload = null; + string rejectAck = null; // generic wire ack; the device log carries the detail +#if UNITY_EDITOR + // Editor play mode: strip a signed envelope without verification (no key is baked + // in play mode), accept legacy raw payloads as-is. Not a security gate — pushes to + // the editor originate from the editor itself. + if (PushEnvelope.LooksLikeEnvelope(data)) + { + if (!PushEnvelope.TryParse(data, out _, out _, out payload)) + rejectAck = "malformed code-reload push"; + } + else + { + payload = data; + } +#else + if (m_PushVerifier == null) + { + LogPushReject("no signing key baked in this build — rebuild with the Pipeline build processor enabled"); + rejectAck = "push rejected (authentication)"; + } + else + { + var status = m_PushVerifier.Verify(data, out payload); + if (status != PushVerifyStatus.Ok) + { + // Q10 diagnostics: a legacy (pre-signing) editor sends a raw payload, which + // is the one failure the sender can actually fix without touching the build. + if (status == PushVerifyStatus.Malformed && !PushEnvelope.LooksLikeEnvelope(data)) + { + LogPushReject("unsigned legacy push — the sending editor's com.unity.pipeline package predates push signing"); + rejectAck = "push rejected: unsigned legacy push — update the com.unity.pipeline package in the editor"; + } + else + { + LogPushReject($"{status} (session nonce/counter and signature details are in this device log only)"); + rejectAck = "push rejected (authentication)"; + } + } + } +#endif + if (rejectAck != null) + { + summary = rejectAck; + } + else if (!PipelineCodeReloadConnect.TryDecode(payload, out var typeName, out var methodNames, out var il)) + { + summary = "malformed code-reload push"; + } + else + { + var registered = Unity.Pipeline.Compilation.InterpreterCodeReloadExecutor.Register( + il, typeName, methodNames, out var skipped, out var warnings); + CodeReloadRegistry.InvokeReloadCallbacks(registered); + // Full warning text (unbound host members) goes to the device log; the ack + // summary the editor shows carries just the count so it stays one line. + foreach (var w in warnings) + Debug.LogWarning($"Pipeline: code-reload {typeName} — {w}"); + // Same for per-method skip reasons: the summary carries only the count, but a + // method that didn't apply (e.g. SetupUI referencing a member the running + // build stripped) is only diagnosable if the reason reaches the device log — + // "skipped 1" alone gives the user nothing to act on. + foreach (var s in skipped) + Debug.LogWarning($"Pipeline: code-reload {typeName} — skipped {s}"); + ok = registered.Count > 0; + summary = ok + ? $"applied {registered.Count} method(s) on {typeName}" + + (skipped.Count > 0 ? $"; skipped {skipped.Count}" : "") + + (warnings.Count > 0 ? $"; {warnings.Count} binding warning(s)" : "") + : $"no methods applied on {typeName}" + + (skipped.Count > 0 ? $": {string.Join("; ", skipped)}" : ""); + } + } + catch (Exception ex) + { + // The interpreter binds via reflection, so the real cause (e.g. + // ExecutionEngineException from a generic instantiation IL2CPP never + // AOT-compiled) arrives wrapped in TargetInvocationException, whose Message is + // just "Exception has been thrown by the target of an invocation." Unwrap for + // the ack the editor shows; keep the full chain + stack in the device log. + var root = ex; + while (root is System.Reflection.TargetInvocationException && root.InnerException != null) + root = root.InnerException; + Debug.LogException(ex); + summary = $"apply failed: {root.GetType().Name}: {root.Message}"; + } + + Debug.Log($"Pipeline: code-reload push — {summary}"); + if (ok) CodeReloadActivity.ReportApplied(summary); + else CodeReloadActivity.ReportFailed(summary); + try + { + PlayerConnection.instance.Send( + PipelineCodeReloadConnect.ResultMsg, PipelineCodeReloadConnect.EncodeResult(ok, summary)); + } + catch { } + } + } + + // Reject-log rate limiting: full detail for the first few failures, then one summary line per + // minute — an attacker probing the port must not be able to spam the device log into + // uselessness, but "signature failures are happening" stays visible (it IS the intrusion signal). + private const int RejectLogBurst = 10; + private const float RejectWindowSeconds = 60f; + private int m_RejectsInWindow; + private float m_RejectWindowStart = float.NegativeInfinity; + private int m_SuppressedRejects; + private float m_LastRejectSummaryTime = float.NegativeInfinity; + + private void LogPushReject(string detail) + { + float now = Time.realtimeSinceStartup; + if (now - m_RejectWindowStart > RejectWindowSeconds) + { + m_RejectWindowStart = now; + m_RejectsInWindow = 0; + } + + m_RejectsInWindow++; + if (m_RejectsInWindow <= RejectLogBurst) + { + Debug.LogWarning($"Pipeline: code-reload push rejected — {detail}"); + return; + } + + m_SuppressedRejects++; + if (now - m_LastRejectSummaryTime >= RejectWindowSeconds) + { + Debug.LogWarning($"Pipeline: {m_SuppressedRejects} further code-reload push(es) rejected in the last minute " + + $"(possible probing on this network); most recent: {detail}"); + m_LastRejectSummaryTime = now; + m_SuppressedRejects = 0; + } + } +#endif + + /// Manually start the Pipeline server. + public void StartServer() + { + if (m_Server != null && m_Server.IsRunning) + { + Debug.LogWarning("Pipeline: Server already started or initialization attempted."); + return; + } + + try + { + System.Console.WriteLine("Pipeline: Starting runtime server from RuntimePipelineDriver..."); + + if (m_Config == null || !m_Config.enableInBuilds) + { + Debug.LogWarning("Pipeline: Runtime server disabled in configuration (enableInBuilds = false)"); + return; + } + + var validation = m_Config.Validate(); + if (!validation.IsValid) + { + Debug.LogError($"Pipeline: Invalid runtime configuration: {validation.Message}"); + return; + } + + if (validation.Level == "warning") + { + Debug.LogWarning($"Pipeline: Runtime configuration warning: {validation.Message}"); + } + + m_Server = new RuntimePipelineServer(m_Config); + m_Server.Start(m_Config.port); + + if (m_Server.IsRunning) + { + // Keeps Update -> Dispatcher.ProcessWorkQueue/WatchdogTick running while unfocused. + // Guarded on m_RunInBackgroundOverridden (rather than unconditional) because + // DrainPendingReloads can already have overridden it — a code-reload push over + // PlayerConnection needs no HTTP server, so it can arrive and force this on before + // StartServer ever runs. Saving unconditionally here would clobber the real + // original value with the already-overridden "true", and StopServer would then + // restore to "true" instead of the user's setting. + if (!m_RunInBackgroundOverridden) + { + m_PreviousRunInBackground = Application.runInBackground; + Application.runInBackground = true; + m_RunInBackgroundOverridden = true; + } + + // The code-reload registry marshals main-thread overrides through a dispatcher + // when reloaded code is invoked from a background thread at runtime. Inject + // this server's dispatcher here (a player has exactly one driver), so editor and + // per-test servers never clobber the global registry's dispatcher. + CodeReloadRegistry.Dispatcher = m_Server.Dispatcher; + + // Publish the build-baked allowed roots so reload commands can validate that + // incoming files are inside the project before compiling and injecting them. + CodeReloadRegistry.AllowedReloadRoots = m_AllowedReloadRoots; + + System.Console.WriteLine($"Pipeline: Runtime server started successfully on port {m_Server.Port}"); + } + else + { + Debug.LogError("Pipeline: Failed to start runtime server"); + } + } + catch (Exception ex) + { + Debug.LogError($"Pipeline: Runtime initialization failed: {ex.Message}"); + Debug.LogError($"Pipeline: Stack trace: {ex.StackTrace}"); + } + } + + /// Manually stop the Pipeline server. + public void StopServer() + { + try + { + if (m_Server != null && m_Server.IsRunning) + { + System.Console.WriteLine("Pipeline: Stopping runtime server..."); + // Drop the registry's reference to this server's (about to be shut down) dispatcher. + if (CodeReloadRegistry.Dispatcher == m_Server.Dispatcher) + CodeReloadRegistry.Dispatcher = null; + m_Server.Stop(); // Stop() shuts down the server's own dispatcher. + } + } + catch (Exception ex) + { + Debug.LogError($"Pipeline: Runtime shutdown error: {ex.Message}"); + } + + // Independent of whether the listener was still alive above: if we overrode + // runInBackground, restore it regardless, so a listener that already died on its own + // (e.g. the watchdog never got to it) can't leave the setting stuck on. + if (m_RunInBackgroundOverridden) + { + Application.runInBackground = m_PreviousRunInBackground; + m_RunInBackgroundOverridden = false; + } + } + + /// Validate the current configuration. + /// The validation result. + public ValidationResult ValidateConfiguration() + { + return m_Config != null ? m_Config.Validate() : ValidationResult.Error("No RuntimePipelineConfig assigned"); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineDriver.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineDriver.cs.meta new file mode 100644 index 0000000..4336557 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineDriver.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 962b2a2812855af4b8ef33c0edccd103 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineServer.cs b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineServer.cs new file mode 100644 index 0000000..8404d90 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineServer.cs @@ -0,0 +1,98 @@ +using System; +using Unity.Pipeline.Config; +using Unity.Pipeline.Models; +using UnityEngine; + +namespace Unity.Pipeline +{ + /// The Player-side , owned by a . + public class RuntimePipelineServer : BasePipelineServer + { + private RuntimePipelineConfig m_Config; + private RuntimeInstanceDescriptor m_InstanceDescriptor; + + /// + /// Guards mutate-then-write of m_InstanceDescriptor: concurrent /api/status probes both + /// reach UpdateHeartBeat now, and RuntimeInstanceDescriptor.WriteToWorkingDirectory's own + /// lock only covers the write, not the field mutation feeding it. + /// + private readonly object m_HeartbeatLock = new object(); + + /// UTC time this server instance started listening. + public override DateTime StartedAt => m_InstanceDescriptor == null ? new DateTime() : m_InstanceDescriptor.StartedAt; + + /// Create a server bound to the given configuration. + /// The runtime pipeline configuration. + public RuntimePipelineServer(RuntimePipelineConfig config) + { + m_Config = config; + } + + /// Runtime servers use ports 7900-7949 (test runtime servers use 7950-7999). + /// The inclusive port range to try when binding the listener. + protected override (int basePort, int maxPort) GetPortRange() + { + return (7900, 7949); // Runtime production (test runtime servers use 7950-7999) + } + + /// Write the runtime instance descriptor to the working directory for CLI discovery. + protected override void CreateInstanceDescriptor() + { + // Create and write instance descriptor for CLI discovery + m_InstanceDescriptor = RuntimeInstanceDescriptor.CreateCurrent(Port, m_Config); + RuntimeInstanceDescriptor.WriteToWorkingDirectory(m_InstanceDescriptor); + } + + /// Remove the runtime instance descriptor on shutdown. + protected override void DeleteInstanceDescriptor() + { + // Clean up instance descriptor file + if (m_InstanceDescriptor != null) + { + RuntimeInstanceDescriptor.RemoveFromWorkingDirectory(); + } + m_InstanceDescriptor = null; + } + + /// Refresh the descriptor's heartbeat timestamp. + protected override void UpdateHeartBeat() + { + // Update heartbeat in instance descriptor + if (m_InstanceDescriptor == null) + return; + + lock (m_HeartbeatLock) + { + m_InstanceDescriptor.LastHeartbeat = DateTime.UtcNow; + try + { + RuntimeInstanceDescriptor.WriteToWorkingDirectory(m_InstanceDescriptor); + } + catch (Exception ex) + { + Debug.LogWarning($"Failed to update instance descriptor: {ex.Message}"); + } + } + } + + /// Build the Player-specific status/heartbeat payload for /api/status. + /// The status payload. + protected override object GetServerStatus() + { + UpdateHeartBeat(); + return new + { + status = m_InstanceDescriptor == null ? "error" : "ready", + lastHeartbeat = m_InstanceDescriptor?.LastHeartbeat, + capabilities = Capabilities + }; + } + + /// The bearer token clients must present to authenticate requests. + /// The current token. + protected override string GetToken() + { + return m_InstanceDescriptor.EvalToken; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineServer.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineServer.cs.meta new file mode 100644 index 0000000..5afc6dc --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/PlayerSupport/RuntimePipelineServer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4599450d651dea74cb4b90289360aa3e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Plugins.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Plugins.meta new file mode 100644 index 0000000..40fe832 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Plugins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a25774b4dfb214b4f8c39d802c589d7d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Plugins/CodeAnalysis.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Plugins/CodeAnalysis.meta new file mode 100644 index 0000000..95f2154 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Plugins/CodeAnalysis.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 014d6925adce7c84bb3742e7557d8581 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Plugins/CodeAnalysis/CHECKSUMS b/AIClient/Packages/com.unity.pipeline/Runtime/Plugins/CodeAnalysis/CHECKSUMS new file mode 100644 index 0000000..80a3ad2 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Plugins/CodeAnalysis/CHECKSUMS @@ -0,0 +1,17 @@ +# SHA-256 integrity manifest for the bundled Roslyn (Microsoft.CodeAnalysis) DLLs. +# Verified at build time by PipelineRuntimeBuildProcessor.VerifyBundledChecksums(); +# a mismatch (tampered/swapped DLL) fails the build. +# +# These DLLs are the NuGet originals renamed with a "UnityPipeline." prefix (assembly name, module name +# and namespaces) by RenameAsm, so they cannot collide with the copies the Unity editor loads. +# The originals are the NuGet packages listed in bundled-roslyn-original/ (hashes + rename script). +# +# Format per line: # +# Regenerate hashes with: shasum -a 256 *.dll (run in this folder) +# Version fields marked TODO should be set to the exact NuGet package version the DLL came from. + +83836addf8d51df5d6d8cff3c43c1663655bdd85eb539b44a56dcd96ff2297a0 UnityPipeline.Microsoft.CodeAnalysis.dll # Microsoft.CodeAnalysis.Common TODO +6ca7115fb0256a4d415a73fe7e264d23c89d6d4019ac463fe519bc9097fbdf9b UnityPipeline.Microsoft.CodeAnalysis.CSharp.dll # Microsoft.CodeAnalysis.CSharp TODO +fb05543596e537d7a4383c7330b181cf31151e985578c57a8b5eef00c6c8a460 UnityPipeline.System.Collections.Immutable.dll # System.Collections.Immutable TODO +3de473fbc3e3e01eef020cb82cb6a3eb288959e24e65175182a818c9d09dbe01 UnityPipeline.System.Reflection.Metadata.dll # System.Reflection.Metadata TODO +6f2becafbd15867d52bfad08f77a23d26c818e55473d6347aef41130572f14f7 UnityPipeline.System.Runtime.CompilerServices.Unsafe.dll # System.Runtime.CompilerServices.Unsafe TODO diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Plugins/CodeAnalysis/CHECKSUMS.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Plugins/CodeAnalysis/CHECKSUMS.meta new file mode 100644 index 0000000..9ac3330 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Plugins/CodeAnalysis/CHECKSUMS.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b61d5dbe422f84644aa94e10778b9e94 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Plugins/CodeAnalysis/UnityPipeline.Microsoft.CodeAnalysis.CSharp.dll b/AIClient/Packages/com.unity.pipeline/Runtime/Plugins/CodeAnalysis/UnityPipeline.Microsoft.CodeAnalysis.CSharp.dll new file mode 100644 index 0000000000000000000000000000000000000000..2f8d10ff1e772ce97a27a9297d4c2e7d290a6dd6 GIT binary patch literal 5758464 zcmeFa2b^S8nfG6PZ`Hk3)z#Hg-96P4V5$i-UMe)91!e|;0ZAevh$6@?Ac|Qo(lZ9e z9xi#tHb~Md(J&ow`;l^#_^T?e_rm)Qzt*? zInQ~{bDk6K?YrFTS%t7rC=`L4ZYmVsjjLyy{jU6T4axP^d+LS1t9<&PcaNO)>4Wb6 zfCtXcTzOS`|Euo((3$((`-&^l?K78MK6BNMD`p;e#mp&pJ#Xfr>3uJs9UH42nxQ`D z)I#B`k)Uwdn_lrCU)y&I!9k-VqlLmZ?pY`VF81Qz;-8WK0{yHqKWU;{k9P|*q-SNq z!nP+WtNst%ET|}+Rp7m|^DgsyL7}!x%8Jo5g+e)(p-lLUTzGc-<&WG>_`YAu+Lddo z&qk3;XRo^aA?bYz84X$6zD1ebv#n4#ITzd~?>6z3N3;cnQsK~7&lI*V990;x*h1k2 z2c1`VZvr3$ia-g7fEXwP z6`%@?0ySU^r~@ObMkqHzxe>~ZP!9Y+43vQiPz6ST8ZZXbfx~Io5x|kaaljpbGypMB1}Z=m7zax0DF?(r8K?kN zpazTqb)dAK@<0rffeKIsYQPv!2TE(e1H?cXr~p-<28;o9U>qo|0T&PhWuO97ff_Id z)PZqe6?q%VzZ#rC1*idIKpiNp1_w|9YQPv!2fjmlKZqE70QfHckK=v}_#Xa;MTNqZ z!1wXb<6Z^OWw$ys{uj_Nz8^Gt}?wdb@pvV0 zW&d>k-`eu`m#ANL4D(-c9%MHteW~%MF*eM9#d*;9Q~FBdFK?GnjXjFXgCZ3k?tkGQ zeiWAnr7OJL_|w?VgWBrDUhb9~{~FtQP+NUiemyrg{>9hfM{yoJf0p9E_&WS3&V%RA zO8gg3_XVVXz5WzW_XVVXeOd1c-@d}2tkWsNdrQHW^{(cUTMGFy@@p=+r7$Qv;KBaP zq5D(T(;_!Nf66bp^>H^hhx&Zp-IubS24B{@c^o%4hI|?C?n~L*>UZN2!SF{0wSOSRDl>M1EW9<7z66S$RvA5KnN6p5)c6~PzEYM6&M9-z!*>m z@(;U{CdJx2^=nvdJ8GwFr8NY}g;7fCUkGR()fftZA|U-D`PcXwmjC7U#`61O%k6{Z z_rQX6>sNeg!N`iw*vL?Z>f-EUBO}4|bQtpAJtNh%YpYfMyNC4YfRt$-%QRw1Yk4e_ z(v=~Xt_+LQ$&gPM{zc`%pmfm@j<_WK3X$O_S~S>0dPbT#mM;2z29+P8Ux-DdwbA3x z^0@L=x$(i(ZJSZ? z{M0WR?Ae=sGE%?Kuw*)0J!Q`Av(wSAJbqPS{kKecMF;BN z71GxRrD=2&5CdhP0#t$0H2MdKfih45szB*L@&hqY1}Z=m7zauRQU-{DGEf1kz&KFa zKsg`=%0LCE0^>kw1Lc4iC<7Is3XB8Vi;e*8N0$NZNml{wMMr@4qsxHyq^rOPb3p)v zKoMAOt{EjQKi`Znp9DY%6oKXDpHb5CbC5K@{uLM{_9NH)E~W3!#Vf_f%QNsZA!KDW zH)MWdhVrQVGEZ?&z`x?2(w>liC43>_(w@>f_z1*68K?kNpazTqb)d8ko&qsY1}Z=m zr~zX@9VktJ2Z(_(Pywny4HyIJKxqOzKn#?D3Qz@Vz!*>mPAr^IIKFTP{vD6+#KI|s zJ92P!68}!dcS=9qhr5O23Ny6X&+C3Z_w##xPG4>gUvB+|Z)k#D_o;I0Lv7a3*kP;4I)Sz}diE0m|4v=M@q|V{#3&d2`LNBeVsj%QzV!*G3G z4|sPa-7s9%hgYh9cz@iN@vg7eyZQR%*W=grzRa-u|9bu6@k$_m`FD$av% z_tN?HZkP5kJmmNGhH1YoeCu;yf9BBrDVuM(*InM-7aiuycz0jQdK!FL@8)sHuV=Y2 zU&`KAzvF;-wh}0p?+4E_@2*tNm+`JIGwk}l^RDuH|IN*zKA(5@rL3pJm-X(x z;P7R#~SZ;p)^y%Im&X*7GOIcse&zIg65A%NITWdxhagYIopdbqTdI`eaHVuG^y|5Kk2bKf$Gk4QRK>)tP_31?x%6ew{`sRz zQ>;IL7$^f3pbFH0F`y2Vrq}}oVxSCEfGSV}#(+9-41IYluo>6_Yz6YqN^38_=G0n1 zPyTM6!d~ZlH?RBU*W>k;KiAfIt{#p>Z?%W5$O2pQ1-Z8dsNuI}`}6g$)c?b4|9$EI zVY_9y{$Hv7zl8k#zh1w1yb?%Od_N5LzsC4V;L5u3{-^Z+tu23liTYK?F#i?jL3Ak1n_V0`ByIlK)b6-IBsQn|H`vT&>fBgKjulKU^_2=)4 z-BSN>{kQa9w(|MM`}gH;*r4pKZ-0mu&wp<_c~>&*{Wmv<`h4Eqm$J8{e&N%zoDJve z^=`iYn=5-;{l?lA=TFZ=?+)t_#jgaaVY#xmg#Wj;{QV{B-=8^jf699P@6Q~%KV^OW ze!lds-8KQ`XnNFY~7#f8vRr{VD6~zoqkLKA)?deE|Au zU%{94_3zId`lpsHt;N0tVxSCEfGSV}#(+9dTFc%B5CdhP0#tz-Fb33t+n)bD99U@` z{eN>Etyv15Gwx7I#_uYX_m5Ip|}W&iYj1drp^+DGv9-&*?!zW!U= z_4Ac?^K;n$&2^M-x3AZ``TFJ8v)ml&%XoKR%HCGLKk_l zU;_g&PzEYM6{rDYKpiL@z+M9o17)BBRDl{W2GoJup8q`@@asD7in6?aB}%=G;aykO zt@l?dmrwI`dDr1^H01Lw<@fb^*Ok4ke(~d$KEvx=mGf~oheLBq9$Z-$cXMTZy6<=I zDn9S``Id5hzkAn}{r^}0`#lBksttMnQtkF}vUT#{%DOn8=jPny_7(gd!%F34>*PUs zeR!pE`82<;;9aHV{rSAZesAM=*Ohg)(s178!rE)dgYxn`sqZ{GiZtE|WC>+ee=iPlN>(Tmt_pajeexGkC z*XQ%@zLfR&d|B`A3l3k#yZchs*Pow1<=5lme4gc8pU=DdQr6@2^QCtcpZEKGOSwLu zclV{N$LHrx?;3Y;3yf`IgVdhwB8y^N^*YDPk z&nLgjm+1RW?TdrtAlzX3S_)G~c-;aY$t$+EX7Qm5!Z@~sjDa(92Mkm+47Auj|3Cr% z=*?mNDR*S37V}TVqn-NA^Y7T1$8TB0KNVkse^zd3{vE!Ee=2`V_$P$7jDH&(pO7r$ zV~%gMzSy1}FC>S6EZj3<{zEf=LH!&QpibW)Yy`d0iD1uahQj)CXEaDQk!}8V{8U3e z{gWj4;yrvUC^-z@C58z}F|7Bah7SI#E}^BfL9vaOX*{S+9##Blg7@N?jIpyz+#1hRVg z0ukO{B+su9L4}pqLx=d^FrZ$J`_nAHPy5$gKE*u|cn+|cyr%+kZ=~$M0D9}`62gxp z{f)rg@IMOh^*;pv_SIPZl2KEV0Fm4Jr2;@^h*YT$>!(}3p#Po>SDgEr5vkKjkl zEdMFsdo=#F)Nwd@H{s@K{wV2h2i~34n@`(U|I5I!D#IgMRGyEX6`oK1@5y-b@yzw< zlE@VB;kV)6291J$#=n95U&H+sFb1w4;%W-G9q=a7c9QQYKm-4=)cH)}uLC?Uwvt_R zoPm28a1TIfuf{!ze76VM8LdwO$JyYzJ8*B{K;oZ)`(fb4!0Uj&2ZZmxaX$-u3-}4} zVDkPAxfizau$OAAUP!qprwN3j#+@l1j(sc zfW`#L=~;lr1PT3T715X=xl2U`&wQCkw!sAh~ZAfH6UGc@{WRf%|6x zxD+H0$O3RFNFJC4?xMhhvcTC2JU9!$zaV)?7Jz?2^3W^*|AOR-ECBz4B+UZwFG#M; z0`Mj$h%x3}k7bM%W0Q?J*9a-Q)1sSpYT% z$rG}`{SeXlv`XNZ3k!7GCg5+6QfPM%P#K7d1eh89d7nP(pg5)__I=vAj&&>k# zMv(k%7N9qRD91s<)y zOS8a&0x!z~^iz<$JPXiIL2{QYKtBb^E3yFn6eJt70R0pshh_o#DM((K1?ZKtBb^ixqI(?emyE3zF-yT=ZFxyd(?IXF>A1EI^+HviPhT`Ye#S z7q!D3Q}{QUonK0yhvifaQ!I>VH15@$Db+e*E|?z0F55(bV5jV^aOaPTh2m5c&(mww z%;egAfUs^>*B9KHh;gMeqQ>}$RCBc(?b@pB1dqd&RIdOkQ=J!ozb3rT{& zbq<)Y38Xq!={ACjHEgmNH;O3(rApeJaeCj3)3b10J;lP`QBTF{k=a{~TBpy}qShG~ zP9JmZX8K%{`UCha?qD!w{ajDhM0D`PNK=Aa-Pj8@6_Yo^#Uy~w?Qpw>|Hc%XFdCZ( zHCI(NM^$V6D418BEOs_b6g5RvCrjm^QEHS-DhyMKvaOPOcbwkW%PEqugqTboQ7SM% zv}SKOkwW+|k)l!8TQ%0M61ONW&z~<0nr+l+EI*84v%RJbM+?s2FqQCyQbFUj!%16J^b()$TYIzkrx1 zc{?2J9!QWyQj~m-1(Bnkx*ElK2+p7RchWJ^sO(5n{GP?6IbpFLm+QlhDHMoE4+$BMR*d;?|f)*l0l zhL5Vs2GK>vIVb0+R_>CBmcIN|ocyit+|9{edVeHoG>Fq5i!q;vF`0~+Jk=0viCFW< z)f1Rwe}&fySnjb-w2Pr#9b-7Sf>upV)o9;C`UZ^w4L3n#@*NGhFf9aHV1}bk4&aMg zKtHNG)sN!VWGU_*Uf#jf5KO}G?jemR{STw!j8Y0h7)hDTYSs9PJQ zd8Td&rsU{a=s;gV$2fH-KX7zR;@>YK4o4`4iJ+hA;LU0>`H7?0i%Uk@rH(Xc3k%mk zTSK(%Kwk#csMid45Dw7ut#HR7_-f_e37xwJQMwkyQMyh|5aM>6J{neOj%apDDc|pn zdXqtHgFQ~4KrnfOvQ4#va=M99<@EWAw6abthWZQrrPZ*;uj&d1byauW8=4ujR{OVL z;BfC*uNC8rAvUxwQ!^z8PXq6y@&9(99gGWgyjK8WI!oGQG!e;8t#%O<8!xrFrN&En zs^Z5>GkK>5XAz>+$Z*ie$x@VvREdKhu9bPCYO%fw)1xVw{G7aCxxHbr7_n+;a&!9X zzSf&+r}Q7ww)RTiK}m3J6J9zthvj&p214)H7L_ylq>(Pq@Re*o$#igfC*k>FpY22H z*cFyG#$G|_rN3vPWwm&2@-Qf%QI_$%c04to{YD7fPG}diWi>80ia7!moHq)+PM5CVDdwt^wx5W#GKt>zYCh`~lja9`{=}x| zr>&pU$NIA1dA#=<9$5Z3BKFcS*+8*6@}uR!9)G#OSSze?_^(}rlS-bZ2&r7~KVAM1 z+kk<&TmB;cn(J{Cs)pAbs-Jc+Ql*1x;g07y9dtnF%plrz z1(~lxF0YK7fjKQJ35zvO-&8I{arzZaAip&4SMhosBm!d7=UM*H*o;mn7no0c8?loj zS)Lj&Bl2g>J3rUFd+uZNQZ-Nd6-%zL&f0cZzipX*9q-JbRoVJ;y-#!Y(w%#$NybND zX9~;WTnEleh12FmShN5amYF1>O}voZ;QCuOx9klJZpKS`?;Hm%+eZ#u>E)?ZI0F3A zBOt!QQ#Py@B$l7rs2gB7u4*3c9^Vh=X@wu?E ze>6+8$szNLxUp!ba`w&(T%==F<`=&vGc4&YFG;-S8*yK>B ze-M^xqq=_f_(t`B+0jN7bM3;-HJagaY=1E_)SQgXgkVxnSCth%_*qu;-niN&!vt7HHOm{3nOacCAiL#(E?c3`QBK~ zo-Aedq;!kelr0BZ1c#ObrWPB~U_qcd+=3u8{4wKlDl~F-|A)c!7IKE^Ta{l*5T&7r zj31I?M}$*?8Q<=VyMZ=MRm1L7n8-+P)#tK#x;nLL#PMz1cDAa$xS0GJ-l?^ksrbsE z6S{h_UaCj)j#<(rXMne5{gE!CSKTOc(}TCZqFoP%-Mb#aj~C|3e5OMK`?~-$#{ZAd zFwRh&8aF#*EA<^@X`JP_nG=ruLVlZ4wE-}g`Ay68$ICp66xYX*?X*)swkIc{iwbuq z!t^=B$tL_8TnyrHs#6QfgBp;pXRDMZ?!I`rnbt20WLiDS*HDp$~BX-`?{fA zaUw8(ktm=O|1Osl&0nopSI1jn6AO?MkN!^rWBy;uA(jFyn#6d zk;2TLkw$?R`@ZBYsKwH!F@N!gQ$5$_HT^cHYw-?kT!>(6eKwS`_L>>J%j1g*Y*Dzi zMmpnh47WMA?8q-V*rkOityfq~yER9;aXB1Ae7hzq8x=553%7IaX{$Z5yx>tsep5mi zfjK2)t#ZujB`#aG(P{!8&#iKi#!j)k*hDGhx2PWL+g>ar)D1{)VQsp)`;8aHqnV7v z^N&+0zqf`pI#`>DJ41po#cJ;Ht{US{mwIkyJ(p*!74>yV7Mp#dmX^XNMa8tAGQeJE+ z+`OUv&PHZjiO=Wwe$_w_LhEGscQ^d5nTs`bei7t)Bio31qVLDZ*6#4QkN@u>IgdVD z(=9o94yMc}8N$gUY6WJ6LeJs5$df2~|H=oT_g?sSzCJD#laEjvH2<|4kY3C$gL#np zHB!}vLCiN5gL<`?*9n8h{AAX8DO~mPBzndVI@`!2y z(bnDpw$=kg>4&JOS8Sc!30kM15H0S5#AV)3;H4oJ{Ym^aTKGVf)3Bor50c+V%g!eH za{?HQwAi*`Gm}7sHRAcF^kp$Bpk|~S8uL%4LDeW+_*Yvl=-2f{Y_lc11v?dI?e2_B z)v}=K=xxXXob*T0p6Dq!^G~IYq{NayLmN}s3M+%t9=4wm_qUm(H%kTP$xN@O^S+TL z7dJDup5AZIA{>v}7aY6$II0D#J+0~JqsIxwhv7ARf4oOWKRr=?@!ii3P9W$Jvx<== zE2-{Nk61wchXiHaqD^iuBQ{#%c_wGcNU?AO^&d(7IzrT)rYKG#I2otAsdfij1KPd3 zajMpNczI)QY!ho>C74Xq2wdv}WAP4V|3D^BZ*9Eet@3kR(OVyP=bS+>8FdZ_8pU!Y zd9SF8I|nhn6MCNuO)|fuc(T*2`Da1S)s48u-@;2`2wN!%<{TXGR@LgfY{i7>uHSmJA?i6p!LY2 z2>>)6;Qf2iC?4nMSsLkVmi#_M`X=ATn;CY`S81Kgh>mPc^bTJZI{r?6x7TztYMn{S z(Ge9kgG=);<^R#+8m40zW9NmAo<(i>@NziBiky-7q9w|H;ue-=_8r(ARcN0cCU~f_ zfi1A855MT^qwQbv{+sPXrg6u+VgWnb*?7io)YQ_Z$aRk1sBkLz(YffkZ>u_;+azVi zHT8c0X*78n)NhRl)AuVy$Hs$Y=1Uw2jMF^M?+K?iI+Dttfb*p}oZI?z{zy2rPrt7u zzRb1R%@4;o`TC?<@&#DD9klV~eR@i=!(@}gxBpbRf1?~LKriFQr$ND2 zxPqGB2IYR|%dNR3|>t!$&wyItlxlVk$0fw4X5^;cM zWL3!rE=nFHW`j?s^;{=)BFrST-up#apKS5JPj}vywNAlq6>kQ+x3XO4uXp^JC|o~M z;4jun<_`vWHQMrAB9hmToN3YYwfMKc2WtUS@uQf`y=tX(NcyZ%_6SL_0q+lu78Lo&VJT?S;)wQc1T` zR}N!(HE0^ei6A{6{FCuSoV<-`HQM=c3c6{xn&hhfB+m!nBETjCY{sC zyXo(#q>74kge}52f#ob}ohT=-Cof01{Tc^8#t?~ICkm!UW9b>`;s@Z~!TOBN`KZfZ zQ%~hdzX=V48zgNGc9lFvvOG4ViQI_aF3Z3YM%|$Voo=v;22;D3J-h;H&cA^Gwm{A9 z0vvDSC}BrLszGgaQ;8Lk+_rrb>zU-yWJ6|EovGk`k=ZakjAB!J!pTY$v%{7xzMR@J z0cM@3=@EX!g}dTnt4OzCWjmt$4XPs*@kO2ck$Tjk)Paq!fif1wQw~3OY2IYmWiMU> z?h_sEEtK9qBk9HZ76}s-RX(ap4GRL`Y9!EXFGEZ=bcb!W4PIzzY!&1Bbn8_ ziXi##?DIS-+#kB{NL%LL4R^JN@Nc$; zV(CAT-kBh7JL4}%o(&NeM^T1vwfEjAMd1C|V%!(*M1Az+lYLL(e~R}@ojuhDhE$lJ zF;QXkx@6F;o1N~T*4g`z&}M9l=jlKe< zgm|8QckOX^vhOSzOFt!a+8v_>|Ljo@jRA)ni%Gb#rXAizeazX$ryP1@xLjact8kX# zzg{@Mfh=$d=}3072rfD;pyxO(=r&!__Q%s1?!KRuaWz{rP+F?q{511*AR4RmAnLXF z{3fyEiR?LNuVAiZ2mEHQ{Ila{)!rmy?~wMtF(YWIQ%Ziq%(k&t!^{vbZGX(F!@hVk z*>r#Q|A3(z@A@=OXH$9CjZ88dd()eC{RGdR=))A7{|spxuTe^XWo}ow-a_fgBDb`& z;-6FTUZc3{-xrtXrM+nW^HyFdK{Ssts3vu=jG+ME1R7hk@b?GPw<;he<#?21k&_{> zm&A?vFM`YTX0`A)aQ$p+|GPnh&Fv|34U2dEbTMK7G-#MoT*F|?Vm^iGJHeLjL7I|( zfwE|q8alOa1pX-3h+ACpOKRF4MEGOk3KMa(y~`-S#pS>3SW^g*-HYLko-q9&$T%vg za#W%<#D^B)CgQ`3B5rYIU-A9m?j16hNUwa=Ba<%qh5}zgks|e9lV8?&nEs2rZtuZn z7NpA2M`sTmxaKxfTcjMIFEgpyU6cJl}gcxv~4?qovQPalI@dqv*<>CcIcSrjjI7%fs! zeR}>y1wY{BA36k&c)pI%7_>KyPoKvzFW{+O%ILIRk z(;0aWfzQn$=@brhi>bD2t#z`^%F=6gZVj5-c{KPr8g#s4xsY!1NLkLytDT_5vX!Io zyFyNbOxek-$!Vy?g^ZT(^=T;;nA`QXv6o56_!v|dqvW-2@O+%mKrBYHqo}Ak|9yu< z?fDHj&IgC?TK*E{tGk!<3~q7ZKg})eU|!J)9hayk;`AS}s{9$xN6jB>DlPn)tkF*W zmiCNrm?~5|UTpH*o6LgO5wx?r6FXN{b{$hL6q_mMZrF_#+pBNt{vf8DH|z{uC0$1r zn)W`h$}7cGbPWC02J=!Haj3bq8}LxAy#+kHiuO8#-U|5(#CfE1Z;zihZ}`^3bVm<(H!oDhW~z26ng(h zmzRpkn-B`&d7z@T0;u^JsTjGfy4Qr=LvybU<#+R(ddar*rrN&>buTcxKgo9{ic`tK zjFavGMSCTN%az8HE>@sry7wHJ*w#abMeQ5H?#5#G;Lt8u^|<$A7q3`B>*7_nT1;Pv ztFLM_+gF9H+U)A0Mom;4+_PoHsw*ni-n-D=d#Sy~D)!ZM3sP^D(CG9;0$J2s)%@)k zYeD*7jJRxl&&HkWqcR)N;_Cc;t*3;$Xf_yf!5w{8q}tcU7=3z&;0UX#H`-|g(RB7gf9zl1@0Tsx9P`&EC+eY@7mA>*;dY0}E{WS_ zJFlumcAGv*A4|R{eVqMXqhI5=8;I&$rs2rl8|sb}WTPSD!d;DKWXvADCYoU(Svc;g z{J5yuvp4^z1<-1R<6dvxH}JcSsjv`kKSWL8?t)%mic?<5!Mfx~dDaZde`|WW#cH zUFN&*>?-HmFw1^k`XA(v!ekX%GySFf#RS3VMCq>xxIX4}A-yxxU*DguDw-VbZPsiU zjE|I)UlZjtR;GBN&?()?s9sEXYo$|8UbRYl7~BwLh4TRfLnkS{xkfygo&1{v71O$n zcrY(b+q^VcoMzW#3x_XPu%o$mxrXa-(q%E=m<@0l#7%OMn~BqDbNAY}ddJ=ZF0n0B zOcBrOWVP8SX6m+4X;dr8e-X= zxFvP=${+@my(D3B;k=7p9)yFFOmnZsg-*uN4O$L-1oohI-zdM#q0uR{*wb}tyje!> zAyI2=wxk>FYvXP+PXF6zpQt8uNOgLy7}wbBwi;QKh!t9d+tnn_0Ih3 zG0nk!wy0<~#TsQlZ@?fn5i9e*1wZSLF*^^qkJ0=0o?aH5o?J+`XmoHiqjw8tq2paX zRqLpC`@mp-Ms$+R$b?)&U}QqG1&qvy_e0#2Gg*d8qqDEsMP}I%NngmQa(z*@xr&KK zUrJh&nFeOugga%m6VMdGp8@OyIvQizXQFuQ@ETuf`pAN=}o;sJ6pzO^zq>V zX2fOkk#6}W7v(#5FMLfdv8@B&6#2Wjt8q8s5w0dMS0hlsp9?<%kn-A?=9uxHRRs@3R_eI-D(Sl}41rb}f{%MmKkB%bC<|t;ia`5uS)CAn-1A&4lpOaA<$8e&9{?h? zcpa{9*CSkb_R`M7@xlGs%W%m#dv52x_%>vDC988TJbPs4Ongilvxnjy7!>%n9bw$V zJ4Z~zBXR10_J($=(r#7Tt92`REz+SKCLq zKHqSk)~XBJ2M05So0tmZx#^}oH}SbLV)&lYCA`D!{6*(KiVU>xl2(Gfq+$gU7>j}W z#bhb$UKAvsfl<7fV9A%ZgXFUcpEM9N^^uq&aXT27@a($I3_iMMb`>tYX#z%n%ncB= zMc@BGp9mEl5SM%!od+x5L)hg`9*s;v(ECP#3aQ!Ft$s0B|6%;nH@v`&&9_+f1IT|I~6u+~ST+ zzPE^Xr&6~YUuuB#0i)5zuSRK`Fs!r=(NWM<-ynKB};VlDXdHE8NLORirnvr}7 zy%g6Ha^>nGQ^p7Jhwpk!UAX3G>tHW#9FC%t)Fx>L$1|6A{e`C7=r7P~c2Q21h|hr=zeP%};3 z)rTm}Bevp-{i|^`yrtK~{!2DLi&6yC1NXqy2tNl`Q^TD%&$~qGv68BH3yFkhZ@>9` zmngL;Aw*5iZp4*RoY}mE#MY_p)`{)bo!YIF+O1RCtvj|`XS7?}+O3n@tPH>-6lHmp3yXeLsPXft z&6*zwFjQ=6(BP65)S$WqSA*(aormDlpgPaxoISg9FMPD!@@ld;(S>KXcDCUYH;%#; zH+r4f);hF&t8KHu+IDNQ-8#&a{~_(xxXlYp3agnmmRHV@>RGS2FL2@6^E&s#r*1tBSKWFNuDbOOowM+%PgO>J+H>LAq$85Wm4k4_fCF&F zfa%Vf)-mnYk?q!j?bZS9*1_%8-P*15+O4}oER2tK*ZRa>jcN1>J{{Ye4DsDNEL0D# z=#!bRB+l6`MbkO=FJR;JMz4B8t#IW$H>|2xhlHNf57`wm*6-|}C6}-F>zUBLmUzp{ zCihj*b?(hs=GmV^tPfu7g5l23Q2X}Z2J8y_TFKQw|07MytbwBTbAqISUDsO|1j#s_ zU7sU=`g#3qB&c1A>Gmca@BXK<(@)ytK{#~JsxdVhq?eOTO&Li$_<|^I7PWqe+E=qy z_yUN!m0~Z_>%bir(M6U>$$u;P?X5lY_c)zx!eHU=nwYHN!aL*?7v3hPwD3+j_2R<2 zaog1vnxDfYlp<^!LIc*+IAq4-~)CKN3}qb}*ROi-_iexa|&tG*6G{ebT~% z2Kjhvd&g-b%GtGyt}rhcxHgVRt_lwx()cXhO9gWxUzTvvr zIBr#EqfRu1$;*yVI!68-EYP*N!bZc0icg7t^Z9n*{*T&&D>~$=pj@jEcQOlOg;@N7 zS$K~NC-+rY?Od8}LuY)bLia>^&Omc@?CzbM1HQwIr(PD zF3f+As9Krj!{>=x_&%ZXPW?_L$1}vXZX=J2NdKB@w$Ml)zJ#zoTlE8SchfA>#YE~F z(2ZCy+(G;#NV625{Zeu?(;reu`=3d`e%Y39KsU#uZzpMLI(--7Y9A)kU6L*DCk;2f zw88$?k0`eJjl?Wp-PB}U-uZ9j+t^#Psa)O@{TToJPZTj(Sx`cw(oAo}P5+%AZZsUr zvi+y>aw%fRI2`P5Up0bZ?iVPu^;x!V{~0x@pGKH4gTls6Lxi=JUF!(n1ON z+Z?^*GT$;+DXf0j&pAUFEo1a5qx*crSpiQplrtFqy6N8;*n{(AD-Oe6; zkIl;k-0mZl@HaNT(@WV$9;>Xq@YGQXQ~=eQaYmEX~nHkLTHS}+~hR6WpDvlv_J-t?R$m25_g_P(4Abu3iQ%Km4y4b=upw4 zS+pbO;vn3iZr$~BiC15f>x<47Uo^$uZU*|^G}FK@Bnzhny;A6E$v3q+HflYDB2LO4!KDH01>s`TbOWhOqt#UgX zXHkJqj7drh>#o9FyR!YHt6q*tkQ26G*O%FsF}^2UQ?W5BJ^UcbY^VNk=QWU>?d~LZ zEiqu(-Qh%v5BT`#G@#Pvo}hc2<39VGmYhy8x|T%HMYFw^TjVY=4JqG#P>>!=7wqIa z(IB?>XL+l;x|Uvr7R@tN+#S%QdE^7INxTxR7>w#?=0#0iOna-M^k?jQMfL%vu4d8p zI#$&;Jw~%S+u)Qri!yqOTB7k{x@wx6DW)gj2~rI1h?8M+t>9cKES@{v4$tXMhUZxB zHFI@eOlca!lD7-N`3U2i+EL{guxKqx*w|q&t2-SfuC96*&F_NYk5x|x@Xcu*SZYB(8wo-oD|LuTR&VOe$o2?}pYK(w~ zQGva@teAJ$g&iBQs`p@ct5xRjhK(x$;%va|L_iMFtq zo=jphIa#@Hr|@ZngB?=z$WNv~TNAV48m_@qJrd~B8IkC_8a&kT38b>xnSvFc#K&16 z=R)8#HBd-CMO^Ru+1_4Q_&nuyQm)DABV{8RUEBP2BI)Xwz*uGbNg+M@iPN-^9CvqC z(lXJ#d0w(9t+}LI$8dNYa@{Sh(e8X{`Vu=weFO7U>)^SPw(Jirt#kRFVENV&)hKPa zq+6rt6BQM1u$L^#jZ(xX%DR(?L~;@oTNjG#CcE#YORH?ue~Hn{3mC=pn|O420~}(n zH7-ahkhb+?Mpf26w+?x<_~O2~TJ1>9p1>S$W=(*OeT$}4sYpbJ_};(v%XVPHf-B2G z6FhB_XC5Edv?!T;k^ad_@>R5I@4J-Lc+>R1%as#9tDOTWCuR;&w_=gzImE7F@vFad5tKqAagI!~|=^aoF-O+NG)CpzW9>?4J zN;rjvJBH6~gCIMzQccL`&D6FhvdWme|ucI$Esa>VQbFdko2tM5nc^@-l zm`s3(#X^`&;@SRVxV7+p5{e9-!{cCAiq>$AJSf_!gqgQ9IfluU>Nm^Ruy58Te35}P z6~y6VR+9)>kD%pS4^{%h$r75mgo+YctFn~oTncMmQf3?h57~==Ptmfy33!hc+U5$a z5p~uzp6a(8v{WHjL5r^8_Y%JE3*~DEWb__foMCeGDeH16=aPbuWo6dqQjR61sFW_e zJD^VmZx$HuE+B0$(mPD2eh;k+DNi!FyQkz5CLRb97XD^)ZS0M1(qG`HOUn+5XP{dLek9*6)|mn10dPPMS+F3m_`CO(4IA6EnZh*Xe4l z^-MMXDvn~ivjlg%o}inNr=g&`jyQKjkh5WZge>`5XRI8~A%tZUGQP3(i)n3YsI**t zfk^J!%+*C1g`1gsAkz}|#Lh2a74sR|N6QV;`;a=NbL`G0m&CTvMmXX4%8H}#^j!Pb zTzD$WAzOXE6<6?TKz6tfOKzVBBw5@GG8b{PJU8HOegi+#Z5y}QA~e;yu2!C&EtNTw z4qG$Y0d`ASY?d1kqOl6Kk5W)v71vJ#s+p@=6&6eatAX`E=ah9+1I;>5n^7?i+hz*e za2?j&?1E%RGiyjFlQ44)1@Ti)mQ@>OZ0Ssyt)b*{}nm?|Ao;)oBa%^zHd&czh(649F|hUb*i z9^P|#?Ss5rZL%_2&Pu103tQ=$ydtxrU!o<3;X&3 z{9e16-M-06!1ap?hx*CGh?}ey&taS8aPV%b7rSgTG%?u`SKf4ORH6h^G9v4Hg|8Us zizV2woE&f)k%FvJRj_kdzNkr}z4u*AjvUbIXy7tUCF1x#eF!+3sD^Ve=#C;+cT+uL z`HM|=1u0yvIvR&pt%~QQb4rejyKawrt|PGFbnu8N+GoH=Y&>T~9E#qM5n(;iZ92}T z*RZ(Tu1&~v?nnk0dCZRZqS*oWrY{)gjbQsjP;9&}IOX2%-n^QGao)R2js~HrHg029 zxBQmwsPH~+DdFBeJ5ZZ3W(vGz{0|D1(RStZ%%*JpD``Uaf&68G`C}p@r#rRIZ zSDC(GjPw)n_Pz=U?}3D^55owqG@{w_pl};0>5q_;$y%NJsB7uuMy;8?8GdA`Q&TC- zj3&n#W5GOs)*fGTvfine8)NB7ly20gFPN-1>R`O^s2dwaLhKmAZ)Sw*iT}cGTHKwg zbFJ}?gddw~^_ZT5w_T5So$8}@v7X7+^0EE(pl6BS>BJeDt9pD>La%CZOR{G>(UU~i zis@<`?qZ%4ckfV|c@6`ctA|9{I~=mg{9k;_MXw^7zwK5|X2|%;^cynHn(a#YlC4Y# zg?P*3_$~L257H?iLJp@doId)%(#%z;og5lrca~k}JePO(<%ot;?4_A!-x6B(G&it$ z=KtE<5Je$x$vec%S{3a>L73KZuf%2l4|#4T?}du_t57WVm%%0wlZg?|4o-)a&06QO zabBhR09nuy$FP*@-DR8$St=8y&&M*It^2UY5hZ6(bYi5E+{xVWu$;V){K=UF1CB2q zh`j2;6t7di(%p3mlCPi+j(RRO`kl$769Bwt;e}w?&|06fgUK4QbLjX;WCV@Ij-c@% z9_OQ$sv^BVsH5o%su6-?D8Hb&Dz?c5Bc;K%7H|7ktMhjO_o!z2RcdcQd(S3@7vht< znp-a==iq6MbuJ(0ea#P3XtFrY_wrTEWNDn%i3j>3ty9KZ(JA&K1HK*bVDe~mRidMwk2=0P(bjtY{19IBMqKy_ZGSGb^PO|% z57_=HEV$7+Hz>aa(|Sk2sqXP0ZxXxLOYcLE9*T!k;y@1SptYIlVQ4`z=&PHKMo}H_(1u|P{ zjn0a=mzwn79C6d_llhw*kkf-Kt=u-Xuh?}V70s~iQb_NGubE!N?={-OGx>-Mr^6$* zx*K6odf2m>wB5qtn0nFK?9Zf`#ld>Vv&H3=h5k?!TGkM)G1;wsG&SqO#{#ZhU*x@o zlJ3yi6WBG^us&L^^~$B>@Yr51PF_l8{{G@uWIdG@c+01VWG(Pg4{mAU>*huayzoOf zUihZD<%MsVTUp?ZAL6SE-^LXQFBb{?u}7hkD|~W=Ppt-PK-N;twc^1Mg7i-gOcmqu}2uc(*#K z*ASdLqaN`Wl$7xIO4w45`5Q_KzEi<=y&Tx*d*^2A75;=03E3x3SJg3*cJ{-)cHr(Y z>hMxu#;wQoa=oHV*OO`fYJN5b>FaRX0WEX;rdYAF}^BV{8hYMix;17I@R$x zvcEnjMico02$<`_z-Qn|K2m`(8{nVOW4vA^?yAqTkFkRBM_{&-+>8Ng#DD=;^9cwd zu=@j+2d}`peF`IOBkv31*C`|IeTR=mmjp%+1~~TV+lXg}^2(zdQESueF;VO2*&_+g zc00#JGpL)w(G$@ODwq9L7v`D`C;8Vah8rR8z@4jcpkx&5K%*%enE!QdBVgIlJ8u*f z2XmkMP4d`UY$L@umZE+&RQuhW-6k&*EsVmqAT7yT^}`9CMBfd8GwDS-GAn1TF*gBVd*#z>^<mpWq3boDuYC9<>FBy!hOlN-bZzG97&Sifh; z)(j(ClOcOr2>lMfkII6rKW1!#^KS;9`YhDmgYM(<4Iv}4^>LTUh4h!E-VDP><5NTO zX#uPSA5%x6Gv1o1b(*bJwN9gT1UEn9-GA(_r-G>L$f3NteXKG)yRoun&QrD_BQ{Ik zy{BIiIS#E~*x=y%7V6g45tsDLc=-dlVw6Z0Su3|z&8{l9W@h7Z>xkKEr?!S~G)#|m zRxz*F%DefLVP{nmr#H8CF zj~l1c*Yx?=gC{RGS>oN^s@^hYfoO8X@yJ!r3^|~3Ql-Usa*UF-jANDlF5y_WYb#M2 z6iqGGhqRu)X!-G~WEb$@YqX6}!6tnYdfE;9;=<3UgVF!L&W=YS%ItTI>-@PI#`enbxt$+H z9NVFjN?s@ZhlpdQ|AnZ!%xe?KU6cU13X5#Zcy_QZ)GeJqTx7lR!4hewDK7bAF2-v? zN?8sy_P3f~zCxdTfkw=Y)1=Si$>xpWhJJQYL(dG7uMxpbOMa8@Xd?V}&^pA;eXF>l z0o(KJ&rF&RK^*P*upAot5z(5XOv!4O(&bvZD4kZf(5IYl-5K8MfoxGQcQ9m&h`F^) zgWr(HX27rFTYd)o3aNu$g945lOi!({efF1VeA$edHy>oC>GX6h+Bm9@)$7TRt(54h z7m!nXmMRw{`nzQHTJjrLVDgA@ovRnvDrtXnz|@~v;OF-HANKnT`~9W;{>pxTtzR=mT+4#wC&akc z3AeV$^oSSxkCB@YMf*cznzD3Q0#<#brsKk=Igaa(lVvfC!Bu+yxxikq^`n?FBc>G7 zx5I~KvnlR~O|celVpF*_J`uXUtvGHie!tIHha%QI$xNT|?5BjLwC%;#H+H?YR`dk+ zVp&+P*T?x}gBuJ>7=-_%VNhE5s2oPa$ILA)eB9h<;S=V@3!gN%yznV=D+~W@Zgt`R zm^-@gX>)4}pD}lA;j_5;QKf1$npBTm)gxE+$W=XZRgYZNBUkmvRXuW5k6hIw*Xq&e ze7r_yh)n<3HD6;>GPUgn!lp|ZqZ(nROSe3iSj0lS(>I^0Tg5h6tr9)AMA)u1fn?Av z5iZxlK*Bh8k=6tf$hmV_4kQxFxzn{AkYKuH!)6)!l2Es7IIPa4N3)t+^_mmc%t&q`!R*Oqsj0!3U_@{mD1a51F%hi` za7qb($eg>BLF@8R>k_}z`y4Dq5J)x$;&{o~#Sa-VZ@$;S<pB`!d%{uG~>q?KB0ykxJ1!@IJgp-Aue>wrp+%TzBh_D4x>8vAN4qw=vU zV9!uKxB5#gqh?zw3KDjw5GeiaKPp@8aA@8}g%n<{dD~7r^eXTkhIaZomJ!`Bu=f${ zMMW-$T|PS%&%BoWbKPJ&^F7;x!V_$tkzWjCi{%lV#Po0%aNTV$j*8F|XHrg2U>HKJ zPGwhlTP2$;zeJZI6knEuP<+K)_5;j~7QSX~yzq5g@lp#0^{|S`RXMpTCs*aYYXMp}#QL{!}o-0Tzaw*3)~lhY#6^J-m2m?BU}9YF3{ON>($K zF4xl4+?P1Pmo0IRL3{PL4(GbQy{g}}7puZG(5#9z#4m4Eus6QA8G2Dza;$S%$?+>R zA0@NIYMpu?tXNixiIkJB<11gyzQ6m@Y~GS0;VQ>oGdlB_zJ)M7f2gZK?>Zjh@tcef z>=qS2z$}((eKc_eLcU>3oIQTLxPjuRt5*_6gUxgLbBeq$$Zu|*d$2D%^9Fow|7wMK zjt~2&r@k!*LFRiHxTS^fm>Vs8*W7sFd*+rGzHe@2flob?ue$I<+@W~ZExrR@Y@G>`V)e7&=+JoGyz1yBd*o%Vt(22r45-vvAq}97zisUc_ zZBy%f$$wix+tfN;gFx?t&mAu**IVLlcAC|+rPsyX?9|fSC4or(!Ocm`T^k8zLUuDd zS?bM2<3@k5l0UvYbAxpY18j+L^CQ?mZ}3eZ>y00qTUz*u<4%A4D4V#Yd~%gfuH_T= zUh2nDT)6jufBM6jbH{k*i5|ziLtxJ_O4HQgM-*{$#AS_La_TsW^g$EVEcEADS$)9_ zCo{+&`+L0!RJpA>D)neslimpJH2L4wLx3usxbE5^m&Y-6Co389?s`ATKe!0po z*Yb-6PjD=NrgGt-8BNx71WDh0a7{l3K{;Mc=Vownf;@*xcJwU>xIx@D`Bq6{j>DI6 znW;)H0Ot4s(RU)k43DDDw6HKvQ-q9U7m=K<@ZEye18kL;%`N|-rkrV!-mtK! z92YFCR{oV*xyQFl^|^Lw!FUFtjNst~qv#m)9Ei^mA#V=s-RbP@^W+DzCKw0P+TF5=YHwNeyTCWmJJ@f(q!GyCujC+$ z{6RO#RA2U#EE!X}TuWEO9-Wgl?#S9hGwttVng%+RX5LecHU)Gna&>`1X6tg~?OHI` zlEA4|PK%k;-Gh89OWoavc{HN$Y!_Z-Jh~5wx);Zr|6JK?F|+ZPKJ+C;dlz85obHhQ z#F^{wwN4_L4Kw~!yuD+d=k=xFalF0+-(p_pZKgL-vm5idjRw!@6+u0Wjn8 zf16uc_>H;I!f$c&Tvv8+TlwWGzg*>)Yx&g+udrUwc+d5L$elYA4yy%@uQHSFt&nw% z%%tQp1+8za55zUE^cndV6I{6u{+b+%#?#eAKwNT_T(cccfHPc{VUN`!xs~MCy-O^3 zgG30hhxM7{AbA*pWRrj|v?l|H|-KO~evXxSH^y>K){ zPWCExS%DCHWk#8K7TX{0n8q@Xy3Dd|jwj#snN6hExjX%aX&sOCy*_SgA+HsEShbK1dU4PlmKOeC zZnW@6bK`|Q=9U+3GPkn8)mQRY7e>q-T?ovrErhrdAir`DdP%$R%N2gP!Y^0&7?a)n>6@XIy)8Z}Su>#ll%uCd3@Cz4*9Pqye97vp4}2-8|ypG*YfNSt${>QNd; zI~25G^&si8hbw5q>LSgc`k)Sb157Dgpvi2mlVx-1dppkNnv=~X*>}^!p>}$xV(Zu{ zFhON9W~)FWA{&ykLzA&TQPd#FCT0zV!SMWfF!M>McWaltX)F^(`_Y-6;>+0T(UKf` zG;*Bl_lT0kNu|rRbaC{3nI2lShIyMVwl#rnyK|LcRp3* zUnmRY?#Pvz=EUqY`1N#!Ov*M(=yoe;QpObo*LtQ>2kBS=5Hzt_`KaDXs}>!|O<#I}i$`ZXEgJ5cpa`865}o zJ2{h7E(9&EpW~#$Evf&Rf1diEyQqFTRo|=9p6W|*gXB7Xb8Agj$@T;@*NMzJtJvN^ zp7z=_8KdKor@9>EY24h>!YXs4g@(ED!i2fyg-LTO3sbnrOJBZ(M)D&(a)n2(@W>S& zxxyn?c;p%$_0_W+uST_>WRKT(YOEWU_o3I+Sl4U!px4BJxw9m1FO~0PiQ3DQ!|p@O zN#0(rpxuW!R7&m@%D1k6Gh&rg+lz?H`abFReSY@N&0z=37PT_qEVJik^L&LdF7H558TwY(4l6`OGqZGrp`V zmstjGhaBKY?>EuHYQnRv3G~;Zx#iu|0rG_oujq~t1iSYq!GHgqkC}N-kF{c z&ca?DkCF+kACh{s>t+6E?4@=zHbVORI&9UA*C-|VE<(XY&E(5e!)c*@)AihDWnn3G zS8@q-|AFEKb?UvCBXHT*WuHz3rqcr{kR7mtBtjhFrSylYyH8z5dA4T6 z71P5N>?htak8M*vz%_(izJnKq+6u}3;G$LGb!Pu3pQBO?5PM&7fd8;XXpMI(q`~qk4VL#K5$cmU-4c+5>~%{( z5;z#8ApAKIoYE)X#?6g@tKFb+Us(PS3!B+!=2b`QC4uMYmzrlp0k@$R%;Pa-gH19l z8%M4l#60}~HPlP#tGQ3Q9UcamYG@`uC4u{c$#+CbJDB1R&|8mEPWMG+zOwz!IQUmG z?7V;hCBA<^+KZ1)4`P!K5|xE7B$u`VKC~#8V%1^QVh?NC(A|@$cJdM8YBIyBoUi={ z)g&iyrG%^d$*%~cx&s@8+usM(T;x1bNQ=KYNlTzb?2A)scyCjdMEEc6nRaN69L!N$<{Rt@yD&QrdHIc>Q9o1 zrbb1t>K;gOE(-;G>7`~;wxMWps6EQ5PQwJw`AdneQP>x2_@w*VN^+2{vNtNc)bJ>L z-MErI1L>^Ay>7W%E~if=pzlwJ`>l)ZFUxgC%ER=u8CGm8^13h{B!IU_2L!hHGj0wM z+{`dt;xR?ZR{9|Q9M$ZFRQu$2hUI#KnK$$6Y@rnvqX#2cXv9P0Fe@HvZfRkoxzWNV zT&W;sldF8VeG5YQ6|ekqEx(lHE2Sj0XQn$ZdeD~|ICH0(QS67UU9^&6^b4igmgO(; zC0|#+nqj0-?hGR-iwQ9*y+b-`_t3JtOx$^?7kNJ_yS`Lv z&WGgm7h2RO(3zVza@&2q8t>b`g~oA&&DOL;l?pyTw!k1C>q)>gM@+#>cE1AEWkCqi9A<^eyi>tq>(I$yZ@yPb);plv^RHqumNo@-w$ti$h7Z+tfNt zi$e($yA*7Gi9LRof)%19>z1q#O+@-P<+5;CfeO4)1O;@^H zOBV~eVgdaY_3x#@gNEqWasz|kEjK3B4r7LGWvv>t17yR?jd4;38UX5#y*cWS64|AN zIXMW#?H!eU>Xj_2l`hxPMSaJpm)tF)pKp~o`q#>%<@8UaRp9 zqz!odq@dMxYtKA!Pd^j=R$MqXqrzNKF_ZOqNq;BH9{PNvXgJu<3(ufvcGw6Z*AiNe zkV6*{!qpMZrrc(Rw$yC*F?Sm{TLNr${Ms_aFGY)A7B5Plzcjzv)af>F)*z%EQLf#K z|Btyh0h6n!{{B0+yKgVEBt0|fP9`BU2}!t2cMp&O3}FjP0z?E7lpTWL1|knw?5l|5Wp8#I?3w;WWje zLG&br)x(urHU?Z}v?>_dCq3ZSLfnxnk1c&@wj*~{w7V+e{0A16B;8Q7`!~4K#%8yJ zlyj+VH%F7Pr#;+0?5eythy=G6nQ6Jhh*rX3* zwa4-`JF61JE!3k!IE8=-?B+7aE?u^NFm;Y^&G1;iMJJJ7{J)^PKJ6!2V`*MHlUP=& zXDN~Brz&fI)sJ#KRl zfHP$m?v!7y^2=3zxymnB`Q=)E;dp)%$3>mjwjXdT#6<66DAiAfXPk;}>^Km8nm&$@ z=J#|Zuqke})W2smy}N^n#E_NAT{uambY}RI@%sMZmWAe2m~7d4HIvZX>Lv?mKw`og@6VI_I)r_&ov*me4+#`kCt(*QO>e%&)e+ zNo~`aj&Vw}GaXx6l}|N&xv-s`HcP^xis_D(S7`rqrxpVb{V1!K)nMPvPe; zq$;QE)?E1_0}lMYpatAC+2Z*f(9!WPBY>)+m&@&^|8@b~PQKFODrkD zfgk?*N(BqPBgn6xV5sDca9an4Jfb(cR&SC6jUI1qw((SR!^YFh%{5NI6==ztK-q*9 z<&&#?a+Oc6^2xP)!dlkRWFhrZ2a;&=CBQkRt;v__vW-)Gd8eA2ZJg%HX_l*GDp%>`DxF+QC#3Z|Qe)o8HP?IK?X|SR&d9z_ zAF@1ry*|un{SEpuqjiqTCHR=p^6(1cTezTa-$?)xPxLli_g+nDtn9p7*Fi+F`pcd+ z;1nw`Wt(=9!O(7w2M+pqN=6>S2^%xhDDHGx33ASm1F|=pn{AwFZrFIbxw*z!=H?q` zOpR7Lxk@M3(g_I*3<;vA(;NzfgZBx1orHM5K6Db|1AMr7 zz=-OD3OAy9#exrGbzAwj+q zXg?}o#AH9F4=qSO(gJE4lf8B-K+!aSrmRcObpSng3P1`LKo%~57AN%7A=iIOK*?U= z(|ok-6|Q?65I@-gBBcH$0<=+ua@+6xGId=ideye)4725V4&>)e0a?KU*}?_#`yI$O zcH7n>s>fhf#jUl-7x4MMo`%-X6W8izV7*aUZI}Ac;nVl+Fmq+5zfr)?Jky`=fizb@ zUN0au!>dS};Wg=aK&H;{U+aK_2RAcis)@cyuoiFqvtcZD7`tE!#uO}!S-617B~dmUxp91Op* zNg1<`vI|{%w@hiTg4JFNS9=>tdw)bN*4`iML!<1r7DUs?;nohA&IpEIFEC!5(7-RPcF_KdR_#-1;Ab6`UlNqPibf|A6K3;eRwPuo)wkDN zRrHXK2-|o#5{UIc;Q0O|=osx!2i0UOI|XVlff(BW>ZtJlZ;0se2fUVj0tWQuvAZ>+o`dh@H% zt3_>+XA&Bq`|k%D*Wrul{=driXLY}%0edU@K76%lG@ypH20jN6Het)}?-6*B>Rqp( z=xYuz3jq>y1<86r@|A=HAEGcLL2ku#OJ2XseQ;_m8(XzpLaY8$)jd|RW;j_**Fzl#1I7|2F**uNe5WiWIu%AOhZ z7#=$lz)dG@mxF}UP%{8p!EzNY*TU6^GgJxVRsD9DjojAQ4XD$N-99=mjc-iDHp9pC zVJiSTy6njiX>~j{ zUQEScV}~5Daj|c`f`tWz%e8Ppag?CA2Pk@|aZIi5)rVR=S8z=u)b0+*437n~`xYvL zp%bO8v&9i-tY(7qx9WG*{N!do?oxMclk!`$G4pj0obF+l1&T&0(* z^m3J6uBBJs9^J%I(cb12u=MRhn&SHQbozD>-`G>>xJAw2^;$h)-4Ko)AbyDfLO8Zc z3#TRe^4-t6X=)DwtfZkWi0lk-*n{B+x+^})Exw*!x&CNHiFt^Znjk(3fYt8Ly zybf1rRdI4vo?MkDSLMl7d2&^rT$LwR<;hifa;-dd&r{Srx{u&HL*27d5vQnocGK5!TG2-OTCWxD?)o}FcDEz?TBXwj zRekwxYjvmFDuDTv%h4XhNIuKh8}@2rFmwin9_>8zXlHug z681a~eLeW1``#dj?t7!T*~Xj94I5YD3Y|(OSLx&`om{1pYw3jUO*R^|c0N;p@B_Yq zEF9Yhr0&H>^mW}=wi`HIrQjt^J~xKf@wuWfzBk^{8M&L<+ros}{Tx>n?cR)z`xymP3`Q%zY zVd(fKzbNQ^5c>f~t7(*@x3wT@KYU|4zQ;vPegRcuw&HN8B9;h02k2`+6nUV&ilWGa z_!^y6vG*imTX@?LM28c=o)`b4yO0(oft>bVB#?K~9I*8+IbiGEzI6&#D-|x+!qwX2 z)Y^a2zQa_DjVDdKs@W!9RX%;`xymP3`Q%zYwffk$K7L`VkB@5N;BauT zK{(i-o_w-CR;hQ7Rs!4i*;QTq6h$ml7ayaqx$5F$m1LhD48&&b=Oand!X8(49qX>_ z5)0R+m`BP7J=Eq3>ca%Jq_pEHV5*e1siROWRI=kID$I+zR|Z2zv$$x#@5$HmA?gA7 zANJMBD`c5p)vi^wGM|;9qnXdjoN=1@tX0;uL!nhqnXy&Z`r^%1@rNX>I$fnskv&gS z3z~&q9}JzYHq4+R@NM~sYs*J{CGx5*=2vAKleRoPY0FtNwdKr?Y8`#I_R5YB@19Xh zoM_=ZG#_)&d|VD>{RwlkjZc~zHm<`JbV?>y>EtS%T&0t1=>+}$g1()1CyT6S0k31t zRjBmYYTGjCla;FIlc00>a*90T-RI(+nRh>vm=?nQb&S@WY~xcN9&=e1p3_=md|FYg zG0thOF)Re&%@y#c8|o8?FQguWcA-BUBjyJCcZe6tqVKtV$QL-`K`}GT);$pmDBH@o`(C5IeS9cw^@+7x-``T9BkQ>_F)fC2eQDGsvoBuqG z$!?Xlpl#zr#@<-c5hB#sULMdJ91T9j>kRSpfi!8b&~YLLR^ zTDTf^kn1ArqXd@;R}c)2k4Xp-j3$H##OXrFYYA*ahW zp#c!RSmz-Ba_Xpg!uM+eo+}UK(1x2F%*}lqMXL>pmuvBA%Nv?)3GJRz>T2p<1&wQq zZUQ!#?CxKg7`|N)eu)9W1!qLQ1+Uk_Q~K1tyNcLWJFg3dKWj}g#YX!+%6A#Ntf#-O zMsQ)BhgDv|Y<|IfZ5zxd2w;BTUhk%su{yxKN3hxO7y{DoH@7Wn2I>!*{`w4{zN-UN zjh8URuB-h7!yKunD;WLU1T&L5#y8-bt^wbYLuY*3+-&1Jz9EWMgA^}U@p3I*4g9EU zplsR4eccIty$|?YpBz9-->)W*(Z~{`9vY`<4y08mR_j*L^H$Ql9fM+7i=RdU#G8OEzmo#%`&|W+mCxZ_F774 z;ryq;@D~lw@MJ_ZY0-sN4RnvqTWK!XyiE?+{E=_Hf`tWz%e8P}zl1QB*DyQn?a*A`*ZjlW`>2CjwTY_*2EcC(Y$Ba*0lA(@aNPtX*8`d+#ZyKMBigj z+VuAkfqOqa)>fHr)@iG2>c-O-JF0mk82(Bd1|MgX{#YpF;yXED@~0ki3Kj+xF4w|^ z$?F_lsrRWl00GQxNPYrS%?~?3WcL3V0h;}Pi5vY) z>JsWfHg4&jjyJtTllf+&y&dzNK{xFeaKCm9yF(7WbEmmnif1mD;+e~(c;<2`9s`TJNWH|NO1M(f#*PP9KUdpKNwW@w{X#z5(0h^? zj5Yi(5-K8b-P@IEi5Tv$^yT*^;JUxYYy7)DtA>JSDB5_>J;Crx)oHWreR)0I?`RA} z@OwGn>K@-V1*?q;muul_>kFD~oxb;VcLHKfa^PfY0 ze7ym#yE~_ESWUC)`h#H4HvTAwCfsXowsD`iVdGEc<{E#-Ra2B)uF}g@dbvt3SLx+i zdNujOZX9&j5B@=oll|Zy^&$Jgd-ZXsdh|Yht!~bvf5Ph~-sLWgzWsAE%r5e5TLsM8 zxyYAooy&-MkN{`)BHTT*iMvlUan~-f1S?tKv|Z%a+R*VUoxjj*uz0^5u=rPVvyBJL z4I6(mH`jO&7wj~JY-JO+luxem$yGkN$|u+I37gkA0@7G{k%yVFqQ;DENM_`}H_;ys|k)I_`P+w;*laA@m=7jx4ky+^IO@pa0@(_Ep6{iEY78 zKV-7-Pt1*;?Mx7++ZI0}=((P43h)XR&=xMBPfhxzwFbBDpmS7*165W?S$t-dljdVK zE2Mz97M%YKhQDQac2m)eN;nayM7|Tr$$IE92lhWanDPo-^9$TBw&8d~i;fE9cC1#m z6GePu{h;?GeQ**PV}8CyDQN0)El+q0U<46uY?<6PlipH5n&|cgfni!!)gUdERWMat z>**+cO~9iW9NOo}ZI$y&I~g5j>_zihIWznymqIxRqvKHHL|?PR`dhv_2i4D2++6Rn z>5OOE&WAGM(My#ntMyWgp8SZOwVc=8xW;WaUE?NIN;v*L>0CIoq||n1>1~uMsq|~E zz3xO0W@64i-AwE=YO&13RD$pRDeAKUmEBbT3eF&fU0&*w2InGTV{yD1;{)BGDX+5RG>7^ z<}JhL2Ap(V!}w+!XG0y(-4P7!;#6C+qiLsu@_*#O)OZX=&^4h|w4hbIT#FafB|$A2 zr-P^MCb*?3iS)6naSTA-9iMA}@wAnAXXj}vh;3o`2f?spD2HTLGTSBX&0twI2f*QL zfrEcSUcqaA!TbCK-VWQUI(4=9!>D|((kfVU%H!Bp)jB}DP3lk`t+I~KHqrtGTxQJW z$~kkxMrdxXk;4^iN+(z8%K+8GQB95rx-9&kOMSDbF+;u zbHheAu4+*-xk@Kj>EtS%TuUbmp6%$gW6ybY6MuWs>HFau+YQvM(Z>?;*ZuX?vZy%# zuMxt`7Bx>Iy4Cf^1WUB^OP*Wl5kTt|mOQs&A#KEJeu4V$br7cvcMnzdT00-YhbOtI z%=qArO4qYxNPuyqt=v`+=(;q8u!G2de_h(DAV&8RMnBOCWoIz7V4Br@qSW@xpcmlj zjJa~?jCtl}8zr@=tp!RZq${0VrITyv)Us|z#?VB^UC;t>Ot&8kMyDi~@%+*9*MTpu(LPgsTlQx4R) zOy(Hm0@un(-*jH&Y^LoUKP9sw8X74^< zu3(vyS^`X)4VFs@6z*=$!YjMcQ7{Z*9s&(@9LL(Wp0w=A)3$$e6>%|KG`c+GX-V$S zm^<2AT@q}414Ao*8Doft9Jp>Uh-0oU9+~82xgsDc)8!o4_K!LLZ_4~cTbUPHnFX#E znypO9A)Rn8XoIuY!?{Ieg8G@^+CUj>Y0c8sWxkB-+ThwExSAL0&Q`9@MRdT%1tjfQ z9P}l>w5{X|RPqdvs{i(;Ja)T~4PQzBY0q*Cm?>5l(34yRThu0_iJ{L%=Bfpi5yH6< zwphQjZ1p-aRA}WvaKm$$06Nv|64(xsUu3X$BDc7aQ z#l4A#6lLxWt1aYc6vMYp4eVFid!h?8oD~g{uAt-r==Lnv4?~5qZij*BwIWiHp3!MP z?sE-J<=|Cz-oL)mr8p&s&m;^=EV?g^*UAhfzQLtWs+y~+j7+yW1W%99)!V>ueiOL4 zzI#-ms`2op^)_FM-5=h@4dNFO*@aLZeFJ2u1CH$Cim&)`f)n3KypF5=Wnt^p^vp@b zYv9;>$KPhW^i&VyqNwlirF)p-LrK^lhFsIsUM3N|wcJ@~*j^|_+)NSmPiwf_7`_s> zo&G8(ugem&iodh`pS};`4~(9?uE2-RiSEOn63R`!cW?U+hX%&>47PHdl#3>4kSCAm zt-`tQ(W~6IP#(R_zNd~oreN-~awyUMc_&`aqc>*2>-hvf9$v+S{(r~o%fLlDUKgFb zE=Q2Ad6#>n{~Pe`Qe3gk-K&QLTe(1%w;DDrkpia5Uk8UGVA!o{XQ~s>W{Ha`e22{AS}maup|h4K}Bl7q@|anGiI2Meod0g4HQK)C_fs zw8#A4ez^KmopKeYI!CLkJh~>Sb8-{HNi-@M(e+RKDr#>Fojf0Njp?02Vd@tVz~_yR ziG>uy%4jwm>K%hIJAQmH@$5*Jg4!C#%qnAh1>3lcTKA;y7RI~p%MEH=ey>~77v$pe z_k{NIwcdPu3JQebFDy%?j4QpK-D3KOn@ystaqE4-Hs0O}5T2qr{fY2&LQ(_FNAryn zHZBU{U0~3)fuQaACY00HXvBJc7Z_nfoyH2dGFPNJE;xR?^-VQBHLzu!)3La+4e@dCe7ES;(agWr%zpu;0Ox2h;LszWMKY z0=omhz5hF9m*u{LF9A3|(&Cr223kC*aaQK0Q0obaUgeQ!{TP7+y%NOwpqCF%3woJ? z1a~^6Q)^$czW+Cr)s($U^g~{4({t?3}A3MX} zBG-+7odLFDhhicqwF*N0Z1y|=x9kLnO*odS@@Ak)(d2Q!)rp(Yro7Z&9rL((m7qFp zj?ukXQT$TXbGi$#dKQ5tkwbN4l2_ODZhByE&2*OCF6|_Ee|;O?C)@C@uAdIHaCyiy zn0IT!Jg*u#nA7F>b*+-q@x`s8)A2$pJDC@!^225}|hCLg~J2>BI;n!+%#Yd?BFyx7ysn;>oUE z)BxN`1%lr3oAb!~70Y|O@}|40{kd45p?Fd*6Tb-^!h4Dj#)@m5My@jA2M2oMZ zw&Pi01e|a1)yhQxCsd2|dxH4GBpvD=>q`4C16r%E=xEX7$lN)6a;IfeJ`q3ICV1*| zMi5?>Qp_AM^duo5Q_H2pXkZzK`od^F4x5T5K}5$aRtcgvO%`9Z_WXx-g0qF8CF#ly zYM^zUT-hfVZoQk18WB6OJQ8?}2Q6(5K{02o!A!6$jm-~Y6-O5egBrbz+uH))PZyH^ z2GvOh#q|^xkM2{@$Sw?ZjqY9DKeUw*=7X+S=MI&|xSGdxF~hP;bfHr$=F99(^xv{S|pJu4}K^S^ikq+X8qu|1H1%AbNA9=w3aa05_W!)8$QEnY@6?F207q>?H5{6fY+CB2SB5 zyz>1*Al;P7*=pJ)%h?h-NvD=}r}Oc1DP~h9A8U2!(&b|<36pf{(jL`Vh`VU$3^l%n z6#bbr7?u`o6HPZo;tVN;)BbFlb@$;EMM}3acPag9+|{cJ-Ez3nm-F{0yY0E@#ZKkM zxA9^(Bd*T8XR4EBUUdT7km{t?=h%mnIc-|DA#b#aypX!N*@~SywIQ4 zI1)SORag6o;cSs_b&cmK;~)^jch_I>koi#X8IPGq)43IU%Nw=@7i@VMN@O=cB?~)= zJ$eREzHhF&6E*mDW(T=1_U;bvUhLhMc=x5=eVKP(?%hkg`wH(~>fKj*_cHIk%Db0) z_toCL!n?2W?rXjKI`6(-?puS&dZJIUCC49pcf6cc?=vzf+!+7^f31;=w!5tpkJ zYs?Kh=XcRuSn1>5RO-k@4nafKc7bM!{!yys)`yw!USPyuiAo{uZ$?cVbVdEVhYpOojF@|;EI z!+iZ^-NtR3z4$IA(58lWG0!vqd%XW@@4nZ&=dz`z^w)U*`{bT7>DDj57jB0@#|}vl zBWDEBYZ!R79@ctL4%&3L5*^V|sc0jUHHt*8;LI^+T!~~d@zp`(j_9l&^yA|@%E*Ch zf?#`@qAC$D0#wag!Mh;(lDz6O&4u5i&(f9AFuh>3uR7e3rC9C5-^x=&@`B4cem~rq zw~MqBs;yY<3MQ1tr`8t2n^ps@K1K(D%hAhWkco^~k(Psa3j zKM;?wl2+8`u9VvP)mpGeJ9kt4VHp1ey8_h7>FBnF$o9X-7xk;Mwocg>l)=O^(a(fs z*H%ekKUCSlb|w=##8K zJDQ7!I`Uc92qfzoWoYY~Hzr+EYt|dsSiZ&eO@-!-X@7HpFk2^4ZI~-4CTHo9vt5s@ zQIA-TU4$MeF;YS4$h_7zNu;+LPAnnpA|3q!1Vls1aS^8mapRI$K39dC=PW{Mfz~KD zwnr~*k4A8?v^$X(qvQ8aGVr=ZR8zs!?d&>lv%Xf^Z7A)eNXqd#gk-6<61vh8KhOYs z4DlnEo_O{WFQBC-p2H^>wKai^kE1TSoAQIy*|cozydlx-Q4XD z4e^FSvofgNiteHP;lyWH+PWoyGWHI)WrSN=!hg|Tu}<^YE)EZ+m`4)qt<5Om5IN69 zNxyZgUjAs}Ca`fJ*xOp30He;3@@z)PtX~Ev&sS>_I6kGyJWh`FIGL^7<+GH_xpsOC zoeCV8QQ|7su0VX6FwQQvfuoS<45hL9=A;(l+Wx1D*Y<;y0N-Gqj+QE2lJj!q>ZS!`T90!eMQnkO{0Vu5-N_IGPHC2)K_Xhxlve&ZYtf#;{cFsM>YYEeta=a`mFCU zy^b?xs$-xMpR5-90<>lw|HCD1C{V8Wsr)lJSYqdon>6@1G#*cCx#PPmI#E@eF&(6D zOOJdI4LsX5aIRXG^z(VDH1V9@?$Pd6Gv;ZEImpAWRexpYoMz++?U5Ja(RAktwH%+= z9{W5zQr09j%HQ-nx7~A6yXWL~&$;a$36`z8PEi!Iw8*Ym>;>}ZJ*IuZ>vNiTjbBZ8 zaexaMM1^f=>zfmQoe&q!vnA#D;r0=Fs)|eCkJ~+`$&=9L|BxrXX%Qh@nawYCi@!v; zKM@Qj8c1KB4;PGP!ojirpd1T+X=K!1Co^2Z&3QDj&bFiIPS1zPHT9Er?4@}28-|rp zb~Q}F(@R8UMwkuq_m1YL-wr|rGC<}hIyK615rx!BU?bLrR$ zbNfqkOqb-^r!t~pI#N~v9(1Zu0Zu|t0R}`G`Z^OB^b@QT1qJ>ugR4LJ<%U!INqmw< z>69i(SIubb1ec#MC$S1)lstAR_4W=GSQpqhtFTY+2C)>OKvXRA;+Ts{w*1*bL!Bp57b1qsxdY*#rdR#!?{zooc{Q`dbO z6=i2kw7Vn~$^Cyjf|B(yqL7cJ>s?!(aw2Qw?;u>UwRVoGqg*kNp`I~W^dMs%0tv{< zV20S}P{m=^)BJ^dh^37Tj=xqTS6VI%d#ce#DRSgG9+2+SjI1SSiI1J(^O(lQIpxYq zRx#1}S{Js{?~CaX{XmtPYRAwsh%MDaR{@61eOl&rZTZ)D;2V;j{D%bpyG1_pqRS2e zB^GI_Ix^_xFIURwyy#V((T*kY3Ksn=8JC;iwgBSDhO`qO5&XutDj?w1Ow*kO+ZU;} z3kc+~NIoa}H7ARoEdXwGx)AOs0NF(A`P6NP_r>#OEnz?<3{Kuc%Y@pO__2x%wi*H% z|2s13h##fed`NiFjnsF$>Z6AxXgU5>PnWB62BSksSRYc9B&`L}I{D|yZ!+8Ac->%= ztef!5zpo(lf`MXs;s9V_N>Z_?2m9v0qxDo+Sl^d#D^ejxs?g;MQK1SsN+Ep;5wBOs z2Guk-oz6vBIO@e;W!=RNR=d~fdGpforhY|x28uz3eyc*X^?W%TuZemIcs|Q(=_>2^ zYrT^gI2Vf*A03Sn*wvQkjUcV3dJ0=ZZ{o{rE{;H$vaKh3PON~jZ$%rM_1;X4ds~LT zybKLuVuZ+*21;%w>wD!=7hE0vQfl;SA%|*h59&gx8oim4>+i@#XF~GDT)Y>-2|QZo zKb7`;Uj1X!sm7~D8jA1YXhk~#eVJNMX7~oGO-H7rhy6s~Cy8ctlN5dgli_fal6|#3 z8ME^6ngGK(d8P>o3%Chw6x4KsW$FNarB5Mm4H*+ZGHmkxN4E(FvMej|wNR>}9-EVL5S5 z&3RHLu{L^qt0X60#QTuPDoIR~PE@f2)b9i0EeRM&3T-dfR-15IJy%YrMK~_ zua>q2PL{+gD0C#f?IMEMpeW>$An{s@W13m1G|VHK+1;qrUfed#&$2eShaD--T1zjX zA9A`23*)W4VMsqSFgVFP{t(QDlST2ky!q%S0&$f)*s<+;Z7q;j{VzUsm-Xc>BykgL zepeE^wBkP>WvC;sn(Hn|$1a5V!2%Ll;84ne>p~N^Q;tUFW(cm{rR|3680Ku$5ytBl z#mZ&_j<*tF2nxvUWGlmxZ9|PQ)^1OseEkH&=!3A(#{`~h0}K8>J00G+ z7BD%yQ-=*>{5&cL)7?GH<>@MO!v^D*@LXdRE`2tkuF}g@dbvt3*V1eHym&px z5$=jQQAWdrZvYXdqBub$y(5%c0z5Y6c0+#IO>Z`oM0wz)?EcAE!h z5NVKTVF~T|t@WY8;@2UQZhIEA;;7=xC8Qggi}YhhlX|mrvnI=P$>8r*#4!q=L?-5} z6Sp|tr7(s_WIgr3U=JI})?@C3hOBF9y@wm-nD3(rL9jpgv>XiNaHmkjL zmS6aD9k`b6p+IWNMl-qQc%{)$L*~;VQr zI?FQ>o#p*#VG|yp{p8=f@o+!z+mSTRWO8p5>@5?)US?1r@6)EPRO09%{+YT`Wu%?A zO}R@Qnu9LFy+?I*DC|m*tnJ@v;`s*HMr^XMVIo%43!dj!eQ+2rBfKXp%&bl7&yd4e z$=2D08!7QVt+Z6*e_KMMHw0~UNBJzsw7!|dkie2m25yB!7AK6 z&-kfT#t<^41*)T>)JqmgmIq=M9aZ1qQB}gb7hI$fwj+ zOK7H*ll$@na5;`tK4+Ppg0R_nd_?)QFVmh6xnfGb-;l4)#(K1#m zEWxa6YzZb^(5aN`*I$OwiY>ZYtE$+RQ)^nwDNEI{oceDIqeRT7-yN@hVsbuenZs#n zd1uBe@vtm1s{16NGT)NXiA%DF`JjPAiArcJZ5#A|G@Mz!GFMe167(T23kRrKv!JgQ zfq$tM#E_x* zzOx@UJyCQf_1Gy8I+1tA&1+@}-PWowGCh1S)D>+OL{J69V5!cMKk>Xs9)_F6$Ryuw zVa!mM4w?Lyy1HFmtJeO2%@E9ep~*&aAPfwCUuX=dy+rrlL=v zv2zA-A|Tl#&Jd;3Op2o2_j#RXo0j&)#5ygljEkhD6*^*BBs(pw1rG>i|F{%9(KgZV zF1Svos^U%Bx06y%o|l4o#Orc1sdc3NGx(UM%Ue&0yym-zrKG$vk!hHS6PTGqT;&82&J&S=g?%+}JK{%%t84+@9~6rB%62*`>kJ zuI#eW-Kp$yZ2629Ted zG(1u#htVnWgh3?MrE7pNnQ-u&OTNEq{7f98l>wRx`mC#ZWX>5>ca0Wu1M!>5Rqe`c zl`Ug@YQ^aVcr>S2UpW4Q*TUg~?aGaCuobf%S)T*5c@C+**?-LF-}q4mR9=ycNI_P<52#P^81`8 zh_5D{?2oG}!wE&Zc8pWbgOn5Tm{PH5x{vXn@Yxk~SC7dz2_>HpO1?!XGUNX#Nh>E~ z_F3*@^%ZdiNs+^q4^b6Y#}Z!3l=t|3-ufJS(vOERFCwucc02!F{Rhs{j=u}SaN zI*_3H@9yZu!l?Xgs4qEsmU3s$`cuPWX3lGU&N?CW5anaLr*=;c_NOuqV?SRG@(32W zbyW}1!j`Y@FrSZaC#tqbJ{EbJR$FO$sskWTY5KEaNryC*Oe$)l$=_0deO%uh7Y9-I zv#DEqLMJquTPe}c7(6B*Mq`k0ZN6=17CCV8MM#JN@I9(!WnPZHtq+LkD%9ed!YEJk zk9f<&!kKk-mp@a~Gn%UwhYH1NX{f)*O57F`(XZ4>X87St1F5nt|KsyXB{W7xh3;2% zO271o)hY3|*2n#KxSHR!^`r5i^CeF2t#r~r9VHEv)#<_?_2I))!XHc0&r$kO4n2OJ zvL$UecqLN^j}A}5&}W4hYs<7a%j@Fik*`AsA4J@^Y|AzT@l5;`mBP&sGGE;~iUB)9 z^Bazs9`+W6!El=CGIpiKl`{vwUBSSXNnJ|){{Zg5^>a9RvIswIlL*|D&1fC5sW-#_ z&D5Z6lSQN5r7V{FP#I?bhw(yZPMkYo7gkCx{vM3JJD=`L$G;Z21_dc|*ivERG3+U! zV#%iq@f{-3!icLG)3r?WEutq*u@NYJ&q`oqN-9;{{sN1W=oY9AY7Aj`HN@OhoR z=+Bq(^_<=#ELM9mrF{Hic4x<53X${|(*515e*{b=2>933-rv*L6TM(pIM!HqZ>GEn z-wW}LB%yolTk3}TO1U#@D>K92T#8oF&TsV3?VIZka3s4;!PT*CFR2t3XQl4G-sl!; zsO1z=>K)0|@}+FOUJC2G6IqC_vBtlG+G-0bT~srct@P)r^i4faqD-l~Kg`vZ1bI@= z>nlaKlfE>smMzWesbb4df)dPBC25}N?=E$(S;^VjNv@=!%Iu z#fv8H;(r$k$cG857jo{SrWG>en}&eDPega2wlX_BXF3>wP$>XLDdXYDYpi8clhpMe z)s>EZKz=bMQB6+)oK{AUsh-^qM3(`90ZAX#E4eXwrLWJ=*9P)a0u$h}9LE=MBNQ$o z?9Y{QW+9{mrJPi01`Ee$QY=wQ{^*=wk#JTkWCu3(W(GFW)HaMHz|`mFIe^8eLtX!< zYRO4(%ZH5VzO03Cro#qyvzS~hov*Jg)aLn+pfC_UqO4i2gm<4*7?iU9JIgV~IlUSE zAI&vOQ5Ctqyj7tC9}sS?W&~K$+G(@}cA-X5)`Xx?3R_i`a`x@&D&?JL=E@{jN~iii z>MPF)(?bV2`HS_98C(sAoMbe)t2c<}!ZFejhUz+wH!yxTJ-XFB&J+(Qr&GasJkr?5Z?|tuW(8YTd8$Hy>_@^g*$|7*I0B_GXvPWg=U=2{9Mc> zU!2t$|BdQZ|2mx%d~9aAMn=6AfG|r++sB!;(R>YZF60Z&&UG-8SH~7MW{#_sGRGO~ ztmPq#D!VfrJmnuVz3?RYAy7TFeSI?%vaXCR_cYkWi5az)>4MYKtO?#g9=m0uSrldQ zUOhC)d3|tm1?y96i7K(Ai>?7i!3%QM5pFg**X^M96n5FOSXeYVTG(ZDb@gx^Y~*xf zw+@ix44rlss=KjO3QW|}+5AS~J*WMTRHjKsLxr_JCmnpOuJDCrs@bOmJ zZaVb5`t#67mNu7JqB?q7tM<7GiaA5w(w(zQTHvW;`TCx@==FrvqwMfc$t%&~m!L73 zE>ukpKAldcix(6S1@fC~r2km(1kxXoF;doY#F@5{aoZEg*qdV_%0|CXp9U4qZ*pQL ztm!`e57Fbb<=NryBLFAxF6cnHLrH~Y9AcHale4Luc+EyXp|p$}CE8kA^J&}$71J~M&(8RtDE=OcS4@A#0n%S6ae8|H8)yO_bJsGDr_#n``m-75GA+5A ziR|FeIohO#;q(`i@DiKjOiAv-B1^MxsVMW&T&ZXrj~p7b^&vjokh?Yy?*OCO>KIbkaqM=~DWC~~R|XNT`%U^ItbBB>=362%z-j_&2;&U$Y6Zqiq? z!#bkbmCenblf(Ky(>S7vE0;Z96=lSAu?@)&i$+&-Ub!%ekj#n0N^;_Gg|Xvqv&`+O z?ww4^QY?4J(w_Hl2*?Q0F0km)grOqa(7-WOPcc-}Rzu{_Z58Bg_YCbuzat$}Vkd!x z+VXn%}XkKGoo+?tFc)ScgyK?1&*zf+*GgihQgjoBt5UBsuB5pNnYK}<5n)+B<^s{(LJ`2!uwj|N;ofJ`DogEg* zCag9=6^jxnLE&T|YXKv~`4%P%wCcKMG4EC}`(}qfzx01!Oet46N!&Mg@NulV+}bsr zdJ3?2fdj|9(Xp5ocV4FR(Eo@-d6&biJ0QuSJcrnMD;;7H#@q_i^>f?xwdPvoW|5!%jtUGa<3%FTKhY4*~izyk;{UKwJ3Dz z{lRv*L3Eb^^-h=^wp$7s(H&P>m$8~CMVwX0_6RT8`9q zfm-YXc5j`AFkC=c8u!XNb^w)4iz^{9x3Q+a>S)RHCfV5|7c9a5b`7~nK*Z0|+3`GG zedBCqW&Ns>yMRM2Tyq}u>vZt76P)Y7Im&zPq^Nj{El8`2`*P8^KJz(7)|<#)2h_X+ zmAI|M)o(|6n%h~1^qb04r#rnpwR>hxFDOWPGu8D$J)33`sKvRh$flUFb{e&I`ks&d z-hF_EIe$xaMnUnP2*jwR5~AYEAMeH z{mxq~;+bhXi-N?*{WJ`qG$)0mKPx&7T5Z6&PA-%#PnH1T_ERBsz1vxwe3Y*?S?V@{ z`r(q~BgI7X88ylRtg7otxLOx`4PmBM@-nAi3`<86n!ZBp#3{w{e3?Sb?07P%zeD4k zQz%9EgOMV(+P0grn%y~(wY1k<`yf#F+l!!}(5e2|kF!)Mv~{a50~ExZ_^*_*V&Vb* z_p<{bCsztD7blR7a@ATcbzUJ^!Y`6)90kJogCvgs&cD9Q&iTqvU0=%87nOK6Pl~nv zoDzoZ2}`*`Y}&R~mi|%}CTY)Q&p7&SJ4a=?C`@8zOe18q_rT*d`O=BtHfG+)MW*g(PJ!cDUlq;;+)gMzD zv@whyB{XMeG#|K>sXu5uyuwU89>vj?SXLsZuI==f$eIO560RH7+QV1*^f|(1ePEgU z<-u5_^VFzC=>o^u4IeBC$}o1jA-bfzrs2bsXl-6UAgeSsBa^DpG~4E+3>cz8LI;GDAbuuMBknvJ&Ae~Atw2So>_ivS zirEUNa=Wa~*$P;&*$VvgQbFZpxLt6at$@RSZY8Ij$vB&>0Cx|~Xe*%U;R)FaEFht` z6|no+cqXAbQe5Or1^y=73dw&t0uc4_phBiuXw7?E3oUE-lY}s}vBO5ou+$@ zQgs*uJmHOg$;HU!Pvk5H`~15!ZKcFpng7|RRX-*Bw7T=miF#8v_0>j>jqx9PF@0QM zcHIAUPv3CTenxu@W!QbLBFb;zaVN45;)Zp_=wcZi2*pUq{JP-PrRW@M7I_$vvy3&) z6I+rEByk7d_uz{;EStKJwzJejrn3|W5bm}g&ASON+q<95z)KhUBsw$ag5s5^lDgPV zba@3p$ISuGesDTWW?RY-Zq}&rY@VkGti*FnyXU}m&#~>EBicO&$>T*0=x?@j{Z^Tj zH9FUC9x3qJZyYfD-~^I3HghwNvr~sRtz71Oh9C|Uag=z8z^9zm==sO^SzBJPS}ZBe+8(^8c&QlNWrLm|FL{94B~%bG%tRt}C# zwGc!2xj}TC!eOF@lVfT3h&x2sJJjP?&Z`pZq=yrhbGbr_$>#FZ58Y?p+^bI8UN>h1 z43A%B-G4A`EnztaA2Ns1>V z;r1X3M_eqFT<@lMa!;6FO!AHE3D{|71IV;0)E!aKqXf^x=T96=eU#w2M70hZYzd;% zSpx*=#(HX}x+COd8%GKjYBP5#Hrlb|j)X48TJKI8j>9UasGKU#5DM<>YAtyNC%3aY zZ{c~+UCTb`uFV~sv8NU#G?pUYBZecm1hy0S) zI*uYxM^ZK@vaJUdE(}>Xjrb@fxc9Zrr-T6x!uaPtp6m-adP)HbR{<7|IZ)#%N|?j9hTxH73Pa*a8*?Ld1F%i}1;l=9sD(o^8$(f|XN-B97r zpO1}()W~3g4~>>3UYAz!`aruq3Gg?j8Tx8}C zzta-z<7()p^n^Nd0Sc1eHv>N$SfE}uQSSPJU_yOd>visAusb^OImQ(CbxBzqOQcl) zT>@MSfs6Zo8aWb*RjFl-Jf3hu{}bb^eY{s)Qy+GoXkWlav0@36KCuo)aQKTrc2Uln z>u}847L4UvQL52(L-aW%20nqFjvu9UoT@ROOAy~XJ?K6KIXc{jcCa`pv3eBvMTd*D zVI&is0VzO>ieY(r0}bHBT&us2X|IU2ep^lA)s>O>9tEA{lDUP4!({x2wzNLz&kFJb z%t#lHH6;FHTZ~g6Bu%s)jPGxc{|HbvQQ+eLHodY3rw2WtprlEbF&+O^VWLC!SyFG) zc#XaWGU`Y2x~tr^4qr9~Yv>9;H$PPzS{r>Hr&e+8O6$}`xaF5UFiLFeIZ5QpRxnij z1HS_$@3hyjy0eDeeQsS*DrgYt)K#%jT6bri#ws+lYinI0 z!w7z869wt0FQ=V}B!xvwM5z>ZCm^{7INEV{W6&bTrUutG%1iE-i`GH0c6l}oITH4CknLjrDfrljqPdg;I2dE8N}Ki`0J5zKqMHZ+c)LzHAxvYw>G)w40v@y`JA;nodJLVRRT1$W zh%iN0zAoGR6<)S;%~tkVxjq-+)J$CH>c?|&1$5A4?S=x^()l?zjldm^gf!dKbh!32 zqMRT<;tO=qeq!khoWXK*JMhd_Nqds6yp_Iiv{m4?^VsN61#K1Adt5p<-ZBe%uz__M z#|kc4PxS!zQ5hY~IofT;EOTjlc<8_~RYnU*h@YN%d}9jSbL;pVSMvCo_k_-F%*KzX z3pP1)diLq{rYEF1o~n_Uu?GNAB5yk#gcnmNBDYcnQ~WE7xC?lNL$NrBl>W5172R?DDKfeH^^o; z^b{&5J+%w7bv5D)NQuIYLAreb|1^;D9IBpp~q)wvxF6pL|lxz>KNPxnps zx`Lr2i2 zl-+X1mU(}z!pE(IFiwcmm(2~}rYtMt=#NyQ$>w@Lu55IT?cy5cSUy9|Nm2ISCZ^{* zNc?|8Ky*JPMc3AVS$9ZCj@M6lL8a_|h7K8j2Y~O;Jk|;wJ_IK1A~q6XGGv{6zf*rr zNS+%Sj$e!Zg$MrdL_4@UHolo<`PAhZdBiiGin~;ORPRn3(TF$~f;khZ`?+c=jl{UH zSPd&h$QZNmz_?+poA3STp&Yel9CH^|C(%O+|S3(@H?=W@q;+7uwsW|qJQdT z2$DU}ne66PGR3%L4qoZ;Fv<`g(1k--Kej!qqLtGUGZZ(u{XfF+k1qqmy2ZfmH_Jv3 zib^)Xy?(?Uh2uX&3+|G5e8^6ISK-6Xox-EKT*6yOI1Zr? z2ixG}Q(a$Yb#G0I+esv6Dt^jJ1Y{;ba|Hl-PMS_4$33ec!}4uS;14+J%{VWwkYejh=V| z+F^KK55+wo2tSzRi5J2QL``(=a<*9SP#~rJL;ayZyRT731xcXEB$Kq4TUbignqn21 zvzbmCTEao)-%5cfk;y(5Nasl0%_5cCbsi*4NiH{j#$Vu+Yl^TF)$(lPB!_?)B~KU+F?lymwvb%oRJn8WPH5+S*6P6I(+Qfw{~D+H z0f5E_bIJ$hWGqHp3U+EOuwc&+LP8cPEpYKcQFBIoXMxquDYjcwu;(#noxeZ zDs+Yv;LP3iVmh4Wy^OZtK!4s+pjlyRnhF!_;%Tm}8EeZ7YCI{+Ol9X4cn%_gZx=aM zMv4_}A&k(d_<2I{uE-iT&$@YGclD!1_Y}7EB1OXvy9?WToZ-+wb$J*+I09GD2@;g% zyz{baF21`n1VYf$82#D4tTTM+&TBdTfdP0M99Z{%PpB_FZj6R>K8|Y>n9r0ouF9e= z;iW~dWlygIt@kK6aug<%dUs&Ee{9UX8ji)0+6j?DB`!$Iy2kmiM>j9^eQ2o zzX@4kyB&WUw?3MkeA{kbihe5}JHuzb8jkQ8CWI9`6vH4NzaC%odjaioMK6WhV9EC_ zN?=~G(^RnX)t{g(Ij+nq#J3QG-CH5PSs&TzL52Jt<+q?BVLF&_;A@<#c1R0ykIsZW7$#l3+FD8 zDz-5`bX&nhXf)vo=s+m9_MC9ShP?eBJHZ%#ITD%oqha3A9p>sQp>D=Qu+4yPXju!#FOuya>p1P{CWxs~6o}dsfCC1l( z0reB}A<^Qmv+*WnwD;~#g{zH?x{$5UhIhrE-xCZ3T#GvV_F>`*!NSI~1^B$6;y!Xg z**-wQ*+huv2o-Y84{d6$(^_OUKDG4#YBFA$OJNkAg3ZHYgder!^Wdk8v$Uv|_~MMH zV{wJpc+8yWi-gwi4x%GyRIvRy=n8SWG|{v{A2 zyf%S&|;%XI@w^n=A#rBaR_IvOf+?O2h|m7_=T+s9*k z1Pb{FAD%Ei24U=+!>NV-+%Wf@vJ|(5IkI%s^=HdiF6(^P2@KO3yI2anQghvfuH;h=!+SP9P zNO*_Id=uinE9zYHs3bDbEMUAQuzN;crna<( zr5ZGk2HBmd?@gsHphd0NCR6j9zaA$Gac3w;VxCR&n)X^7$IP%c+;%j@E3^CpbDC75 zV?n{lq0R#$=B2n?Quozc?4WsCv4M+i1!OvsSK9L~=*&ymodG+1faBMw22y)B`;A`e z3vD*kCc;UK4Pmr>^SrsmtZUEhEm9{h?n4>FS8#~Sivya!<1QH7));0P{ZS{o!dk@A z`f~(!Rp&z&pXZBJb>4=Tofr`FC$Rn-XeyU_IpcR<%8j^B7ISBZPR+H+;V_!Q;V>S5 z8DbD4?3s1uoI>;nJz@u*t|7u^wc6tJ@CS3y05*<<^%wh!?aYhd_Y$0rG-Kjw`IR5J^X1Dl_&-L$p+3Gxnoh)0(ovE zPyHqeemHtnMjk-0nXeHVsrqHp_qs=49M zP*HzRy3|t&lXF;h!pY}IcnOA~l&%F0O*Dx~tBvtzznU6gX@&SEfHDD;e&`0SgFkNO znO`SZ{C5%S&^O~^vQ`SVpDQZ<22uOb4M-4o9f8pAItk8i@{gN*{On_lgx4qNztAM0 zT(oXjeAd$Ta3-a|n#tykR@rQ~TXfE?8<-kY?Hyg5EC~y4W^gk}FrkPMKSw+@Ref=) z3$Wm2?w-HZ2J>?T^EZLHHkLp-8+6fnfa?mjD@!i=BZyiVOvsbiSR@R?G^v*)GWmx< zg*)evHF|Z`pzzev^a8SD^nem7qkDP>q8C7JTBn8fnDTytF+Fi36Irc`bMHfotJ$Fe z?v8aC%M3XpUkaQx|qBU@TYmOrAcYb?J@oMo}LbN<3KHzsFfB%w^XwoIyXm^}Np zh_FxUI%gO|n2{pKES_Xq;pc9gD*L>_G zf)seOpMZze)t3L)f0!c1U#KQ8DSNl#-388FHq`F}7A67RK48$hi;{@llaKkyM^Ez6 zm3&0W$K2$jH~H8l`4~z*mLwm|Dtw*GhK7@G48bf~Ud{jK(dh?3k4zGxEG}f} z-)C-a!RX@L!qEuN=%VT&xuMGF^4!pZ(cN-GL!%?rJ@o_|mk;d`@zNUZZhC1AcPM&~ zxs`|)*6`1bcwr5fiwaaJn?| zU-Ue6#wG_dw`fG4B+!{aP`FYoAn_UQb7%!`*jV7uN-L5L zG9_8q4Aymhdhy1B2b;kvLyy*2@FF~zcPQh~?rq=8+P-&f`^L((2|%$~r0(abU_@!< zEaqVj`&eS3zW!aBi3=8-w4%Eiu2-$?idaL%`9ehkSr1XkcRR#gZQ&8$2_DaD&)naZ zXnxywJL2Q^48yJ@bz*co8WYJ48r#puUE8ET6W|~j%?i0{)<~YiK$`iw^Y%J%p7hza zKil)&jjQ^Gx)~xG5~3|$C*ySmhq20Nn&`4ippq_MOzF;KO)$(!$;OwhLg@Myz;opP z9u1_3w=})Jbfz>{ccckY&!n6~n{DCVA+r#56x-gEBqn+cS*oiAHSbR_BFa!d%V9siSbgkrpdrXv^s3vYryBRD?{7OKcz6y-*v&nJ7CW|GqqhVr`w2#ALQTok+0P9_f#jeDbmhppSO-2NDZMz2HeDxk9_N=4VpXt^km3BW*1k$^H-fHbJ5^WCJj6<8{BHokP`40m zl3;i7a5EfnN-1sg$&$KI(%F;SUYWQA5?;oIZ2 zuDwInj!pw-C2IZ>kBWA{(DEpPyL}XdpTWtkV5a5V!a@$8Id)BE(WSBg(Up7qX}##m z>!m+Jmpe-q*9zAunK-NW@-|@Epr)C^*sg5UwuPNc96z3J(=FZZ12%6sh`BV)^N~zS z`}*A90S$Zn#B+#+faP^NxZLTKtEYo16svyNm~%9nwL6ey1MdOQ$s3rCvwqL4ELXdu zwns>6t6Y>$*%hPH=xdj4%$e0EtGeLo@w-s5jZd;{9nq$G6Rwg$E&QndBU>lL zt0O5#2m4X}QEF!LIU^=Q%qY2ng@jAHIEY4-mOb5T$s67O8p{}8hleRqbI*F<+90?Rt6`bJ znDsA84h`n|?x7V{8w%qX>&mW5H?Y5%alnNKd|kyCN)%18GW1uOvYmdi$~4nV=8|1~ zQHy*LJ{#tIt|VobeVMD!3~|&F1!LhQ(0RXCvRaTjma>ml*(Q2E8+D!W%6ToWQPX!WQNr>qyLi(qG=W@|wTAG#0*rLG9-`JJ^E1Q36#$YiYKf*Ug0!D0H;93tBFcj5Z z0@KlNp^&beNiLF9*t|hg-Ez&?ZII^|+1lqqGGD*+iN`eQvKS7I^4?Nmlv77Ma3<5U zv-}-GT^#*(eV`M^w8b}F(kQqT7KV6rMZs!p8~>&H&7F{23!=E>xtyV(4vRnjUXb>>Mk+L9K_9Al&TWDoqKmaReBc{n?zr_`lJTdphQeln9X=5jytv zd~OzXs=IyMM(5ABn1Je4u7@%;$>QOl+)gc3zf8o$zoA1C;l zG^;!O-A%qmkgRM6M+b64i$>?>h8B(%b3;o;v#e*EXU)2oYN9lq7E zWU&wH-+2%$Hd5&;&RO*fdrVV(oZK%iI~L5lneUFG5y`gyDrtg%N3Wm>-Z`n|q}ych z3dvl2-k-DSiIpW5DN1K1ZtE!o5ib5DRn+?ZHLG@g>BYLC6b!hlO6?+hbzFRf8Fmw(W4U4U2gw_rzrP@eb|W5QFhmu@T~1!du8%!cp{wQpH-E#V*C6cX zuga|mni1+;Q|!KU*v`03C;?{x=Hs}n!VKn&z2o{+U>^S&7D>f0b0LUY)c6P}+P%gGc)U93c6Y-)EprFpk~tSmTroyb>k=}+u!syj7|3w&%mV6MmH z>q%PjyvCt;x8&DrC?^aC5E#o5BE7fe$fbUd4*hAgA-$qLu(FqnA~CqqaI3OM{1oUL zYpu|RcTZsoXwZp)*6vRIuI}j$IZD}HTVCnv3mqgfb7;!A0>^ITNSCrBRBwhnq{q@0 zNiBYCIRZsLcP-X>vs}=bi~pej*kl418o?f5+0GvteEUmQhKc`r!Y`W=CoRTmOmXX}ysJp8NhFjUq2;!17-qk%qlL4*Ruon~P==;Kv zZa^3)vA(qqx%~9zI987|Mst) zVNG|f-korFiCT9EQiVj0?WJnC8~Ky}GyJW-pTIn?{N@KobNK~pQ6rHpWi|@>A6%_(m9gF3J&D@6=SHMVbUk_k$*Sy1>}2{9G1c!` z%`zmFUuY1VV?|pWcUbIq3SNw8T*m#7lmNul@&B>*CjfF5#UD35d7hbP&OK&#GP5~n zL)g&l%q%1el7t%t6j6za5|BegK@=X`NkFsNHFygFJU|fz74bqv@ILXx14QuxML@n^JuJRHx_h_cZ<<#h=*F zTFzwcS|K5j;FWFEK16&n3AxsXd}A&IpIqrmO)^JIb3-uupNF27=W@{{(V`DyQ+ORJblwHL1xR^)cb!{c?|Tw2ARO|22f{W*S_4M=RIZ%e5H?`X4l4DzI52nHvue(f@aygXdPgBbO`pc81 z^QW|ptky8S>!qcHTG`25T;Fr!$o>#d$i^)GoaRZ=4>tDg^bPF$xO|h zT}b9^3b!?u-xoYpJZ|#?@KuxL#m_=-YP7gnyjFD9*-`wSO`%_#y%^xV^Kmk{sNs75 zwC3o1ACkNauT}g>1fe)iL-`fN?*ttd{C!LMK>zsP42!iF>(5Vb*rkTuU;K z)0N%5Rgj9wvr&26>qT2Eh{QI$C11}wjjyrYy?NtO5(N|c;{KHv?K}NWRF+%XiApZ3 z6-MOVPa9!r>i3~P#vih+Rn-rn-Mh}@jLe8d{BtQ@8_A@PR)g31iZhgJlPkS9Rw{)F z$qJ0Enz(k7TZLvmJ$o{eUJMb;+b{bi$q$eSdsfE=#}hOW+UM^Y0WN{vAH|$Pd8(&~ zTXy*4-n^c(3g>~IH-z^zv>g2WK0@h@_OKiv5iSmtGu|u_nIFH8B<)GSo(Bx)$nk&Z z_7aABfy3==p${MP{{)!dfTZ(9j06Jr5HYQLxg-@46q`ojIs-g-b-8h#-|Mk!+<0V; zz|K-gPtAJz>%8kJAChu><=&k5hGSY!!-v^_|RU>k1h+QxnAJ$_x=aw<;SCz^4BH=AlCQ^>!;2^>CL-0WgBfJdq?i& z-6iiR2Xs@G-L@Gvp8ikymhGDFWt4ZS>T0Eo?DKqYCaGO{k=sEFjZ+w(xTeC-VlW%f zQt?6Rz(?oeqqsgqV;y5iE)_VS8&GxMBgFK4-{)n~TaN`*f9t7cy{S*5{^~%H{4Opr% z;i4{Fo&ipn-7rp=7-mV{qGuI`V@SfpC;I{_@Ir;EAZt<>}a`2YE1{jrJ<4+5W4kn|7!eA0`Uf1+)zV?K<&l* zM|o=BN**0CwZ_~^nHr;Ecw7|!icn}n{7$?!Nvpln{IpTKL>MUrH%i@3+S5I)NS^Lb zj;N;uylBThN|b4FXbz+5>aD$>?n2F8*dcWSCHXL4)H<%ixqy}QhU|>Z3l$FhAe5}Z zJ`LL?+!ANWPm)_n()tb?++wYmj|&8r8p9o!Hv+Siw+7EPSE#nRpv!J>uM>k$lH?YxtGayOTg`VjL}o z=}ro}id-qO>EvEzi%3cs+u#!GJ`3Ersqxlos?6#S@OP8c@aYTd5DDxdvpn}P1EqAWOA(atO`W~LFzo7XV6YTY}1CxE+h?tHyec)36?MP8oIOV6AWXuqC% zrto%;C8`kN@Ev{^$Ln>vEOgZMj?Kdl2s z`J3Qx?F0Ns$UMT)*2UvX#+QyS8(%(N&&$(Ly~u)9^0IZGB^4_7Km{3>!R)Y z;CQg^ErfVYz`85!RjL4vo~st6T(T3;%31Z$Iz_lJFhn zuc5z#vFWW3jia|kvsqs_UPsN3OQezU`l9jrV)pIAwOOk#>AaTeOULWW#_Lq5&b6PO z@0HYv&_U>D2)v)>T}%z+@OvF@))xZc~6 zTvl`d?A_)!xV3M}e51@%siy3KkoOJw0I5Yra+}?{#a}!uXlepGBFV? z-FRd~^L6%|8V&l>w?=(y&(;JEm?q$)H@%+2TUX7G7G zm-p7MaH@YPiR(pn~JF=xoAsU%ju0|Ex zQ3HxSE>Hf%ZW>ENyDqC{jv0~v`_Co*bC=yZI`njE8~OBa@g?lG7mQV>j$!`6{rc4D z_8hSZ4ZrnMZ{tA0wcDgVn)MQ*A4%$yVIJKk(O44rV+BfquuamjB=CL(MoK9GSrYgY z1xoO>O)@g$D=Wam)mKbgr$@-H0l}UBb{hVSGyx>+Zm$q}889hVD`gyxRD!*!E!J zBQx>0>yepxhaMbjN3y{)GlL)_9c)FK#E~y1^d;laW+wF%aL~W0-{n&0b?(0jrUhy{ zOhngx1=E7aRRMv!mcq7Q0}(^5!L&-?J{%4c&IRLxQ3YP>9)awE3d)z=DZU7fcnEB0 zzmxb*64=mw6RQpm`wC`gzeyO@^8y&!ZxS{XOsh7b{n||~Ogm=mb+uY!jm*CErg;LJ zvKy#}*_7$UB1ryq57%Si%k@w_mS#X^lBl_#PJd~ie~xIy%5QRpNZ7<5fY{V`uY_=0 z3+D$`?Tj$RYOVSIM}Ewafl7W!dsRnCd-asR6Up%O5Bo50G}fP!omjrV;NGn?cK;Od zS3_eR8!`=g>*Cl0U(Jr+Ks-461@%fBQd|2H&1-5(9MxT*A`E;58T^<)>doJIUJ>nK0<)T zS;>~G!m+21`t$0gLVwYH$dXxIw5-*?PCwy*he+Q^?o*v~*%Xtr{R`@&p}J3SXn)`A zw10l*_P>z^r2SFCTl=%{HLmbMdqy)KvS)UN!=TpAO0M=+dOek1Po>vW>Gibq>W@mN zKZ>dA6Wr*J4}nKiIazrZ-^YZ{`9b}hkZCvVCbOxA2AajDeJt2oD)r3M)ic-A z83qsUd<9JNeA6V2VHhFm7Dj_aho zYTri%wy=I+{6P!n!YjpZRx)wWY9V%hX_hZ$JNmn$DN|Tx6q4jj9tAd*LHipQlY+4{ z?%RuoFplMZ?i=G1pr_9Iq&+h;I3lyoQn)%z;d)wl($7gde%i96XKq%K)7596^DyT{ zkXPS=VF}j+TR+RU&CMFy{``qZK5(d^3QWYG5#aQUlF?mgybQz7+cPus1$#y_x7af~ z^F@2+X1-+4{LGi_S(y2XJ&QA6wP$JOR(tl%+{RPbd`(ZRUT5qDMa}QQK0auWcEoB$ zA3U9mG~tt)ceLH-R3&SxmgK*txxXjPM&O(WoX`u>(R=(=g@hf^ z$y~sf5ps-74thNd5)Qhs8HBn;<8S0BW|4-6^&}D-sfUutOr- z6;c=xm38Q09`SVvQO;U^r1gg+($&9t}Rn;D6?Z|0DD2#*sA z21jdvw&3)SG7HbU1dmJm5_pR;EU)_03A}U%!hC1V$=9l&{(Lu*)Y0F0W%_`6)5(QA z+NP!6K4fGPha5Ha1OlaaKjQpZT>!km0}!q334T8R77N7rVZGIX#5O=$NtqE=`41X& z?4#sr(8!JJnS{q;)3Mn_Gs1w_&|N|o8Wi82Ioqsav9VKMaQQZ83UQ?38p;VS^83Q} zNWMGDVZ9Mw3ZUwmbHdr%83i!|8bw3(s{V}cL&@uWS~`K##U%g9>f zSH0qOMfdsV(-@hQp zIA8d>qjB;;qrHlfxe13|121XUq)6RBCd<^<5K;=VHSM1Ef+F&!7Rb4uA?_ghwaSTc zQ%_DacOfrgqxqRkxJ{nR$y0IPfuz?xM9W3-6$F^41uX1%ZG};Tz545UH3WyV?nPzdA-RfF+}(nMnjFICH}Vy~i637#Q>o})m)5zU*-daY z2`+uMzH2A=EIwo-3W9E;8$i2SE?Q?{;8YkY`R)Q*6U(YOYrt|rek0PZMPpi7YLa|y z<)6eJ)YO>@Kb#NTpG&#~7*um>)&FAqd zE1iM+kVJaWUsgJe)blC3KeJ=uNQh56X1LWr#6KHjKk_8cJ-g67D$|Ht&$x?Q+yFPZ z?0WrR4kq^VFY!aL?ABgc7Rg!sbNi9*0S>2YCB_X1uLC?rZXAueo*ir-mmt5H=GRTz zrg?~;O?>|cs_nBVO)N66>Wwn?pl3CIqubF>8EMzzzc~eqiwKS z3}?9luT$jNQS*%cEKCa3)jq&#ZKQsB;X3eaq48KO7?)utXx34Oi&%;u{d!lf-AJJMz}-4orW7^qhizg+bPmGMaQ^% z@nm1H`L8&}p}(}xwPQJ520RHICdu}%FXDMr?Gi+>2%hSVtG9_?j-MMgt7*HeTx<`u zy8ALzLm4X)R>>KU|Ovxa5p$8nTYaR}daoL%AQakk#i(~ZdQ8MykdPh7PA%=HF}t4ufO{8kC+r^Q8&mVtvEVrao*DN&I!7nW za7p`pUIT9|nyI;uE|xt#?D7FYXl30Zdc9GqU2=pGR(LID&i-gx%|jmEcOZ2%aAyrJ zmXp|Gg_!AjIYOm6`vc&I@jdqYBdR^SA(u+`XDjVKu&z|vj|abEx|u`Ec)DJ(V+r@| zHzO**cK62}@df+e!t}jB+x}(T)4BV2>o4|~+!K5?$;+M@erS1Te@OIM0jF4aR zN>W(|_vfZz$c6Tc4+MxxtYy3$)$e&n1k{BDd#eK~9*Lc6WI%qcfs?bh$sp!*96rcP0t z{FS#Y!2Fvszs>YK1_vKj`|P2S@AIpElH)weC`fy~Pcc(?UKhB(lbP#f=!(Go!`{EG zSocKfAEwoUNKt(Q{*!1=-N^1rwx2MX{6E7({1CVvC?2n461?z9W|aDWK#9pnbueDE z8|*yXLw8f(&}lqBTzxCm-2l@T;dq*dz8y%t2bkN$7mYP@3MKv*jlxpYa|8W)b264! zVhy4F?pVOGghh#P2KE2liPi13S}6Z-UPI4odI5KcshNNKZGrLq>Gd z>2FU89H130I~VnET{Mp*!-N|DKcw%_xVL63@gSboUOJ(zc9XGnW!xIb@5jgB%NL3s zd{>Bz>rx9$@TB~Xx*q*p6+eUMgl~iK@9CjFc z`c?Yq$$P-aDlG7tPt~=uB+zO;{_P6lbvONuu!H77@~<8OjF{gj24!!zig8+74=IZ? zD$ZZn67k9*Prp1n%C}P752;Sy3pV3Zp{_L%$@;(_6Bx!>G9`O+&7b05OVCAP$B=rF zXqY+S{O+6(y5-gi!MMwlFBufYC~G6f)rnkH!!2s)MtO~kq!~`Hy$zV0y(sC6dbXBK zy$FZ~HotwP4hFn~vFc|XD%(f8)~I{s;oQ8k+l0o7aRV6lld?JLUi#ltdiL6!Aj5qu zPvWmr81P^A-*XB60Pt5~#}Ge2KAQE^k~UFPC4{op@6Ey<=XY#|2*DVka8DEuk|Qav zlCP~EbT3ya)_{gJ>%>7iq=J;^t^_dWQ?)O{-K<+8c@bB0woc>@Vv)>`pblLk%SLH2-^~^7Kl2)_ zobKs5tDAep|41N%KxzLG=9`L>!C4+NR@FiV-!9va2Jc^eBh~A8BZ5c1(%Y#uK^sDjPx>I_& z!F|RJhJY$Qto`@+xxw^35EB0Wt>N&y%sS7%vrV(G(0cjSA zPoj-qme6vgzq8&9wdvO#5Uxr}JoOtAVO&$b&c_HJ-2J?UTa#W0iYA~&M3OZDHS)AO zd&0L5ibcPldf8bT&-(u(7QF~4W7`xXQFBB1-YjTur;%WQ+HxOJo5*(z%xtZWAzKQiH*5Z3 z*8Es?3}oX^8C^zhMg&)pWLTsZ#;cSGcO?2+<>^p#IjdyzbQE)RKtFg1y01ef^$g0p zNOhRLTV(uXw--S1%;jDHl%V~^N3em6W^bHNAUi}Lj)Y^|6cg_OfmGbPpnMjd(y#OtVDs@_xghoWt4aNHtnM??r z)a@kkwD~rP982k3YrVtz*j7I~s>n?im{XuiMb^#JYyr!8E^}!gK$7-tbmqeL_i6F= z27VgDonDXE679Qn1Acd{j_Kp#b%bs(XZhNr$Lsl&mw*F#x)k!AO}JDJB$CpGtyy91 zt(n$Ovs#Ioq5~hR+RDcVDYxwL?xgQ7Q9HYf=nvZKWb2kzcJ{NhL8Fw7UqL|NZX2@+ zZpY(U?8(OP1H>k`blEG!qquR0)UMFyP|2{m;{1jJK7<5g z+Z5wiNH^Rnb?{K&UZsAB8Y@_LzS_D(*TPR<%`E`&T1r3}f*|z6#E{@}9<4iB?yM&! zA9Ju)%zj!Tiuh1fmmwN-`IKn(Qlqc=t;Bjgnte6CO*Z2wjBIg9L`dh(h3*7w(GBzhe_eh?#jvmRg zA>6bCTyp%=DG^pT*=F%xIdk;BEXOsDsz}Z|T;IQ@&a+s#|38kyjbbSejZa5kFPj z8zHADAwqXKA;}E_MFz{M%jtNDrOnfAmI6L93WQYGlTiF95SDPx+Yg!_Cc8JFeLo5= z?YdqE#AMg?!;GNg@UU*Wix%zoc6^A@6L@`O_HkazFC8InQ%w4y=2eMtgB-Zu+Di{+Wm{*sY8EyLG|MNEic`Tul<^oUE8~;`Hq;)mgR{+j+&5_cQf~B_>QQk%i#?|R{_X7Zj?c%FF5WvqF8r&^6@v;suVzYi~F5p6frT||8 zU`}_u8FaRz5?SKjOy4xNRQj^PRAEW#yv1q9c0RJ;G7{0Sc}g~(gc62Jjpk6v?Wfm1 z-x%e--4xcB6h_+pN!z-O#_OMJAZBogjjM|aS{q0o_yqco`IzOA+$zs}TKz4@g2VXI z_XXQof==07>a28JyjSi=*ZEe^AG1peh6krN018hN+47*`+E3&&eiA>8r|>;k9$?mC zrsX!%a(}#;X|*{PjlO$;R_otQMf#J9aNksUz`JQi{o8Lymj}#8eNxBur?GiNlRK>X zp2Mv5WL2q*D7fs7=XGrQDGC@Go4!p`=kWAX^;szomxs#oA8I)5RUURPUX_YQpUz1U zX!sy1iPQ2jZu|4VrRZVrN3rZqAbaa=Yrg|!CQ2&halc|+cIanBuGx4aNvenFSW7uO z`vID?XDfp5mZ*Iq3C6Z5Mutm`;f3XevmczFZh_LBWa$*+8cJ6kTIfE)tTbF}Jbnnh zi(W@YxvHUSY*HRUEm_W0<37;7w!E-hH9kMQC@L>1k61$wFCJR#ZwRWkSAunn7N!8S zkMn4~d#(X#A8SBsFyG=y?H}kg_dt}J7RmTlYMh;Ko#_M2>3DnzgcM&YYFg45FE5EN z)9cdm()d-p)R#{5C$FRM&lEC$K7|V@C2DEij+|u)B7wwWzgyPRXqCz^*Wma*KQ!N} zMx(DBP8gWKIb!YaY5i!l%BalmN?!Sdy4K#RKFW25SffMc%gW1Y@mZqLk!TeE<*D+r zIUv4(&ItQjf<|ri1?AjqxQI2z$>3KnyVKzUIDu)>aqe(?pZ(DMJ`U8!r&u2=#F?!$kgmqjwKU};I|4Rx+&#k%T z!cW3~?!n>A;TRhQG{Zkbe6aIe4UZ`C)IWvmeG0}p%O7oQ|8(}^Al@#Ar-$*=DYMX6 z9>u5gVzLynNKsRw*&VIgWJ86 zi^Dy!KJ4VacVp%Q=DEVU6z0NdQpeW4V~soF&qW9IQ+q=Z4&&sN(awpopF?O-`w3i( zgnf;>34WFv3ehU=J4EN#^YL56&+Y8pp#Mm4Fr9jGJ}^xE0i4m!(iT%9nj8zXXV4bx z(S){nL&9_!4{Q@l6KI^?AcCsJC>kZzu2)ATDjWpBWkOAvdGZf zHWF{OEW5(0&K;hRoynItMZhhsopglgT!9^K=1{x5wKXx`k)t|ab-b}4UP=&I9M(%- z4rFVj4{41=Tc{r&%M%s4$&xF~ZC=uwMxwSy_bZ%IjQa*Nb0KZv_MV($4jdbfC}MW1 z#wYd(vSbuGXTvcr*{Zwih?nf>o1AO)<%X%v#G~9VXDS;g%$)FUzaCPiGyaSLCe{pp z;ZejVWwyCI8~>D6!rUP~gZ{!-RCa^g4ltjiCo>N3tu(cmeAse+sfn_|a);!~`5adF zwCU}B3XYN=uJ6`1UE8NP^+bIRa3qQSq%HC@Qew(%$6M{By-}CiFf=>6UEzdwQ`=k? zZ_=f;=o2ab4QlhLmy~GN+kCrn-paohGgDZq`1UTzV|k&^JLDOe7>u%JkTt}GiqB+H z80Y)rv>NNjGxWK*{Q#!HTOJ>5MT3Gp9Q-MapGBLk^6j2ZolMzRCH=jrTjyS3_BaY-;qYIVe4$NgtcJn zuY}k8AqWgQtHIU>yPwu48M}Y=jo`;t>e&LEIgX*XGH|Do#SX`xP3R?mK$K9-Am>?4 z4drw)i?r-2R)Hm4XT;ATiCu7wYl!GFrFA!|MD^7^l=CKopKgcfieM|}ki3{VZs**Y zY~EqG(#TK#BpN>vd?aS9x*LELRw^-+Y+DdXh}_;p>E59*wGH@J3;y(vsak6&*s5py zT*|1pNx-oUQi!+>a>}RBh&~`R@p}`on$+^z>9Hvd+c6oPY3F^i_&fr9bBM^*8k2}8 zp2zdPLKdE#T$$u~_R7=~H+!Ca2>#*Px3gYKyAP`^q(^!R69)<|aQ!YAt$QS&VYA3_ zQGl)6pRY=RtCg4)u%c`e2Bu0FZ{oeUw#aHA8*k>l#GQM8Wwi=E=kwW@pFWUzlC$(& zmRn9Ac0WymAjzOg+>)O@SkW1*%@CxV#>jRTkgc^QKYb7pqucl3lyY|TNp)u9%;=MO zaM7N;%As|5J_(bh!^ME|=&jqvD}}#+Nb~WwMc@jEO5%fQ%f=Z!fG3~ovCEhcV<_Az zTnve7jAac@-?$y-1K?Dt#rx4+cKymqOe5o?=wpi=B$nf!FQFOn&;i$-rnpsEuOoR7 zS8Uc1*+lKM?$;n!aX)8w*8aK{<%lY`3enQqcMI*3o6%Pveifd}gkLVQW4McS!SwHF zYiXscjhve$4H|=1pRaKo=mfws%0=s*_=SSd-#Cbs_cpz9;qqMOEIWV;32hDdysXP# z#3vh$B=?K?y01oFTh4uwPmf?@5k^Q|> z_z3IQ)?)P6$SU)h}_-&kbxilq1~Y8E!o<)z~3|}AgRUg@5`yOn5^of9%{eX;v_gy$yuLbf+8 z`zHjVJxb*JA#F*rZl;bw{6?0s5g2%*`Mg1v8(~ zgJU3{1LVCHkgBoc}5Qhc*fjkYSx_#l2cOIoVmDGA6!Fb^E! zEAD%IuWFo;q!f8@N)>h?^5~1US{kvhXj*vKp2)W%o*uqTskPca@YOeXKPleKk<^wk!A37^d;aMxVbovw7^d=j?o zl#AswJg>0~ZzPxLHRo%=Rv1%t0{pfy>t4-!>+S^6_0r^qczFzK*2L^%knhe_-?0`+ znj>lLmxE<|00ftO%M^3nOQFwXbA5bgbG=VHA>(^#9JiJn&8K_FqaRtJQ_{xg>F$yy@>)BoPG^;Pm>!#w%)d0eJ z*8~;chr{`y!j6U9ceSKksFd>#;X_o55vVf9Y97|=#g-mL?(NcK+kzCYQ0vUmO*k^a zrSNLV<}o%*l9trWDMO-6`*mdS%pVi$QZ=E=uZXs+(FyYcjFR7xZzremlF-g*zKyXG zdR_Dnp-?zS{CXfZ4}hs%$xE@ZCw%V>yiH%l&-TYrol>Tm%jDuW@(l}&kwnTH+ne}o zecP`E3kLf-@t3sFTpG+?O*Dq3m5RTPEE8Wtz$OGua1Gr+m2pRGU@Q`!vD>KBZjn3F z!orMSSU?lvfk*O0XrlGMnB;>xHWsrUD)&r8?(!qVo{rov8}s8udonJJh$PGs9jr4$&)B3SrZQ ze5m>Rl5T0`^6mZjZuEso|Fqi-E=Jc21(wu*S5LS4xoY+|Okg}<#c2IBt94BBB%qRR z#I0i}7c-lTIvr4Ok_v*?{N6;Uow*2{`Xv>34^QE&=yAPf0(#z*9zw~Sd6)|7nO zq*%8eY*%?$9jp$tplN{*rUlm|^W*2&ceF>Dy2gT;uQI^L!kOFjNYC8P!_Tp3FjMaW z@Alp{XQpSqK@?Nx9Xtjyw){3~DeBY$6K6l%=%}pc#nH4S-Vu#!dVD)I@$;Gm_h)P# z>tj;0RMUd!Zl^{2kb#SDB;c7Z@|rIMc^_trxzv>%k{=f;VJ_Gcr07I#x}1+Ry?r*{UKJA4C~yr@qu%>ECx7 zZO#IZWy;49c8s;kt0I2}Bzc+X@kLxHy!rcES%uk1g3gydOln{ z%=Ty6H$&*9#(upCuLnpg9BE*kCc|UPEp3mGV+W^PUsNvqc5_xa4U@(%%zMa`!x;b% z4jtukjOF*~9lv6uncFOwxUbkI*J1=D4S2Wki~r{xE^@eyd@}hxTViXR&6P zcM2#Me}n|AH>N%&$;wChxZ{if<3{G8Li=Ni^QVJw|C6J@FH_sbvtTW!p}EUVf1Cul z_!Im>a-ZZOn^vR4z92`cY%T9syh2t}WVSV!cb`(iT#(DV?@}3RHl%(O#Zni$`ROzv zUt=$xNy$6ld)3#|lH9D@&L_(0Pm{P-ZQsm;&9`DqcI^(Kuj9`WT5L>aR=Q8%$w4-?>X$d^sI|kqEz6ZQU|&qgsn^QSSIl{9?(X_vx?j8-JCb zLQF6s`KPmK@8$VEaJH6UZ-6U=$lXfnAe_EU4^Q1PYBGDTnmZJ{XFm*s=~1$0MugQO^e4zUkP^7Oc}XbnT=f<6uFm37q!}j@Mz!IAQZY{Kb4MERJVB zjqjjZawaAL^|$npj+RYd>PGVQtg6(nvmcq?sA)B74yH7=O)+k`AAotji)(*G$s9A} zebXowGx*v1Ce<^!i6k3+xIXLsMvRkBn{}P^t87*93$NGza%KM#) z$RVo9P2a_<;~YTL+#?r%s~4pE9#N$DzEa%HPwNSp(YK-l%Gp|>qm#{dPVB8NXJ&t( zENREC0^e-ALTlec{BS-*8gnmii7;lNWEGN%CBhi`(96ZvrT*AhkkD~Dbpp8Gq`olc zuv|%YA0S3fl*iU8C&1+~cI2dDgG0X~C&nl63vl*8W^?wc z%Q>=ZZq+%#bV~MTh?SBuMo!|K;EzZs$3*)Cxt-w>Fb^(M@weh1livG8T623gzMn6S zXRBSP7PJ|p9?A2AMpIfU&dEadN@O8AiS{5(kTWBEGnJPQq@Mtyx|(HqM@DjoKMrnZ zJtP`=GSE8K7VgI~K4IcAxu+dWL-wFq!=%3My-JIvkuWg1iW#nVEvAWireY)^cF)oq zHkq3k4}p7X=L;|9fjgm-|Fk67oy&{6Tcrc!i3$Y^O>OR%3RDrV>ZFyqoA3NXGC;N?G?L=sl6Qt2Eqd*Tyy&XW_S!u zK&6*;oLV7)hAzO7?mXGu>?1LMtWqj=)Of-uiog-aD&fE&Ia3l_Ahzg5?Xbw{dyW`2-@Q#XQEEVQy07 znky=io&L_G*>3BU_+@HD&QZF5fu^TfaLvdER0{h7^hcMgkM5wNW5@*lLMl`?zo&SM z@Wy%k-QS2TVEUSrj2GW60}G%^mF*s) z)rKQ1WN^O2*c#3LFr0%DHa@u~~KPkd5O~Uw8f;AUN(UP9`wGjrk6O2d0 zQqm^jmEjbeP7nisl9u*?-Gvoj~}N&nnydT`HikVg8uCFveqSd7r#T-n8jfPH}G z@RyMOjKQ?$wlQ_&f@Ho*-Tm_knpb;bM2sx>x?0i&VA6(jjyQ^ES9Z zH#(e&CfW}DajS&i0enYWTGh|n8+-zIv!9$ln)4dXJ5+&fiYd%~YJPk{@$eVo6;lj3 zH=k|e0l6?f+fkVYtJoXc5~0#wK#bR$iob`c?^2IXQtnVHoVgnSQ&-Y3UU+SyX7E0Q z8YD7-&5V_1ed@^rN@G$2g-GEV0C#>`$*!AYQ&;wN(<+38)sE_8I|lIcbG(8RYd}9@ zxSK;EyFecVAGql#Qmy9FsX=g=`UFU4w-d6&y$b?JzNL_4ymf%xGapz!9wd?uSg@3RV`~4@v#;^0%mA+-?pOX@ zbU#Bo-K=(+{yn3tb#Aa#Pgf>)>*=J}qmvc~X5@3mxP>XDWfCFfv{kp_ z9;2S}=;3loZMnWH1O5xi_}r>z=qg06>WTfcV)r1iy=ag1brAThr^SUNHowQyenRHU?O!S)yw@({}#SXRmoM*eW7khi74@#;S*LxhDLKtO|+PmXhB!*Z_u7bXhO9(}kZl_W*d zN|&iI%DC!z9L>RLO8031=i?A%PCoWSM-7+t{g6(fzSNypWwXmd&{f9-(T&oP^6xlx zGyK_h1a7HalaQ{!OPQf%^sEhF&#RoJ@QVjYyP$N9`rR zD}+(vrdV&8_)QoqGOa!(+{BI`2uFOi4qr%?`{*+sn5R}u)Co1K1eQ;uN zV_7|4sBy}XM`I6u>cwJX@zO%0S|2Dh${yPG_euD=mMKXtk=e^I1FYQ$3K#^jTky&@ z3E>lrmxIu{b;KiLlIk!ztm!{$tVD8$)%{16kEIjCnRNs9oiRU6>jFNar3Z>R=q4?$ z*&Ud8;o3Web!1vc%`LGskFxa{VUo$Q2Tj){$I8Y}Cp?_4Q~qHX+F^y9J?ti)NuwO5 zHX_vsCAWrnS)>sjbK*ky^Y@#;35hzLUN(J|05wZO`ShR24d^26?!{Ze$Q8H#ZzW$Ba zC*>2GyAj;JVEl3@RdbV2g|!E>4Wdfab$bGlJvhQ zNualY9@GoQra`yf@82*_K6}X}sOs>xg&()<_GPqZ8{?(IbruL)s&VS0igDUDpnhxT z_>po{;{^WM0O-lJh|v7bfr|;u?Gz|Cj1B2+7r~0lxUgBJVX8I6A(VE@+#E0g`ZmYa zj|xV=NSqD-k?Qt^9ef>c4XNJ+3fo14r16gXangTjcd(9D`X{hZu=9S(*g@f1+fc0m z8|m+)re11PWquSR`C0f|}S%!@rO8yf5x~U*3IR6VwNLKMw1D2-hf8VFY6< zRt}f%yCO_D&?@jhg1=w$cM5;u@`>};{zNbJ!2@4r&(Q;~vgct3-oSJ1m-xXu-)IqN zqfh5Y6}?^+)e%_iQHhgwYV`Eo#|?3d*R*fCs@zIpbipZ3ZBJb9-g8F0Ta%u*` zdts6RUI$KKAv*xGLkE%a56Q0wBccg9zq4lwo73qopXy&4xyz< zF<0bRhRu^Ix(7J{kZ(T;Bn$zxxb@A*9v65X&>70UACCi%Th)*Cih*ZU;mQEVLRG+{ zoqUoS?Cc!uk{5rN@X&Zwx`$Vt3hdjAMixRXMh{6P3M1imHcOs28j{8OK~XKe{gMvD zY_Fyt>IX-)%uZnrNkpR*)DO(&I?QZ%-z9cu;MXXtT9xe*mP(vAXKd@dxiK-xN3zxG z;!4dDC`J2KEStB0TLr`3;q(rx0Ye_?A)#tvH5mj-jEfI5rbAUVzC zlO%_+bluG9EHSV%F`Fkl!`O5_jUBl9FOZ}=mQH;GW#3Ny+sj$|qW_)w0s@XGJ@Z8# zfofaDoN>U8bp@8PZynCOPKy>4dN)NY_vY&~-#WqgA+rjKe^sudczBbDMDsZiuSeE)9D-(d7o zmhi>K5E9*&@x}lzGuIx<3`WSy32FVzu3GJ8cWB@WYi^=5W%JKfP^mlAmtGEmc~e&o z(OkfsfTLLH)MAw;iLXj4GzQt^s5Dtqn`nSWLmjMt9xJUIU`*ltO`*_mt1ZF4! zBisMXd_X@ljn_^mVAJ5?;#8P{N{h7qnDvw>*%%Lqsy?hV@n;Sp@sNB0q$!I5B0f&^xChZxH;cXeePg_T0dR;R;4Y)?~t~CKA7h7I^lOAJKd=n zkL@%gK8o#5+}3(LC=Yn4*gj+w;iwb*zIf9ftQI)fI~e~FEj-(Xf#Jb`qrM3?Nl(5< zmZ^jtMny0L!u@jc!O@4CprG}?Waq&9hj>Q@mgR^*a@Hj2Gz~sh4Lx7Jhmp{zC!oK> zVfz|OYPd7$h(r0%xYEBv0-b~KKFOE(vugJJF70uNmz+|&&TrFVp%w_*JY4dff2 zO7de-uiK10u=gr6cgI=&1*uV<-!wiZ(3_9WbuN#-?Zu?i9Qnc!_ZIRLk4)K$7q}MJ zI@kwx@7x=SBPni3sK}2&H;K+e*@x^_b(?YG$Hn`&-38~Kw0reJS)6=G)E=2lllK~9 z0FUY^qG=)jrA;2MHo3bu$HNvB?p)C4dr)evNIq0|dUp}`CoWg-@Ky-AlFuS z7^>qgMJImnt-t*TTl%`{lQ}5nJ;!mnZH_ z!s)YktybgXsGFGz-SkSc%3QU|Oobc|3;u);-p2<|bb`O&gAeq<2P^mx?2T^s!H?26 zi}DlIHyq38($qH%=68Ln$NJ32C^5=EOY{=u@MGX~>iq344V!!FLbPaZzDg6XG1hrD zOid#wQ#Yki1xfb9oMJMUB7A*;$y>|{TRI!QKh8AS`gyHeIO=dI)8^1+x7UqC18jB} zD!?5H2hep59kfyLcOzqzu5%w48_a#YR3Ea-y4SbBlY9$2Q7xe0pZnkweelyd!N2#x zr~BYD6x=Bo4Xwmo9%c057=U6ud?veI=Gp~zhsJm2+7L4WJD&RN(Ny7^9bO?`vzs)} zA&tR!nD}!P-$4VNu^Fpahj#+8mz=A*Z4`>MIQ-%Hpb=uFZpvT&OpcTwoGX5LI z*)n0s``ur2c{a`r(BP7FP7Cv!cWs3q5WWin)taxn6za+t|Aj)vxfqB4HDdqiY3pne zm0tsoQ2#rrzxxgv+d>7``wW#Ala;Fv39&WY<4A*WtjvP*_2NII_@YubRx@GW!doeQ zT&t9xT|A8XxWC^|3 z6C#v@i;PpnLRsGh|Gi1y>jU?05aODdhcpvwO)nn;XaHFEs^g?d)Fq+C#uAX$#g^g` z>N^u!hq#?U2TzpU6?zZMNHE5LaaR`x)n#EzRsri~P5Z2N{R-FHXz6V30K_LS9OLMQ zSK`O`-Q><9`XD*Nu&*T2J-5u~nS1b8n<%Ox~)s&RZ>c^E~}M;CMGUax~E# zKe7Cp+R&|Hx+k>D!sV{s>M=m4>{1~)(w0!Yud$d7nFQ+ACMG_~Ar@KmSDJ0I!Pn`4BwDs6V@cx0?b_%K2c{{i7jJ5AFs94CVgi>QUR3&t1TWz=M1Cym} z-bCRshXQqu&QSV(Hh!KM=@WzaYMM@$+{hwVXK6a~;B}OJ4`u5HgtQgi;EbbO_J}4_ zTCpLQ;3^FhS1T<)c~;H@#T5T+y0*EoKRvn)K&Q6ynY@YmCy&b8C6f+&&4$`5eiVa% zBT2kHQo}*((dLRI9Or?Za8YNyFqsWKg;26;vVIE|sEoJ3?v8`58E;CdeP$o&Cvsxm zvi|V0wZMFL^rjC}2hcP_%rn)E%5tR;qH6PAAjc4@ME z1zbz0Sw8V5^}#GALTUFLO7{0aO{q6^L)f2=27kS@71GaL(_H#3ryI3NI~OKy?bt3P zHm#w_R_@i>lyq zsnSOCJgu2a*O#5DA3ipkvP$Yp%;W3<B|C zi?^d}+I^qM<@_$IJn@52;=uGHeaP0_*B;ltMFs)M-}03j|@W5kI2 zYoZeO_xt>W`-kqw6v9|Cmj83V4#=cl46GljJ>0j+*+LZ%a8 zqWGEc2X_nLH+UE|KL?#XA0PH3yW%2aOv8o2d0E|79{;oGukBi}FE?2ate{+zT^WHP zh>BVKhSl~TsSiYlc!|jlY&-3C0qK7<*KQ>*`_)!49Cy!y;0uN~oX#A4q$3WYki9v| zp+kmB*6Q!UC->T_j8Y>Aa8ao?jp8;?JQ1{l9F|Z9DCf|>C-e2K;P7LkWl;)gZHQC> za1ljGcJ~W-R`rkF#{Whk!x{MFX7H%ujq;=+G>;u}%yeFJX*SAqY2=2$Cf>?5 zjJnW}6C@ETdf7a<0^Lqmn~1`Z$+WJt$8QjSxaoDzg#lG{Jj4vnlQ%`2GZ(?4 z#F&mQdDlAI$eL~m+}D&(>zpHKkH0d0up`}^V(q{TvtuES3zlFBGJ63FEIZ9|J}*0> z3JkjaMtI`bHpRGenMW8H4B0Lg_9mN|R{>Z5g20%@MA5C5UG~`shqid`if5cP-5`n| zVh~{C`mc8P!n;|{yr$icWg|A|E;^iTo<*A7B^lI|9@NC3yLf(dVBH?NZ@&UMQ;j)P z$vG2w20-W2{szGsV+&GyfaCq5n?hp|21z6l#}H^SINX}TRp7cmwY&RBt2TQi&z~5r z`PgO-<&%zz=%VrMJhZ^{OU{J=6VvIF8$??;exCLt&^XWiew;4^-cNzo8Qr1dd z*Jb%J7Mgs=kICLLl@32OR%rZWO)ayYpb|!CJc}7g_44tWulJ<9pBerN7qY4^Z7I-b zu=1QK;rvR(84vb*){>6vmzkUc*0n}b5)z#f`WsUE!cA{N+!VC;&;%a%I?2xj1cgl^ z$~@M*4jUN+>DrpsI+iGE-JQtG(sn1V<>x#GBhu!3E0!Mm zvkJB;)n~(imbt|cP;i*+yAX%BxtSbyWWHbc#(qGSGOT4f^z3o`gQ_>G!P5g)WkxXv z9DF-3u(jLIMGJEMX6wuIVTG+=ge`}=fLHZ2|4XMK?J``H^_3?4_5Y$d{I16v?k4MA zym77jkww{#UO&lsal4Ll-4`uRi>;}<0!)g~Jr~x!e=dW?(Dg~o6&52AT_LKj$w$lg z$%N698Jf!{XFNT%HV4egnp?dCDWexS{xZ+U<-1HH4_{fYwq=1>VscS8x>}>i&u49U z)xk3xr(SOa1R2t?L_-575xjNQEk`Md z&3{R|B|K}awl9POv)!Vbk+}lNVUrXUmaiG(Hl!8FEscwoFL&5{M%YmcUoK4M?qtk1 zqg5no_2D_d6R`2x)nHhTbga*!EADhcR_S_ow-Q2VWX$buG0OC3Im@Bb z5T*W1a}tRA2oZCyth=0Z<_NYw-#%}YNsR{NXe>9>p?-yuse3@ti?{34$j>or>f z+8JTyF9Wf{xVU(7#(b_lXtb%$TfPr#XSEyBjK%@}wW#BOVkNthhOH)u^;y54^H~v} zI&6Gd>AxfFusRkR-yAeF-H&cPT#z*ui(kt|`o4U1-!JFJx1?!^y=AHq za-Ip@DW@_t^Hkl}%1Qmwrn~%&>X%@`>06AcBi)J+6>)dxu(*zDs~4u1&xK<`kh5?b zcUkf3)Ng?i#uui0+80$|{2~H0(dz&Xq@@n-qog$;1HCf=>m{QV;q(x;bjdLqE-D*Z zz}MyELXjyWy5{laTx$cD%M982aFTr7Tyi3h=7H(aPu3Y3@iq#RDJMDq#IU!ktz$M{ z1si6a+Z@YT`HV>v>75m0Ieq9>ZL^;kEMJ{4joB17C3M~8^8y!i0@u$5{`D%%i7p>M zX6i}oeKADDXwPmfGRN}R95UOmlXO`BC3KoiT||5RPHoOLIs~)qd4#tHE~ZC6OHDG? zSshc>tQlMy&SNZNrF^*7eV!g{9PQ`9QqE>VG1Xe5=;n@tG;w5CaT&}|@v5H@TjBiH z7)uZnW$W}%`~q4ySqlWIy!uglJbFl6c>DuB%)s-Q;b5zH4QmiaQpKIi8W<~MlL%@I zE=Vm0hQ?sRi!j7dqzyb~x*ZEgS@Qa^<sKlNK=sgHQ@mML4J<21C!R1oz;#(-C~%J)4(r4t8Vf3Tf7WHa z7@kJML*;?m368TH(eQA&j3?-gs$HerNBgV;gW)RhszJGm&**{jP_@hjloPBth8H%V z2V26F%O#vRr*V-p5Kn_vgFAn#O02Z+I$CLS<%RJDbWpj{JiJ_XZx%{x{d_iD!~L?I zMl251z^cRHMsk8uHaH{I@{*G?Q#%}_x9MWTYF(02NI?;g(8-z^aj$xP+ zKgifwls_3i(7cIQP!9>hjmYy%t9n6{z?u9}cuM0bQFiwE^JNJOq2Bfk9X7U2F)oH< zmvXZ&n4hYuRPO%e8>Y9$Wj{0v@k7qLod;9|?q=YAS*76J^?Oq#hk z4O7wb%`fJ9mvC%b&E9Phw4r~qUgS{|0-Hf#o20%;;D`bjD^LQ8BydqT@Sg-OzvN!b z0LSjQ7cV95owUX_&DzT^`HhACxErczd-)|3+0>G;YR$)1N1Nbq4TLq)31DlMx@N34 zI^iQm7A0^#-GPHMxy4D?J#%4;mn307oeNvCGzq(TE^O(tBb{P`#daI2=bydvRG* zp+A%`rW+a>$JGhYg9&e8yQz)wxKH%~l*pkL&*_=89+?@|sN5}_o{8+4naS$uXoJG| z#2uf4s?5ofl)cKQ{l5WFfFM|ay$~Q+7GN&~2&e_v3ju;|0rsMLWo*rO4Kq|QdorbJ z#fWCwoBrMhFUeNh98^ixjM``ZlQw8CK{-)~IEjPiaw+etqNxMA@6aJette9>^YYb6 zaA-F{WIn`_c3la}Vef}OhDUZ2gi{;l-UA(uA&ZI$r%sg}jujbBZJbLqKf^c~RF&#t zs$zw8vh-#@=i#z*a7KH#9aXi&!)Cwa;j&|UFPZ0#s@m^iv%ml0vhPcF#@LSPC7lD% z9{HM1#5qi5b^9U5=fjCU30}e&Gfeq;gyBgp{u25~|J-sKEN~n!isCx2qkA8J{M%1- zqY5=*idXP@LK3`(1&fm6l|8|GTCnIT9_tBSWx=AVc(0ydXThSacy9&EfyibfVnb2$ zUnu>l{R_eaU&Bkd?jn9Yo?$F(U4VT{^MW2sLyzw`Fq@~kIaEU%193y)N4q&(LmLWl zQ{nr#Ib=f{5phf5H8+QCXaggjAl%w`HX8GMN8*XP*2$f zviD5=oAH=7i?miPZ5rmqlQ;ssfI?c4-54M(N5&mRz}WPsX*aH*xtT|C`ZN5N=2Ce~ zbiYBy9Z70U9v5JO)!KuX=j&xre)_en0P@qX<~NF8jA?;8hLrdZc~Kr6YUsAgWXo_n z58VDE9_+!U<3ExD4E2aVNY3OnT&lGn*%-yXT+NhLuG~3UxyvIfH?ne*e7h8$@`c|| zzZ?cm^#e>i)2Uw%VRDVKZ4D9b2n*nyW|4j;e7{1Z{W)uKwZB@Td<(U z?{yD(6+L;CjJ*2r_sR_>BoIXnBO^}x=9JI*!YZWk>fm7-uAH8}0;;N-PhvhqV(V<5 zp0>`H%5>ceD4ZioA=CA`&w&T;pQByu4(e|M5E+8c8D9z5=0^5;>NR<@_t%Wb&fVL$ zyptuw`n`dNY0O4s8Xm7*g>XswL=;!!`0k%ouvgl;m9+V~pZEZF3(@+!cn2cA)eEt6 zGzPI=d^bDPRf0pmb1lgFxAUMKMDgq2prG{h>!^Eu;INDNs?p4cQeE@liiiWTvKJYi zLv{UYxtNacqL!ViUk;=sCOv&QpgIw+BO;yx7>9>y*;WbP_6t7(D=U{8=tD%t?JJ4R z#D}pAVxKOL4AwQpm@6lBOjX0XoPmA^Q!fR%1<-*XB<|m&EoMAng_t4OV6lPd2aD%u zpMYS}vG7R8ueV>%e}(2LG^QZDukuFq9?3G;A48kW)M6bnt7YRO2$W3x7DdXLQ8qrxejjVU zkK(ueo)wIvaGI;Z(m}R;Bv-a1nhtuyNB5T%DF^9dyyly4D^-^0ig(=f; z(N2L;ZI>k*-D+hjvSqVm^vd#G?FL54r8q)57NvIbMe#F8&^$Jb)o@-#b%1*d*o?LM zR_Tn~Gu5G)MzQKngEq|>PG8N$*srIga(c%C*z}dWa*Wka4_--Xq}=R}{E6%&s$NCm zAk^Ah#3Ho@W&N27HU8r(D0ST>`i%by3#w@+F27JY?-r_rW=IAB8TS;1zN-3uU^KH? zcb#B)J~cYP2+YL$GA6K9OKi&y%EzCh&dvSuwM(vs*^E_v3D?R)CrkuJmOwQ-+8YHH z`#tw|!S!`|O=k%(Q()R;4X@dgHN0k7t>OE4j(@_>x^`uDFs&e6KdUDb_v1mDyIC0t z$c`;Ji*f<8e$AvbRMXZDYJIpij>ppOh2)}LUu-p$>mGM@QhCEN$c{(N)ucO_P!XPm z7J0czm8fCOqCBVXl!vK?&}ZxtO5k&L7x-KP{d|_OJugN}$noc6$ET1Gy&4iI=M9N2 zrTJyUE~r$rm=G%CX9MC5yingOeSOoJs`ED^`F+^Yv{9t8b%;Fg4cIUPgxqBb$D7%X z^iK*nNf{I`Rqce1yKE<*7I?K!^|EfN_xgZ~6#$g?`OnL`@i+K@ ztGfZOC7_oUl3J-f({^{f+9UMW#j!rrwQ(JuZy2aby><2Zk5L>g_yuBX?H8yt_0M-Z z{j*zm;CqQj?}`NdOa15TI@kj7bvu=3NZhD&3%xg(MH8q~mBGEClg)kD!+C8d063Qu z)LU-~|AN$>+!X=WCMBtNf>xF~82ABBt7@b2_EPTu%H8e|fIcTJHvm zOi}UAAk~s=#sdBd{KY+gvU%!!OFpXiA^zA$nm3uoImY#hjSJlCfmm$BR`p`zOsBdQ z8>bp-#l};eYE^7JA^ASqkDyZ81`>X`^H>mpw@fpP9pNHf+_RCdFJfn?F{V?rDJR6Y zV}hSJRLK56#JvfaoK=cXD&0Y)NyHryP}~qyKwLn<6-S-XQN*8)>x{doh>D8iGA_SyR%gQh^F8;zwKN@N z=KuVke?L#x`@VNQ_ug~QJ@?#m&egmLGNRE%(ZF~b{4h179_?Z-!MOoaE$Sr;kAbG- zxU%pV$`%8M_t0#@%!uQsMxz6hNqz|2%f*NJGP$hcjg(Vrj&)W^(Rv>mwtwmMvYb3q zbOcGE02UqDG!*W)b9{46B&E`MW*3Jy_1?(3CdpZraa6Fue8u2yOuK9yGwM^a(8Lk#FaAgalwNjH>-pIuR8FqQN{RXBD3ipDtBf-br*pz4QV?x2V!t+@MgZazY zX)5aRsw&0F){`n+v>wdA#7Ca0NL?>)>*rDIDe|@tmWv|Xbp-QQQ$cbXwm20w2gxZ) zE{}PZ95+9W_)0+%zsi1v?rt4%ba_DdybFWrYY89T7$*>HQJcc zE{GpPA@#{=crZJ%1@@YqObSe$KDa`La6oi3#mp^qE2AE*RdYOt=o4EIUQ3O=Q!?jl zS_Y<1&e<^rd%50PXSnPk)#P&38q%rWe5|t4&T5tGrGmVfHTxjY+V=dO`k4gR?F)ia zmV^L3>wQAtOY4DQ#gZ_fgTbUOs}GVl*?wXyMiW`rD%ji=U3PEQ+XGR3X!}=yI!v&k zA(iteqnm#MOE6Td7v1_aMk=jO2lD?^{w0??$v>ayp9)L=wN@R=fAcxD!XaD;{}Atc zv(9p-ensJsVxj(`^m{UM1Lbe$f`?lfUD;brR;OTV!;4D7BktB3n$pM9lQ+PN+l+gnpgS`ZjOh zv$By|onB4Gjek4yGU|}C$O&w8a^2Ee*;S3yYb0~r68})PJZsIC$7+>m#Ypy-d1+<$ z>zMGQ8NSs#2sakZ6=aFJMNdp;S2QXdG-@SClimkqxd%WKt~h0JMw#MR8S$M%Ppn4pHYjjgDT+WAR0 zeb&|#lRa3Bxo%!~9LgB+SqC!cTrb-BkV-rnWiJu1NDlSn0-j+6q(0G^ilynv)+NwVX+2Zx#ge-8V6;+ko!Ia3j?t#ZKzo{T z%0MOvUUA1dsc#U5Wv?Da@E6&y8#T3q*c*v$e@{S&Zm%N0;l`LYRIgBnhw&@bLeB&- z*t%~=e5qtSIlS~hgZqSPMyq?b%8u0c?xus*2|?Ul5{~do0z`hlJ>Otfm=)94dD$CY z4yMmt!q2)Z6jO^|C!jpaN~n};9c~q@-t*1=oV%6tQp>5BTKqw`PTHysQDX5u^PZ!rp2s7K9X#fy1!{R0ND$$E);6OR?@PvO`Z zl&in&nw>iad1`;DwLZr`2M}l(xqYePv{xPBU;9t-1mpZSSLrBvqOqc}vazbMUt@J+ zO#^aTFEy}NMI%LHekkeaOZXDW?BXkJ&}s(@CA%R5k%jCTVM=4r_ZHv;#Q%Bz%HsUl z42yYY1$~!IX2ht66FYaP8EU4QRpVdcvq}E9@vmx6;D3^TeT%iz|LOi;?@#ByxhtD+ z543KmV%6NzdE3!>lZ!qVEAFFqktIB`6NpbAAN{Cq^fa#rP`dqDhQ|`J=VX53z3iG9 zIjtk-5fAt8`?M4?e9Rvk77fiK{a4%5eqdv5%vQUE6`o_eQhq6$c^nB*QG-rM_QsX- zdJJ&&6oc8yMT1Q)jdJfYwB(vGw=bZ8g307pX_sBF;T|fk*;yahWMx0V(ytOIP&|>Q zeBeVk8}}jpttXB8AeY$#Osh1tVf@VE^B*EysR)zSTds_jIX(VjNXK(VVnv_I$fP?Tfl;6$2wF5~8^i zX0D};`_V?H^d`EF)pau+ixZB@?h9g)JMqHH%R?;=N!W{PGYz?rFCAkGzd@;Sj> zUCA6(_UuCoJ^N6(G0;BL@o}!qjUOrJ3bq|}9cFD_z2`gq?YKhiaP&+uj-E9>sy5e) zd$_2(mu$Ycn^-Y4TGWqm4NWeJt2FtajgJ=&tkmUT_9o|Qrq}0eDiQYCe%yz4ntl`w zR_oQ=(Vk{MU(HSh3T-TOy4!DARrfYqwQT%&f3q12twHFx7~VPly$$HvAE%??rbfxh z*6@82r5LxO2jd9!7`LJa;|RSQK+OY6Ta ztISyqajf;T@w6;QSI@>I!vu z`tgR_IwLZWF)40LfH6MCr^B9(yaRIe&27+f6|ZwTEc_8{h)c0%fJMfjI6fsGzgZA# z9n57;0S5i~d|0D7?ne0>;%Bg(!{zU^fv<76n^ z_HkXPlToZN&kaT~OCjRnh^$(R^gM)rZ6VYD^}HiWncCDm$w^7kuGTnQNUIDWecYrb zT5$L678f?3L3%`zTRTZ^)*H|P^NAF$zwSr`CW-auWA9Q*C+}??XvHhU*J@~imrm9H zZXfLUw_N72lsVbOIX5m!c)d@UbFv`k;{vAKSp4y%%HAO#KO?O~`|7v!6m594owBti zx{Z|et`&yUuc?*c%Bfn`m$zbZaRT7BPI2Ei$ki>KZoI>P%Vwthf78S z)o+49e}VIU!dP2j@8~V;osXa};f)3yKDL77`z)yu^~$~Nkhe3^>W*{(+}d~qc~77( zdd4rGoJ}d>FP*2Q1VXLlx{M-U{m}(Td&clXZ!>Vem9!!IR{@0_1g!s;7Pv%w|awbN1_%#h?c@?x5rj z%w?SKP?xjCcYZ7E7e^+_#rcI9-AC?;{hEE(hGu>Yl=x7RGmdHwI|_SYS##FM$h}3% z91Oad3+06?fXsA(P=B`65&k`u$}rU~<(8`n9Zl>AC|!)7@Z@Cvn@@G{$M;f5EB3|v z%IXv5@TG+bkS_IlsgmTm&+GoD)%bae)$W#sHUgRA{g1J9K4e@WTTru7-B)8Hllt2q zKa-1;6E=gTZDR-p?yowhAuf$?M<-m&K$_U_VW7EoO_IWWzI>@ z#q1C@q5p?-u7?2ox%{F|xu#VzFg?mP&=bv+AozJ+$T=MwFv&~xhLO2QtOp?4YGU4P z+BAYLt*K{yG$PTN&Vs%>ox%C6ZAuOh&N{w>8NUll|i?AQ_!xT1PETAiPclxaa6? z-u%HINWQ?%Mo`#WQ%H3L$DH0EVI>zPFOM?kmtLe32u{N)N{cYEUt4kQjY}VvJIz9F z59LrHxmnvvGQ)OW>NJofxO37&9MU-zx^4(qWHLoqO({s3oXQ6+PHPHQi;J|teEdB+ zR<#fqk^;?PvUoHE+Y&KAZ!N@03(z1tMD&7FrVmo31KGhs`v_Fsmpy%b!hLVwoN zUruMb#hp;Xhn3vdZZF2ev2KWSS!tXG!={lDaH){j>sy1o?yj4hIg?0N4?>;2jXy1N zr)1`?%JsfyD;&?loXscl6Enm>>1kfEW~64<^@b&px7GsYrPd1Vj7$t}VNt=nvQ!5~ z2Z-x9C90MxrOrwrkx8BZ<}q2WaCEzx_Td1cuYCLgjcV*a4M!mPh6=jkMK7{&=OFnU z&Dhi#7igo6*0$4G0A#|&xaTuR(!U!FAN%(u`$w(1-<5C<5+?s@dlLO}2u$@%=?J-< z4MN>9kbUf<=^^NRM*PoUvxcBdyow#rcF~$pV}O1VwhqUeG^Mu==FU#d#0|buH!6Os zVcTf+q60#M9JO8)xtz~;qiY~(0j{r{;>wfys;NCv3yS=qYU ze%7$nQz93`e6biu(@cV@MAo_qXkSNS<5%L9E`5u2(@ACWP8Ub;YK{A_pAas}b~AwrE_-SzFcvqjH4$GSP$0#KOb21bok8iL33!KZestfe>y|-j#0H2D$ly zLz;i#7FT@#IR~XV@_DTloQ0Ag>LiHF#|G0?6qI%M0f+lh=1tUj5Oq4=skywap#58# z8Q((n=G#%K&he)R!d{KAD0w@-5)9nRv(0w*e1seg2(@G?cav_YsL%^ss3ZxWAyEDr z75sDsdW!p5>HNoQy6*t4Vg-iH$4Y(+(Hq5 zf;XIexEHN21@j5kpiO9D+{=6`HK*8Qe2+J4PdOi5@+{0J%VGR!@(M8&^wMq+slQL^ z_7|=GP_~L(dk;?IlhADv3VFA{ENkc{`s8|Op!PY)o=c^fPm!D=4&?)h&paH!R`fD5 z1>2FV7}=dIdq<~Ovo1rE%;3cM_Z`Q1N4h!|#f|5%UQ?w{zf zps+2de`n@iO)8f1-9IHHh!*tN8(u}=+&gJT{9X{MHR!@ESA$9RJoFt_?S6oy(cbXt zH0>ZJt(JT?8x;23OKi_s&`Xr+U6i=)3dKa1D|h^_5Cyz5F6iUMDil5Ap08}M=X?Fd zytG@4Vwkf3MiHh%`Dt3yR=ckuO^KHNj0Cj%=R5+gE4em>(*YTU3rYZk;9B#bQtu64 zlcpL7B9~AaD0{Fg>21x+x?m_Kyj;2Ce+LxqNYT4%Oz#J6`9XgnFYgwjn0)*nYKpD% zI(xj+o%4z;oegU0-0Y*8O`Mzg(=XAS!jg3H|BxZ>ql>lpbA5`^W<^{bvO|)QA{I?M&Cs7Mc)QyP$ytpZ1fES2%~S3 zIut#9$d}IyK)q z%uo3ioT8Bzyh`L90fAcVqo8sgZ$JU?9CTF7M-1R7#K`cP(E<0eT#!ACuF;)FaNY&M zq35;wY`x5gk9evxf%0I@!PkP@nuEUpvBL%ZwpM8pUYAa<&LmVEJkOr{c=phXS9B+b zV*KP#9g;`G)>P(R=j-@K;#KzRA6B+vRQ3=1%YJ3IY{leL8WPx{=5Oif8m7TFq1BOH zxP@PbB7O(LQhp|}()n<)&Z5fs{k6!j@us;qP{q3J?q90nVE3vYy1<9$y`eAfP%+J0?8)l_C)Q(R*s0gIM`sorX%C0)?}px^ z-}n>?L|?%r#0|oxU^o-S*MU08ZAyXj6vtXYhxi-}d7QIo(Z*o)$QHClTTy-p3Qve7_#)`j6p$DbSkvL0;xy z3QO^S2~l+inBr^=gkFeiZmkR#RL1Z!0&L7|_&-cgW2_%mF)22xi+H?#Doy{O~M105`{j-_=ar?7i3}w(BHe`%|h-(}k z#)a&;A7a)+_^(W<&$=rVQ!rX7(S)H<8GGlRU62iTv8?vaYSZDgDcgDuj$_$7wVv+W)?c!- z;QiIKPR}L?W1!rv6WtZGm;5w!dDEH+Ee?s{RAfF`TkD-4S47ME`TGP05uW$C&PFYa z&A7?$UqSu)3u@D6`SVwqggfoBM`yiS8Q11Y$^!GIW81c_k#`@F7yOpwrzC!&hEYsT~xj4I?ir_)?l!NYfAgjd?bd;XO5VWce#-dZ7 zdfK=A^`HD`3i=e@AAUfI(?$FS+{eq*DyOR{CzbD_ptx}>g2xiEDDAJNeP>eY!mg|8zYR#Vc-Q)HQcTeyXR7$3&(&?#mdMcfsmQGNw5!8%F zl#$#+f3)DoYQa_@{)t`=#Ye>hdWrW`xtB%$D}Ksn@^)M=w#Hl-Nq&}wwI|ai!{5un zg|+)fM0eZ$R4xEz%P;Q(3sI)2ZoW7NBm(IOf%IO$cn%@)l~qw#U!pJT7ky=YgA1du zv%oXP8d}Fl)%D2lp45XrT5Hez?)~it*m%qG)R{Yq#VoPYFn?Leb5&syIipXM)hZ)ax*4as1y=Zj8r6 z918td&bTSZKrM~yRq!=<^%sHp2i2{NG2TIYPG@6Ju#sd3yh?PVenj#k#%le#?BxP} zZ|!%0+T*ikUHvGZpg!42DbV*o2}&G31L3dqNtg2!Zwbjp zOvI`cFGD3-;<~VNUsO+;1NW6iyp77qa!JqPViwgy)r;!cn2od48sEE`VM{;8xE!$a z@dL%&lbzhQ77-ukiriBI#Q(y0BxlffwL?e!XDvCC@A`J5R%AHhf0RLe;(TMGdC1wF zpeluv@0n!d$Md~<=9=CUKWX!((}pTxC8%vI!9d0j0@9%amn0i9&z<`vw}oDoYY$wq zpf9`d)2C>2&&9zTXp;ZVUHi;4=g#K3r&3Tmv>0Zwem{pV&Zy7jk(PUKg{k6m1Up@d zeO^BEK>pPf2$-wIrFZzM!}p1GCGDWw{}1_a>x@8F$!!YI9o6m#cM zjLUsuHaQ&Roo7QOm&2$_G)|_{3-H|E8%Fu+s}|3%IQ%&h1^rf;q(|`*#3S?_?PI+@ zpR(m6KOR<4z&U%?c)3~Ni(yGh@)7oQo&(LzFk;W(O}piDL1CPvph8xBm-v_XLL%04 z?PP{X)nS@p&r~3}F5=n#%>89KhRSi(p}V<=+Mh*4BjfHaDrb&4)zo6)3FhyEY6r>F z@J~Vi`LFZ(zRq`FLGndvn_rf-duEo|S@tI-Pu+#_9`;-)A0$7=V};g7;d+%mSsedh zCq8TYfWCP8Ci$gHpuLyoTVH$;MTX=zF2UC9ylN!?-D-_>kXb?cdCk3D><9#prGFA3Z!vvK?T-r~TgeT~~cJi>He ze^@%!yMFkr-fvpEQ&+&KR!##YG`|D$oBVJXzx6*z`5{XtjdPwJE7|!wwB$aA;CH>3+0}^u`DooY zNfx_w*=4pXNo-HvTka43Y`M(UWl7R47guKCCCcK;waowPa`E_`!n^Ns{|v7Fptr+B z=l26=(1h>O4$-Wqoj|v0FF1|+;|N-`k96lPo$jcf^4jSA?p=PEl|#wrD@R)1pGkK? zZ#wkz`{8?fS}&qlgKuAR={{@jdAhKgcJ3RGe)tH}-Tw&F{m9b2x~E>r*thq#!{+9X zl};UWV1Ug{3Zv3uiO_AcrTs~owq>1pnxpo*5N1q%5*|?W6Z-@6@lO@HC}~ns_nq9A zG#OYTY*1l~GY>71u&glkZ_d`NCFb<7Qsl?DLCeNrpXn<7>71QWUwMO~&75FXyD9%n zz4dOYKMNmMBRwMc#vft26^}68sz;b^^&?ETc5%9WtXT&tT}n8`?}`pA+0W~`DHo$c ztf<9-jimycO9i%;3T!VGIJH#Z!Ak`mvQ*%qO9gIRDsXzKz{8db+_Y5S=A{A;Un+2B zsleH#0=F&^7%walm>jWG;E_uO9<@~9wxt5MFBN#q5`poKr2>yzA}~3AslXGK3OrGP zsH8lf{l(->lWY;$+Q{S~8}A}08(+#V zG-ze~*I8D$H_va4LCRXr6_m)5~_e;2gEU?r|t>b`U0Pf>EIIoelrshP#h z+SY9b!1jeMAKqxP3+mHSb0E7QSbS1Rjb1-Pr|acG0c-V!nFXH5(pG{sR`K1$wU0%B zr2&m!#~#1E83C0B)_uj2ZV3V6_bcfNiLYM3=k#zH1bAVZuC>9I1*x6H3o%>cYYjui^5zY^hYa!von{#{x`5HH75ovW1$yMV@_az$&-I(H)1M4p(b460JfZlg$ zy)~0qOX&T_rt@Iz@H zZE36>mgWOW^HM9u)_NpDnXhYqnu4!JBoiUMuOfdza``~U<%se;n5~}>XnfkEUWnQ* zGD~}fjYtaDgF{FPH|T++Fy<*4n}YRJxSkd++&a>vrIOi(W*7=cl9#@k8skk!3)|~K zpR4ut-6CHTV9zytfjxwG#hDZ-zX66rUZi;y$-3fE@vK@)Z&iEaHxNe~v+)~Mau%$O zQOj&Lew&?qxd5JiOU7kl^vMQQs?srOjk%yY*4hQTh}zjcL}C7z@$5x;;RuNw+*lx z{w!c`?gQ+>?Bp9&f#^H;nMLJ7pJculMsTU6?#=IR`(D(idegoI`Kvm(Q^;ImkQ?l8 zqsr+WfPIr*jsW6rYo^qd-R9Iqje6U|99GBpj^4iqs|2vethe^HiN1U%0gX$L{U}jv zIFjEzCFntpgFV>#7WnqP6<5|mrC>K_VHRvpgw9CCS2`)RlaC{q_Ae$bFW0NYoAZ1U zuji7<lB& z?Ch8$ie!%Lt-X_s$$d!LfPU^Nuci*SD4*)2aM{Zbr3vu|wS;L!+sN0rPTe|tw%)aB z+^Hw}o=~=`7$i-ZP7oiP>V#rwlJ0$!0W!cCa<YS}&-by!cMEXSAA zMya46woe;>1iE(qg2V-7X~sVu;qb(d__GOWT$ZvapH>sET|*P)(Xv!?43$uL%v#V+ zTadFB2*0wKgDL++YlBtbK(7b!4M^RWTJwL?UGu*yn6(mqTQ5)SxRs@GI-}a8p5t^< zpJN;|Y|SnxC`kSQ>aK5W=DMYO$#}(PrDM|mSf#*o#y{ePF8v9Q_(26O8r{Rm;Lsb` zm*5wFpnmu~{gCo}e~#bO44I+8iTDFHLl*OL6MlYlDs}Utn`IyKW5Uf3WwZIA3_bJX z$>~_!#iH(bId@;~V;nxI52nW%N%e|j+=`G!^~uy)){*$3eT>i7-T0iQ>7u;7{kUZ3 zrhzVb@UR~5pw}j`@qeco)Qeu~zb&+F-1XmST*B<8QcvJ!AGn|}L&Z0x%|BS=A)QMn zxwikh+hpqcjhd{v^wNFIr3-rIk`l*%;KvAr3JTn(L!rztF*SvHQZ4f8%Rv1E!mZ?k7{_i^?t?LOX~x!ou5)O=ZWNGbCm&&R1B%Fd@dtNp;-k0`eU zAH%JBqeO(|fpTfjzwgI*=g(o86;mMV12H?;Cq#SxgQ#X0&3)@^PWP69AcI`-nnb(| zmC?L=6!o1}9x5yx%}Z@>a9X)sSlFS!!UF!#bFHyrqSOEOU{PG^KsU5tZrIBO?U< z$oD|R<*~M^!7Cn|z;7rv)TD$!0F3hSPvMJHA`P z86>~OR~lC5@j;aAJMQ~*99wRo89o-&m)NEe7AEJ1oT3kA3-J)C9Ucbp*(Wl}_m8=h zcwHoAwqTL>6&vmhHO@3nvm;Dk$Ynl_w({czL)I`!HdEtg?iNy2bTiy_@bGvH>xHN@ zl!FE5!ZdjikjVGjo@cK1N>>;1vNv3JE~xv1F{uJ7CdQXlv&BUN3$s|b?zyNx@p>iJ zrEKf2P)z(9My4H8=(GFNZRi%Nm`V+c1L`a zFS!JY6ZX)ZApR4Qv1;M|)h=1l4QM6jhP#qC@^oK?d;Q$lp1kbTo0sWW!FZ^Pc%H7Y z-E{=BQhIswIu-Ay+F{XiJ)cMMnU9~` zi9Ra3-=2BMUM`q>)iRQ+?;`Wnf=({?L@#KS02WdFpj6Hcl=H}#Hgf%eX*Il9stx() z>DPRzjiH-!n$($Waj{%+U0}F!Phw1-pfLdmnC7*_$Y)s)?}Gb88@mRF{EWez-9Jl+YhmVio@cnSPdboQIiz7K_Az`sqGC@Zp)2-rdK3TrTWHgnl!^WZq#J6ahndW+ zL%}6JNj*j%eqaPul5plqAdvlpz92^NdUfrEsH7SdK6d)JN;Ho&B`d?uf)y2W8ANmb z*@TV9Um$h0h`}duzolI~ey2wfs?W{Yf8aeinF^Z+Mwou~WOAWpg~nQ)?Hf2g1RPtR zjhSr?x-DEtjzXa$nPL!8#T=?tOU<28rIg$Uebha;t^JBEJV;eaF;uzapx;;-h&QMi z2NlN8^yEJg!Ev{U6q0ceR!bUym&TGGQdFgcA5MOwg~0m+8?xKWB={HNe;S zoOvmoRjUrxszc3lxeeDr!JWA+w23Q2Js`9@-&NE%0|B#=8*1M}#ckB;ME1B`ww(Mm zM5S7exW2aR;1~ps!O9T7LzN*9%^QhN?x+4Jc^r*IiPtEtLw(gh$yILf&Oao+K%SJUg=j3QFC_oP=wfxeRY-?kJd&R-sEeU9_>Gb!hgqFz z=L{BX@AB6S@>!ab*30O>eFZ6x05!|_a2M8#(ElxOAXyv0AIlBG`T8k1M>;<1rWvb-*0>V1XNEwGANO)Fm^|x0nkz z)r$3Vr_L+ZFThCp$;JAGQ)kRPSy7X(A?c=7MH4E|UZ;E(H2VQwXSP_9+j!l%Bji`^ zbe0o#BTtA^=KcKN!+&w|GyHBZ5jBnmc6J_RPjwmU^I>aMm|$jr`xlT`_UmDSr9)`E zEHb^Ubr^2C)n%^32BW0hNukpIPF*TFv&)p7->!hu=tUwS|Jme5_s-E#Hu*L6m?seS zCd7j-*#zz`Or8~qWGM`N)oik%KWqo8aSYifRxu+W;=A5T8skTX`FOoPK(_W!vj!%q zB#aTpVQJ)Ygjb)_aU&J0M)FGCi}*OYMt?!_eA2e@A)#xV_Mlhm%mf_A+B_E~^#8yN zth+)nF|1TmD$xCVn04*!`bK;iJfN6=+X*@fuS)~xFr+p)+@RI@6ya2myamjTH?x%b zyXk`DMnXcVgiOLY;5K>h^0mBhhg;yT2rbG6>V7s?l^mL($qgj0%{`Oe(pny&6ohYZ zS9V2+oUXT{d?eXN`-PpgJQ-1l7IxfO_+>l_k}9EvcnW%MqOwnmq{`lc4$qvea%~H@ zRqI6FNL4u;&fE14-0CF)*cf9;=DH=DD33;*t?d<#RoK}Qs(n=xD`Q~ZN=>?Ej7;gY ziW<2+&!L+<{ZuL)Of;zBLq+g&ME+Y5k?UH%9aOQ3oB!nH0_gWBlU}PejbwXJ;-zqR@TSOi_S5@I^f>joc?OIZGIl+err3;b;b_JM*M)8BZkPnj;&%`iLJ|A~R6cYNtAz8J= zCznW+2t1cS9#3R;2^iKTCHHz3>RI3Jl<@Z5g6>6=?7SIgxf5t8TvtY!zAZXnQOf? zkA1gmqwsHhd2G|UQ?i>*mw4MiQJ)NCo(;Z{-}lKtWMq5OWK_Rk_8+Mts$V#ZDt*R< z&;B#7Gn|<4E%ci@B1w%kdd1FI=S_#Hb8?2n=9>(cIwG=Rg3k^4CA9@ziWHJzg9U_NrSxyNc!>Wg!&+T6+d%2SaR43-})8HPNQchH#W zgTM@(WQK`OFy#Xq}!^#oaoT*c{%uOe6bHTln{-}7+*l|YK#&L`)y2+Xrd z$R;m1SQzcM(<0b-Q2jmJR2knAS=b{uMkH(!unp(A?qVWF$1)trl}oJ)7-q?C*v2bg zkxf>8Z!$t2GqW2j*5>|`=xRQwE<}{qib8T1pNJf7 z=z6*NFdU2GZ@}$N%Io@6!DVk!j0#}fer7|4w?cg6|Mx>@Lv(W_Qcdx(KwmA$f*#^I zR;a~qP(V?$pwo2E{#S|xKfs=L~0F?+da*~DWMGf^p%xls6F<6w?G^46jG7#=q~ zhaJUu1+)3_aI(U4=fviQ3z<4}=7yp=eteXU-^7#ZrjFvtLOXTb%;iLyi*_R>$FRgU zI-m7Q{3M}HH(+#eKy`7zm5dY2fVTF!wX(7WAE0ckU2#{|W+o|5p&d`2S$iq+!=(Gnw?? z4Tf{R{sO|kN?pH)<B(Cjmn^khq#Cn-BF z?tG%8$bHNx8f6ed3MeuiQm5y5l5Ef=a~~BYa~+*$cxJHz7u3A&+>xV?|Bas$gG}Zp zgmXbGal+SGtWPsDUw3I&GJdz%_z8s%c^nn#3CJ6ibj)%oX!cAp%)G_r;@j2mMrwE# zH6SU^IE+v+v!|&BoJvt+euXbi;h(db6f}FWU_Z$fr|&Z;iPXR|`wnYkS+9>GbY{Iv z1)p#TQ?0zp6`1Ea`vR9#uQet8lYQq&I_r9>tk*vQ;mnUMYIu#yJq+bE2TkFmf@Tj@ zlD~CH*yqju#u`4nI-9X8)<{+7^^d?mb3Lg#^C;fgH>YDa=RMC*4(rAEEKAT0Dftk` zR*>X>PZwY)Y|BFXN_It43r+x^Ko1YicS8TOKP}uii$(o{sWOGx>xJ7tN>Aq9(lHXu z+|E~8(W1=0qTbMMMT>x1s-nmCRkW?AqD7ha(IS&_z%$ztIdKgWi~D)Y`CHdNl{@L;96w(^cP7X7Jb7L$M zZW9_`thFM|-$}WpDX`PT9HbgM=Myj8`yPZ&5&J-izXU>O0Jhu?sr&yK1k9WF1%hJ* zwcOV0@lzK~wQW9xjw|Om8d0=I2~I`^Zg8+0coFD4k-l*YLYgw}MhZ*km~UqG}RS+Mzi z(Dv^rz|V^>@t!v#Jrzxgd1~e-B{dj?0AwC|=A?X-L(H-p4V zM8OyMa;w3$@p4Loa`%@u)Ge)OrR94{%Que)v0YKqE7S3*EUL13K&QUxiFBBTv*o^$ zf_62R9~-Nq9IJ7v&D{p~h>#^n?%*XbW|9kopm;7pa=YT;2@9E@(FUYYmHe*vIUCeN zbI|-{nW=+#uI9OxN;wEa1vgCcoT|5m+|!zk=`~(S*I`VY+pB$q(u zJX(sQ8)VCp1q8e*^BVzBsHYK*q`)gD`xga4a^;B<4rp&tuOBj2hwFB%-a_BN>D}i6bbfwymE>u(g^f*6S>>PEh z8wo1KY95(sI9AP%rE(|hUf5;hitW--vBkJV?SR~Yu07#F?rn#=POn-3@Eu;bBPV3Z zyhmOmpFLDYG4XzF2cRe!CzfPETO!BHCaWoek+_ z-gc(i-evJ`V3ty48vIR@X^6~v;sLLPEQ+O^EJ#sp$BvW;!S0bnQ$&ha0T zh_}X}Lm2x@zEr;?ej?f9pQ^`mCZDmc>+N8#lC-C{2szs`I1you$AX~o)Sgo3drGx& zJc)69j_}z=d@N=oiL^{=25xZhrDcQTrDc)MGxDRk4sq}ksvw)wa&9#2L?EpWit(e> z1)QORC-%yzV=+Enff60&-7C(CZDcw8O}m{J$l~;feOCu2hw1R@U~`}{qz{N^)t{7m znpUQ?0SsP2kodd&KuHRfGQv5BJDf)c%y~(2o%;869$o+?z51?WVz z5)@6MgS_1YJHN-4*UodF3xBr<9qaUz1M1vI0M{jt#o~=a;0kXM2vGk%Y32 zbh18)Ft$U#?-Tr-8 z@eQU&#k$?<_0zL5;mJ5W!lwECaf zXs6nhQA+H{L8Hvk(A(#B=#wW;rSNQSGn3$XDeU+M$3vOI8FnJGwHG5)wcSQ9{fY5f2u&VsU1H6 zlRFUq7QKo=H_iPlAF}Cl_8 zd&w3g(a$?Ocj}^-6kFwqwA1_5!Omb+hlGzT+idVW=9B}3_B0_%@Cwbu*0}oiho+M? zr+yx<#jmCnt%KZL=H4<+dYldiPO%eYIHi1K^EvsQ3L9DG{UwcL0_O01e;=OI=|j)L z792}Ejci&=X8Z&a_#?;|S317KefOd>@gc?~>KW24w-DgCFFP9A{#t$8c?hRio%4|T zhUv@PryZYz6>pX7Tgzta++y-JeP{u0old9d$fRILCJ?N*5Cv>5gXiHrRkUDb?GNts zaHm6=1mfq<2ee)44_oB%LM3*xcVtVcU%t@!<BVscfQ~QDuZLb924kwP7QjNI3auFsc$E1q=Kr&&bNw+swMab zk<-31s{`_g*gYh0nnB?CfNy}IGkqUrzD-{|-}*vhE`CeTfv}zDVi@dxj3-9dORICX zvxxZBnN{0X=kBsCF3R{LWyPwk(?HDzt*@6nhEFjyX-UCarcE5~$oYoBaYulq zF;0%H+uixcz!Hn4e4E=^xwwUn#va9dL-y=>k@)dysL?Aww@&W{SaWqWm+E7A{sb1J ze+lifqhd%3y`gzq(dGv0(D=mTJ9hU$Xuun2kcDBmEkcI=X!c`1ki;ieg%xR^hHJ2 znIn~vUUWgj(<`F74MKbd-G;tKPOGcCv&`M?Wuh9>Hw_cKrMff+_%!}LKeke!+9V~k z%20{iDK6=$c1f*h!k2JV1y3geE}XDD2{bmlL?B6OWupwt~qB^1U#?b4id~Wr_=eDGs_=ksME4%@+!` zr7zf)UaqeTwyCFo)$6vahl37{m1e{?0M*o3&o)Z1X&_}u=p1u zGI92=_{m*Yh~@HU|X$er=E zhj6GW?9isLi9@#1E zXz)+ei^h=Av8bt&ny2eka<#+t!gxYz@YwOdc=6?0VO3m^5p_oe5Hl3oGo48IjExoz&$0nHtZjd2hOhtj31ui@6V`cV91sml7< z)t3OB-zC!+4vgCx&IKv$&~C}9S5UBo$$vG2R7l5YB->=@ZHF4>>l-9(4D#$$W1+L( z%SRnrsQECEc@OQ|t?|q|g;GBQP>8n%4+5%bgEcXE0P@xWQNjTr&f(9-^}mi>vfNPi zqi*>l`R1Ws;%P_p=TvhLLz7G9vpRb1Nz2Aw*f)|7TD1V#<-^63OGq?uDMErYir8GBAF*Gmj8zy`V+EVn@31p#A5l0ME``6 z1!eZoKW^d9**$T|IqWh~c@V?DSmbPq|Bg0kHZilhsS4J0Xo_#S9mpdzkLyG3ERjkw z8~A@L|BvUtc}Bir5&~R!RYGyP(MtSDWfSbPxJd{u7g4v8pN*yt7^%`v=YydlhRcg?10J%pebER zJq!hw%uE(;z~!$mxBM)_w(M7muB5z`G_tI)>KwNAL&zv|Gv6bp&ot~ZdHIVk!@SoXx4VV9>;q&+$=SfJk2rulr{YD#zUsmL zylbd>P54(>=J zF6)#bhl7RbvX+_I9(8cYBWVc(E2t_AH0}8$YT|PBka)3CUPNy z-t)CUa3@9(SzU#8S@%1H?1`iZzwsNQr;+WwUP69nV>no-pD=Y`q5iDt<=i-?vh$xOle4UdUuNf|xf;P{mD2c*9|PPv zm=Q(so=CkLGm9qV(+5g=0IFT*{(>O z-kMoRT6CEF4MpQmXnmI30xtx7E3cTj6DsgB%F71HGVsdlMJE~FO#(0f@lIb?oG9nL6y?pWxOiO*{rNGhJ7DertJfR1kJ)QMsK}o)&mGEtP3Q+ zn)@kL4K^PgwKnyjVO2IX2Vw(r9n2gmIzu0Htk@y8V ziy0mr_NNgp5f|R}C5v*&rG4qN*8nLqFW0!mIcj7ZcTUiHiZilpJ;6Pb3|Il?KRQa* z!mGB90_DLVZvVrBl)Ew~Odeo<6_cmZ+T?V8*xBgNW8n%ogXE{gttaV5jo()^PjZ=y zsP`4U^`0HHp6u&Ay}#ZazTP9L7xhBwZBQ5rh9!<6UA@v6P0r<~uil?gFDcPJEVaLC zcsgi)hF?x|Pjhg3^ma+SF8zu9Lk3YKoYw@xe}x-#^&z|FvJ8rQ#!4zwxs* z6U0wV(XK14e5aUNKrt02rRFtLv*m&G$R?8hS{UQp)Xkx?>B7E>yf7?g(s2?md&SEf zq(g_JJUhQxPy7Kjkw4407|>|MT|ugLY3bZ4tj zjaMr@hk4?zQWFGO!00S}AgXWO1jkaEn&53}U9*H5_f&)qw``08S*nEdui&UVx&C+! z9u8kQS+e6nWO+Is94b!i+#!Z6*Ygh>gy-!3f5nS=>rJP3rAxyUue^FLl~(B#pQca0 z7uVJMt#X1A4FbF|Cr#|a}DhGu3+^X;l9BuaqmCiZ~^rW zCdeG^Zyiv^W46S!FII1(T^T-4gAm1-!GW#=1#=Dia7c{nF4^m|rbBcJLNP`VZ`&u9?#%vEezK32xKU_mUjFljy&m3MB#fOR< zp%)GFv0@szRs41W+9h2wbSrP@F$|%Bo`%B!-X6qEXBW| zp@ZBJbNDbqq;mx;ZV#5NKs5l7)aWvIH+1}S26UM7x_>51awh~M`A72EtuKC9Hh#L< zTvS9}7k`cIBb%>(xd#&X`d^N>QBW8==MzdQb zF4`=I$2m_6@>SKM?$=UxHu)6*mYR5^kAKZuE6OJCWgr@S|Az1OFGN5LlYu$Pe3g9Y z(sFOt%*S~h2E){Cl7L%9LD(#a?YoIu2a%G*s1Sui!^jmoxI^!U+$(bJGr?Leu6#b- z(GoVEiK)}wlr_x_nzSj3Ukk(59%1A}U|LZ*Dnz$7n~rh7_NS6tF@kq*EIU1xHsd`nfG)m{wmBq{fs1CVA<;k$ zyWrdmiaD8K_T$#(YJNE98qGOTa93ID|}l?<2&~*8ywb5?mOP4H6mnqvN!&_f&NyUz=NLDh3 zok6F`EcRz9Ze8dY!3uoTw{Wkp-c*MyJFHmhP zs7AGFp}Aao2AD||&a~XOR&Z^g4PON!x$&pU)7^?Pd$mSGH9`}UIaUx-H-6@TJR%gb z*FJMwgZZm9rjU6%4Y{5+a~lf{p1GFK{)L=F;T9`wd#*4(o#Y~V!Yj*7SBpK}xd)0d zK6SDqzS!Y*4y3ALJ$k@%Zbjf%^4|POXM4Biqj96X*oHZ!5_bp<%u%@QSsfajvwiiO zZHzt)QnbuFN_R&GGbZauwhh|$1<76fCYP}(>sYI>uO5%Da0smR>Q``jH&7l1V!NM* z`7(}6chA`~xBL0-J6upi@??h0wllkT@oBu@fKib_pWrMKEW9Vmoq&LF4jTgFs2G^KGNQ{l}0p&OS1n z4sc03FEFs%WkzGLRU-oqgDfk_Sq>rfu$vae!%DsfEu>1|()IpQoD_*FUVMjx3mMTSXIhwhmqOxb zxmz%5in!e91)^*~gbNytRJq|O`qe~rE_igbQ-BRxg??7@MF7&GQQsmnB=&t8UGi(( z#WeGm{D}v>q|S<0L63Zoxw4Yy+nyh04{CCqhRf@|R!Ux8(3y&+Wmz3@qiItD600o% zQe~|VsQL7sV9GeZx7a8-Uc`zMyYC^4X~jL|M9FTJ;zIH*mC`@+bv7L(Cy=v{+*6d9 zJ+v;&Jco&Xqvm}JF`jnA?NZu{?JTDbIk$6nG$gs5t$*7S6n{RlcNrdU{QzQQTWXQc5v<-M zoh{b?KwfQ7@$;kYDQoP2+ndr!h0*1n!C79(*G6let*MQUd$wjg(1ms Dq+9%du> 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�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

Dmf7ZVQ#+pm8;dMBFDdu0y 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 z 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

Ja)`SnapDHktc2Ad>sdC>;l}yO#6lTD2 zCpjg%|9~fD3C-GA%(X-PFm$OV8Q{ND>yFlxuM4&352omJ8I~?}Ebl<>#qjcXK&Q!X znTV^lIPW4OxLa}OpkxmFI$MrJ9~n?|Bq+j$Km&+_KoUjl>bJDSUUw00Kt9d&FRKJVhV7E(YL$+Xi?W(|xBOVlr@d6wRNJ=`{}{ zS0RfGdJERrEfA4BmO7Dlb*IZUbk94*censtpHjKw&1rxk_!izJh~0@G)_Sl{*js9# zaM?!9UD+teA{3~6%&KovQI8QCQZFQ*}Jqi9b#fV4Zo1eTj};68#t2`0>PUz0jM%pEvGR*@xh-yb*JrPOZtVXftp z`+f*D+eIG!U1Eiil~;rqb)@Z;2i`!Lz74?(v$Q`R4Mq)qZId^j9M3TM_3sdIl~Xdu z71z&{bTnqFd6BP%?-rzB`RZO&ldLJ!rE)SRM4|d>u*LDh;Pzc7J{` z9m2y9TKe5xnd?UR+I+a%g@XT;=@+O{J58&(E`}v8t!vrJGzTDer zvKeGZu{U=Q2_bfA`L-WTBC|t19U9(_-X*fTlC{{*+r{$mxeLKP-gt^8^0JF<*CrHr z&Rxq7tMcRmr6?n^U6P@DIU*lNZnH6A?5FueB|cw?*(IJ|$|kPtmUv6IWVqSS*1kXx)|uj4eO@h?Iy9r)JO3yecx@J_G#u)sHYVjn?|{)I2Rk z5=+tuNo@Y+3=F!@wuoXxFzT+Q2DhBq$jp@Gu)%-*Hdvxi3W@6W&~ z?vt*XqWRA}z?V`6d6X}CZ2=-;w+cFwo*_)y(w2K&gPRAc7AuqOJdJmPaLj`2%6hx! zPYVboO8yz!pw`Acvu|B+pJCr&)cTC>LdJODj!{P&lc{RQFG&5e12!xW4CTfU;OAEA zyAh5yzlzrM!?;=MN1wz*^g-YG`3CkAQ?fo1ORPYrDDwSnV%EFXgSbOEN2b{QB_8rQ z-?rT*h``6iyBJN~Ztl(!n$J?MnVlt0_T1Nd25{%Xu&1x|Tc}?BjG>m)&+fwYn7Tcm z-r4i#-*Py`f0o=QHt`_`1LCnEC(F)HT&^#!1*HBCw zH#GCV177Ii06Ywo=Hn;XI;YNqxK;CQ|1way9^=KpaXbjg7q$8yn|+!6_MpcPMLK(2QWZ^EgT@5yvimHK`vN*1nVs|yrvXD1rrH7qsbL)kaqIxT4 z|1pc~-OI$0Lm*de*u;5T@W|l7WRZ?640JhbfrcGTqkW=+n`Vek|2CRG44kADr+FmH z$2KJ4K|V4p^Lp~y^q-<+6$2IHu>T@CmIwc>2g}Pz5D1Y^46{7+73VPk7%C{RV(kS> ze~dhVSsmbL9g9is(gR!)KImQ{7)f5SNGZPv=;*w zm7AQ_r2j);t%e-w-7GN6SEp7b^ABI(R%*H1l@-qh<_~!k-LogpEm3kCD2EpQ9BQ^F z(J$~c`EDN5z2NQr!T0nB-`^knK!5Oq{lO3Q2S3~&{78TBy$Ws$P`URhbYu!+!QIiH z_+R>iAL|d^*&qCPfAEw2!A~fdsp(VwpFh3q^Jn@$f3`pPx&GkY{lU-o2fxrC{9=Fb z-xSQi_0j&%|GMn+mzIUUye#|`g}dneszSX!ze~Z?w6+>gZ@{AVU5cw>Vw%1;IQ?Tp z+>QBPy--y4|8CxFWVX8O`?AE#g1r)A43kCdJO3h5*SL7TZzyfJj<@7*-QdgngD>s| z8NYcutn~iC`(DbYVTy`3!XqvSE`IVuHaFh3fmx0@^20nixUyICX#aitV>wrZ+m2$g zi`n&Unbz~v;A&~|qk697Jk9o(QhSu#t0IfrUr4iY3v2<)k~u56C88Hz zB4B#G@S<)|?akYs-*e!bN_sutz`J`Jytp-&!TY3+Bh7B~F`OKc;oSDE)a;JtjEw9m zFGR-@kRI@9mA|lCo9cQDZU11v?JM|#w+xl!4-8lp2rsIT(&RsV@1B_>k3=ymF6KoffJ(!RI%ubBtiPlw7wL5FAumypRU=L!#Dd z0V+s1@FL)g+&6BtCd*yz%iTb2{!<}|F90GR{g&m?z$Z9Q;Q3+T^jWqaWmN2L4NcZj zq@uemg8)_kG-8vBgbgMcOqVG-#YeZykMzns+Lw7(Uzwl!pUZq}rc8R$nwt0R*%3f} zu=@YU6eAd3P5RISzFq9_=I-dhfZ~$Tsg&;|Wzn6m1$p2y+7Yk^+=bk8$@9@(9#uf= zzeyD%h&X#Ai&m1C$zREE(S3*5v@4pkK2;hv%kB#db=hPVox$B$K-vIz1OeD<04#YX zn!(1xXBo?Zj9={rfsAZ!whT3HTYA(lwI1NI*x) zaQ6eq*Z2Ads88eM&R%`Td)nAM<5`2RW=jaE5qlUXZ=mSDaiTVSMLN3-8!~n~;bXR= zeZiFqeAumK87Mxt5>LI&z=S*_28C~=V9$>|ZjPhekN03bt&5vm3^)G)n8LLO`ZpnD zJSB^pbY%E4FQCknPyZ9ebon#}RWkH#|9|G!zODH%deyhG1-PpR|B)WoFQgOIc^>SS z5YnMFjmokgm8**G#l+gMPSM}wNSTtR{5y@$u&*~|yTxd0KkENPw|<;|7MNB&_xNYS zV1{u#A#@csx~Q7+$(u=#+{aHCzf$yllCt<#NZv*~h_mkA{wQ*|&mBm=7TI#sYPGTO z_mde}eSG^?viJ-kdftbuytnf)n-u{sPToOeBYA~J-WIR!h%&gH1fEX`9@!uzE0`dn z5;vf}jO0^(Msl|Tik%mfec`8-*1hCV@cJ7OqS#6Z3k&IJLSC>5Au28Wot535O7wKJ zi84Q9Wv1E1C?j_#WSBCl-3pDn!-oEe?H;VpS{YA02uWdUE1WCvs0AZ}N2x;6!e#iWy>I zXW`_2y2WTB%3TZ&J_r2x>%qLd+BkTGx2K?=5_BT(YIEOMQ_j9NCRovnpqRT$Ii9xP%S*cC- z`qB!!HN-_ZBkf!<17Z`Ii^@_z{wr3>L zgOa8wr>^c~tQBot^abF-w>b7;{x%M-%fb&uG@Xx(ZN-hoxEnSlb5L^snA+NL)Epb5 zIBn7Tgr2{#F=v9S?Stjh1etv>PQ-g|_)_pbeasFm?H0by@Y(rSE%F3c*<1>g<>S^A zQ7y*XYe9h>{zyu6e2epI9_Gn&A;*-3?$0NdQfkZOdCTH!#a3Lh5{m8~iFp-FjP#ne7Zc0BnRR@O@^_EP!9rP!XOrM#Ynr2>zF-6mc` zqyF!-EMnhLiT(N0Mq^@wbF}ZbrHZ?XCy;#y20cDIP~bh`d_uF92^xkJU^xhu0sk z;Txhv!tNp>Z0E$C!JCH`rLa}}SYohy@a1+>k9I53hksnA_RVcDSyPQ$L><8wb!<#^ zG@{r$uanMKrJ<0Np$Dv#EoyR@-3b5c2UwbNw`OXfnBA8f0eJQVEI-B_=^epks#UHt zU=M4XE7l|rgT=~ITiK3$V;kaMqK?K(i;GkIn|;L$xsH?KQ^^tvuDH_(xB)8T5H{*z zwG;(2z7m7VYJzs85vH`tMwr?v8zE&?l8unos4v1aFxeEQgULon@zR&Y^d{L9TJrU! z&@#F&LhG)+2rc3JB5awGEmX@9pWu7(gqL@ixLNAsJz8~dIf)~u0jksxv zj`GJ0TZj9n(F(^=Y)N7P)2rB0mOcKv_A#Yh+53%=`<6zEXsrT5HPn;0vo&7{<4!_< zDz>Mqfv6+$4%FtpC9c~MV_x_HueB0ecgcQ0pLc`m=+M2kIIy;SAZUN~4O+$#KS6m_ zl<63I2nhQ#`P>|B|EgfJy2Coa$aOgYTC5}+sUHLE9u%j_GyN0{%{>!_k!%olC374= zxtKl35Ap&N8S>oOn*Nv{elE`TY3P+rLOXlzc9PTcrh*P+;?rw%@zUE4r&m zR!F8)1Fp?8wdQ>!IQDy~U$gcY7kd_Y7$tg-IvUY*ykG>ZXY)x?-^yyPnh6g3;B)%F zra^sOxQ1`;x%?Dh7Tv+0?gSQ!f$^SBFVzYq?&;`V4+?Ig+<(!=uM0*~zt&0<58rlN zjkwqH_b&bl{2j|5hgmF)1Zq#&2VTzK^ZA>*m7i$)dHlFR*2+eh)j3(3MB5*w*q@>B z39;8$?D>k_zniu>A8mhhf5PVZ(e}p@g}&#Zq|?1NWp{Ef$I;RDi_09D`gFI52ywiUxmnI*#FKS&`5=uu@$g!E8`-X6B!$1}Srgc6H z55B&@0BeJGTF5g$~+%(l5Z_z-R1DLn!^$uD7HRLQh=_YQDa-B=_WMYF$I=Aa78r~w zR#e4`s@Nj2o8b8*V1h()P;ET4AmveJ$(<%Lsom?*=wL)pjS9qq%_T8Vzg#$mPqqF(rBfoRX0n&pR!o*g%r7M+rm5#<|dR0-eYR= z)|Y^mkE|>tOL!@34G+oVp?zCu8p6_amlbo(Av~I0M{?kloPI9PZvn4)+(1f~*{4P_ zHvb%xoTcv1@ithDE9P9I;!Z{ste9VoitT(>-0{R@JzcEuZZtkw^qwx(?!dB#ZPBsm zv%=+?@lp})fvjEPp()m$-7VXp33HFp4eN#bKmGMhy!Ae$my%jrVjWELJ{Rml()D%+ z=`x24${g;uT)U$pxYpXWw>)kXR@d&h%15R!hf61iCMJV>27%62uy?~UDpd>{zCDoA zeP=d{m9kUB)09%+v!@%z?BFiYOl3c$d-XLf@7IXyvPLMAm18Ma=@~6N?@S?hJ)O6a zqcMuZk)06H!%A8$fUs-$XqC>Q>Y!Rq`Yrv77M>0%EDfo^iTjpT>M63oHN{W~dAKrE zZ6ptsw<1rC^2)bqoGD5@k;=R|(FJ*IO)HzdEs%_efMqHOuO_Y2|Jl>@CN18gEFGMMlQ7o7q{JIGboD z-Jy8w$F5@^bIl%_6;h^UD)Vyer5GEJSn(y7&?GyLprjrwk4VY4i^SHzwV*K(&bw|<9lw(xAwfOxpHn)-_Qr8PXp*icZu$Xuwy;1cK5+LUUn6)rL2V)GowuH)R!H5^?!bzKEK31>q}DB z?)0wWa}@nDq7xV-C*iCaDQ11B*b!Xiq)GyJys#?MCpEX&5jY+NhH1>!ouGH z)fjUM#iU4NS+T4XER?}yVGtNW9Rgod?emZ4D7(kA;zMlFG+@2qu_Wq9K~p++qN zG}5ByxMNfsdT{+72C1(+j7xESMpQa!RAIrzE|K`Q?G~4Qk@fMh@wK(Od z9II0qDIX8~_8%7?S@Sx>0&s623l(|nc)j=0^zrfXS;ajYeXZBw%X~NHyE66g#rX@J zTnCg5#AW2jBB{(oWrAHE;d&kCD%gC@eb45vuG+~K;n*Fj*iHPTrERm>leKg*Pc1sRkeyVsb!bAY6^-aa$C_?244ks(_i?6P zWndl&CHjh3NQzRdH~dW8F73bz0ehD|*vAahbm}|*{s2_asnbKdbrY;1%(<)U_>>QP zv5&)tVwvE2Q&+{BVm|-0)cAi7#46UjjYV5%Tx1?#}Vz1JWz2G%pd0?5&$?r>) z+Y~+LBN0v#G{y?Hj{d&JLe!D`I9M6qW`blzCd!KtR2W&fFyQSR%K{qH*qU(*MBH8z=fUli&8Iu<68U`Q*d! zn}vfs4EFUKd}UBS0#VrgD_WD%^vi;yv3N;6#qvXhf`VT2hos&yo-C@oH?mds75DuH z6PK4_r(>_MbbE4n>XjZea1-Ya1GXO;Y?`U@3O^VvJf9wzsxB!)rp7NI_&=6$5oP>H zWh6FZBJ~QS7B{`?8N0*l+Ut-<0Fjul<1M<`sJf(xqHYs@n=VA!d;Wuu%Uu@R`YhqL z>gvK5P+-)GG4|?wFVU8y1j3@m(l{AmS^s&Qt|NO))M*e_6ZMSU>q$MWOAIV5_we+K z|MW(E5?#cmL;10_U8T{+Q5Z!nEqrWAK{(q^)e&`+rq%Yv43veZTPSL3U`gecS>PzS z`zPYKWlrz%TA-))dwj&olAH`GuH@dNguYbnO;q7y7-^1&h9!*$@{%&ZTwyWVp&rhiz-wjK%dIgi}owytL?%oI(&0`|Acy1vGT>nh&=E2zgySMZr6ntwh*yLR2?JT@A zXO4mRDj?o+3@4$A9kt8dB7C0g>vR7^AWGgLgwQ_ekB{N`Gox7nr284)L>hcU8h|ld zZZwMvBSxam1`^EQn{xjqOhvFyRoy?6!}BI@oAz_cTlfW)REveB!^njgze$gU&l9U6i$nU{`92?0dt{<$Gtf$-M zk~O=vSJbh@)^sFT^=W2q$r-J1!_8V8ql!{Ioj@D7Rnw6olJiA9(*AyN#~k(AqU3O1 zb`^iaS8MsyPJKx@k=-0Hf*fpc7Y~OifoQa3_Y#dj8V2Dg?rX~KEucj^J1sOkShVY`r*sPQ7#p*L&1d_4qly z@>;#t8mutk3V>EThKC&dFVvDZkx8jE6zZj;PKEj^MtHt*n@^)LL%gTELhh^3-7o2r z*v1W>w?9Ed(Wu=Yu>Z>DU2Ux?V4;oOabR#pv|WxtlM=$ZZS z^CK^Ly*1ay*EsF`73CBhqDe8iKIFr*(#<6DI`j8327gT&M!pdbN+r*5Rv4Xb^cX5F zd`me}qG*l!?l({h?p}sHH-vITkwn3+xa@QIbYjbk-=G156)spQEdHBVGJE&!Q|2bA zA5t-5fT+Y(r8G7O*^Ko>)QdrU)#gIQy_AG##rYL!CqEN-X*tQQ8i!?uK;A8oB9v?3 zE!@mE_jZ0b{R*QNjru7%=gQYevrP&G|6s+6PkG zfUiwagUZ-{i%#IHF&ZrN1+*%*s zLm&T!{u{|5A#P=$F`C{<-d2>K&M%(ASzK`b;QZo4<*!vJe@K4uRK3$Bn_ov}?w>!9 zY+5vQX7r*P0)9ZXAh6(msFzCfz_?K9wD`L4RRIK``xD@i@F*lJVUYw5=qA9oSG~k^ z`BqX-b#4QmTIXH-qV}(s=|cf(ZNpPc%uaYVhRGLPR@_fjQ$BT?AvxhJ!2M6!8e6-N zFB`G7i)rwH*jk0WmS{TajpCw#of%*e7t*~^MMvd)@&>)cy*diH|E7-LQU_L+Y9fj& zVJ9}!B)5|sFBZa%fq=dJOvx%h+{@Hi&hQL6Pe{z$z~rE=0-;}82YIAQi<-%;<8NJ- zLv~dcvWLmO_T+S_2Y1cpEId%oY%;pFyPoTZj<(BY>viZ9erGflEj@_V>n`6T?3rIW z(w@bR!q(wSNAXtdDBhc0CFdi{Z+-z~jUfhf$&(M#A4)LZH(^)v)gW`De7;GmSDJN%| znI=}v)c9@8JbLckv;c|J%NX`MvC=GdLOwafF?3`=*s&Q1GP1;f(w2qWY2egOeMyEH zD99yGT2}7xKP-1kf4RTym8&mlx%EtwJW*#5>%Z0ME1`)y8-ylJ&mtgbLh6S;M0Ige z_inbd9ELJ-HU66GCI{9-E#+o=a?ro*H#y{A)@7iuUcdf(*r5iO0QmS@dN37^zy-2o zkjb;~MOv4<2dpg}P0FY-Qo2enMk%NiOUc_vU@~Ohc5r{M@oE&~@(>A(VZ}5{?)OrH z-WXk?rp^gves;2~aqr_xtu%kIhSB?Z*EOU*&4WlYG2mW`bGU(W3)`?w2=ew>Quf4< zbrj1_3yoO_NvHGv0amRD91DK}veANAs4eV2K;avi(+jz0L2!Q%?{cqYZrCpAU7A15 znD`qqzVBW}V4&;^_bN&2l-S)!7F`3GoQpt?J=!VQqn)Q$rhYZ8Ug~^pjPX~b^>9>^ z#)=Ssn+R|IApPxM%{()?7vm0d z9<=#pQH0?lBS@tqMu3HEf~%hQOc6hh$=iXcwSV|1I~?v@_4q##{QG!h;xA%1Gg>Y4 z=Ix(^^ss_6hCW&=`?A_huFcRZOtadB^W>a1*z3D}oL_r<5zzmS(Tz&YfFGNf3k|LG z(hif$_PLj;p)3bMNAgbfQkI`)g-+izmf;#y9ur=hY;_}`XdO9oR`xsPD$;P?H&2-) zlH5jh7y$SMr(b7sf`&-ul4YyR=_kjnM&6c}mqSYDg?q>HxeI{#zp2M$x~l!wIJ}(G!V}xa0xG8g zuCI%dB5#8QlPuy&=SEtech9BZc3i?|S;a&?l9fr;{xS~0Nl>!ig%9#dn<}{mWAsnd zm0xqvGvjKUKd090@2P@kS(=avHnR=ojWZRK4^f6yn!Foy^+%VeG9wVM9;+5hhrBsU z0|n#BncmN@J`WlbY0f_~o$Mj-9#utqfTbhG8tRVA=ZtU5fF;p|L7$N;$`Z51NwdXP zvZ6uxoP2p(nriy1LGzej(#VeTog)~lOExA8OZzD*u!6$E?pdcdcmQOQ7&CO7F$vunS=L!}tQx}~!j7tmmu~re=RIR9ORHHbin&eX=1dL6r zWGL7Mv-`YQDhq{iJJ#Y`==o=KHcctJ$ElWTIY{nyhjiK3g0|Uesrgz$f7ZjZ2wVFv zbim$leY)aysGy;d!Q_qb*QFBxi1#03?Xh&CU>))|UV})XoZzk;OygXD7+p!|J?N1~ z>m&6>atkwDk*x2hY2%~ATnjb2vN1YbA08cPo=i$v(2TAcSydlN4kqd7XvM=mY97ui zlrg-mv2efeG=`SKnlNTf2!+;1&?t`$% zKJG@mnRF@gTV3JFh^biE?N zr-Hjgg=&}59mG$ltZxnUS4P-hY;3Bu%-rZ}>mRINV&pMc4~`eV$Qui=Q{%-i^Tq^n zcHCR(&&S5_O+kCr+$*Rd3ggXFh4*h-n#`?6xGYTW&m(yk6pUbIcq%(5xW@o_I`R~Y z5#Ae+9lAMDcPJ;1kTdj-tl^{vFxHHtQIA9+$J7S}(AF;LzttJ{*NCiywt{CdJ=V>LcD4Drp^T6|A7nMH@Y zY_8I20Y!NR5xb~S zHdxuLk?9+vxo`8Y2nHP4=_>KNFgm623mlZa17mzT$Ms&gT3e1DjlB)bZ~{&jad<3{ zUd^r8@6n?E-CHc3nz3b0DfF6NuVkBDO`9FYhaGWHw=QpT_j{(b8Sd;k4_6e4H;+#v ziHuE+*3PKc&X5dR%-uwv-)rMjdqg`<2E(@YK8crI#lONmf*xOAY#*Z<+a3irKN6iM z9zTON$KEcUT@xoS7za6Q8V&iT;oIr|P{u~?hoX2p9j860!R7^ME&8_=PKBA+B28!a zY>~z;5$iQuq@jqk<=NsS2xS|^PpM^Fo`p}oA~M)Q?9-HQn-i}Jj+$;4oj!~H2w~kD znd$dQIbL$>u+8-6&d&3Q^M?WM*?^7oN%10#1Mb{9%C~06L;I2Sw;rpMabKf+F`$7;)YND((ZI@qQkNP5*J9_@3=?Nhcbm%eliNTgoyeAKARJX!N<` zVHB1bBlimAkI_?8JM|?QK|eKJvbCF+$o~TJ5puQgHL;viczb*P;Pk1rvSMPkdkE-; zP}qz2i8Hx1Rtvc^q2AN6`7d-t0Ihw4JDQ7Um^A!YoL%W@3rhqIyY|KqG?Z5h9TAEr z`eN{UYBUBSv>v^X@^={?wD(J!s~!*S6Pm|m;ODTxCcohH@E=e#__>Z=1QYHk9xJ(H z32o%EZd;kZi9VI-)3@o?>8El-7XavMWi<3&_vSbwxQ5p#p| zNOmWpQfgtI{Pm#}=l#7zxf98Asol5mYf`!k5UeNaGyCGIm!S6L-$U!;)0y&Ht7Es3aP0Qyx7P`~QNb5OQOnxKagztA`%69p zW+;CbSz5k}f#H6}6o*7iTxiU$=JlP33!!^v9~RI#P5e8E7v4^0?bn{oMC{ZKeseW8 z5Lff28?Aa2fNGWaXA$520cQ}rZBuMpl}j5nq_iJu_AqtyR;FQr4NALHD<)qOo0u#4 z=Sebg6nT7TMCru7XXiLdEog$Z-^~Ix#fE!4i90$*s9PftX~ReMl{? z;w9;Qw%{8mkq6#5{d;}yvR~F!=(de=w z>Mj_-ti}ZQ_&EokRM@U9T(bdi!ankua8$8+i%+s%>69H0 zvtAXrp@!Ax94#HX2V6p!m7Gm6dvd*`J$w704GSyOpqcV<)hUY_tqtWdDrFA?4Vv%^ zs5o~XSh$CGi^1kvO%RBs;|tX>_Y%Rz8D}=9H26@3Jpr%n%R>IqjhQ0 z>LUhI7QE3=*BIY~k5Mcl^7VRs)T%>WHdbF{;CUDe=)r~qnByTU_x9w`SB?7|t9?S^ zAQp@2asodV_6FEkv>9YS>7Hc7RkVE@_hEp5geoeBSGJWcn z{^YPITAUdQZdN=~#PhAeh6ej!_`LbetZArQ>0(bRV_aRI$G; zqBy-HRN?+b6(Fbz6a-bJlx-1OStU>ElAn!F%>dhD;Zu!j)Y^aYQ#Y@_y4ui&O39sr zdbfDtH#I4>512Bmkr zqeh(Hn(W056z4y)5P6I6!Qy=3lGJ2?#e}JVS*rTmibe~?a>>rNrS_%8;^Z(2xT4p! zNK^JZR4{tlB^c*ueJ5`R#q|7J5yghiT@|gRZi3hJu*JBnob6j9dp2TfwbT=4oI16J zHIgh6VEMg*bP-|MJ(l(t?drbp9v)qo*sR?p*nAzP(oC*F67h=G0G0>VQ0_IK0zL(B zU7DGC>QW6^odM?Y-P5lZ;2zw)1l!skqC%z~a5V$Yo9-LJD%RvNw^_}#^C97V3Oson zX3k%Yf^&ab?w-9y%a{}PZe&LJc@|~Zd4zj%)42z)hv4|fSh8Ds2ce<86qcK0 z%BK(m^mHo4+|b>{xNF7bHpj!@9aok$=DdGS_VNBb_>?5bqv<}Xc4+f-#5@cRQ&|B6;KIFcvBB7O{-4$0=U-=o)bV6na zYJ~xU)X1^>g$_c=d;xLM{fa=TsG}>?pmmITc`#_=DlV__*t1mdx;n3l!-vu?n{j07 zB~9@BQo5@Ywi(9x9Yfnze#23A{rN7FXUAsj-t$WQq)nDe+?G(F}&d%Ps%}q zDlNl!vyg1kmd=XlkVn3nS_gP2?6g^kmw%?%Zp-0vLSOuYC7oNPK^>>H$-}9mwkMj3 z7e5L!LlLx!gGjO;K_(HD+`J&NhF{!9B-+_=JKLhZE4vQu7m*D!dPTE^+=D59fbu;h z?ukaZ0()0+Oe{ne`lylLOSxe8-_cxA7N(k`R+@NiA$Ko&*+I%P|03S*1;tsgdtv`> zy|;Vu>a#{tC#%NbA7^kc7>$#do)$O7?HQ8yNK8-X(qV+hD4I6uH{y<7= ztJkKR-y|ryRrcEumv3Mjg6-&Pw;mv1Lw*E!QH%PUl z1SuPc-FM-UJ04Gz&8d&$Wmj<>;4OTUv{O6vB^hJV%)40I@oe?Tz>L+4uJODNQ2kiC z5&3B4p2n)@|F%2{98=D1iX=LVVr+C8gRU93*tju;Th!IZS^hc2$OzKH~42iTj zj4;sDmZAEA74QoB&^R$0P2Z+f?(v|2Y3AQ~FQ?PYV31E*MVk=XBO!moEv4B*OjdHK zB=^(Osm`~+$!NawZ9NKU&H3I;<g#l;x_r>lzeDl+stI%`M zfwvXJ&wyIpG3sF||AGhyu^$m{Eo8k@6y6o_&;SbOj6sc)lWdeQPQo0?>1~?5{haD12kncAr@x&gHr$QUPs8YI1u;m5Yd|LK1GuO~C(e{UYy@n6o3=5x7W zjUV3%OnIyovY+)%K4==X^aHm+ zfpcow_{ew|xGA<8*@0UQ>1_O!LaRbty^$TbBgs3!$(A4Py8nI;PlmE$cNlf~Ew9bL zgOo#EKE8*HVrw+*)zZS`Fz(!{krB7tRRiUgTl>zY(1v#unOVT$E&C22-x_vGMZ zc9Sg+0PziYNb+XJEyUjA4rZi+2|&Yb!yHcn%I)ZDV0Zg~=AGhMyRo~Oh5hvH;{I>0 zGfqB~3FlOKvVV9q;T@Nd$he*lKcoGv2LD2;_Vm5@?LiW1!(zv z53a(dF|0n8=NfbsJ$@+NiC@tz)0a%&#{E`onMtvNb6>e{TzVljMIHSHhq|22dJ!Qj zuaG+!+|=Qn$@nU8!-;b7^n9_f&<5DZ&brsw2$;G^Dt)(_M5XQTf!4@wve&UZN5p&c zJtrzGE(XK3$M^Gj2CsObzeN-4L~PV&APM zsy!UJaXrhCThEjD*s@K3lTB~VleJ3dJon*?H_%{1SgG7vej5w_!QSqaH zRS0$neVHfQsrIM$|ICDc#(OAp>qmK?!+nS%-o!hO#4D56@v`;oUgXTg+(UinE&B3# zen@4=ym0PdzHns>oluQduE2DX#>y-1KB&m*)$v9$OV`n9?hrmq=eJW5er;B+C_9{0 zv1-BxSTUp;L-SKvE8?X=s?W8Y>k;9 zambEzXOgq>*9ZKVDCD-%L1WMvE(-62b5@ zw$K2sGeTOkQyOS+#Jf;DpwyGBuQaGp)R`qB)x$+Vewy zPqfxWCG*F(3Ouq7<=CJ5Ia5M%AYERI@XmogjBxCJX}|x$uluzU983b^ZTTEDn9Jlx zGndKl9;u+EmcDjb+AI6hUX@8(%(eQ<{j;jg!1Wh{=&yq4-Y!Jaacu0*r>jP~`C@kt z!IC?#Ta)u3{!UnvZ-;f|Z3JWY4u0Lc_2nSzM6K1Q3ZW z)HXnS6n6^|ZjyJSo;T^U^%7Xt{NvZ&%i#KKKU|+PxIQDeKA(lFnA-$g<2~9GXVn!h zFt&ANE(`K3SX3%*8~3Bmg5qak-taqf1n@!CF)+&tGk)jZSzX4*j{f)n-&E4 z?-vA>0KfoOMA?+-D@Thwf@sl~GR!Um9PkV?2yTbUAmac*((XYb8ZWYA)Q3x(&-Q>z zo6oZNJDPlJdu{kLOPeq@#4i4l2CYd0MJWDHM3u_1`vXt+M}0R!(>R-=tPHPso(8U` z7Iosa8q6Eefw}KcTNd$yWt%9(JtrQ2*ciXb%&~gkikO?5lkSnw#amx(FOw1^X0Iyy zsaNWFO}*X*?+TW%Bk_200i$l9c}aQuL;dI;!7{^jsS+&#t|tSX5wNdDqLo0RmC)}x zwy#6?Rj9t!P)vA z&R(cwzMr`BLEV0R8Z$6ALfSrz8Qbe6h$f!u1E0jUD zpn)UQ#voOBSo9X5o?e^Bd&^MwSj;U2D5KDew5@%kh>+8l=H?+w zKL`3eKH9&V$lD`r+w~V|FRwe)=I_J_N4WbT=}S?^9fTY&S(4r0Lb}vY>CVe>ZjQdS zdEfmRJ~gpwb|tPUg^8nu36_aLC@d&0Wz_EPr1c2j15ba|iJ7E+{p?<&IAb$i9#gb6 zafYw|9Wka`g|`gGDw)XG-77H%zxiFVguY4~cj=oKw0gQ;r+*_$+#@w>G zWp%chtaS;p*0tYpe%*R~?{7y%_Zeh)<(rkJk5~S48Z$8WBVg_uqsA+H2{ODgrI|O8 zdyh1u`%L~f?9dky$R*t;7JZlf2sRs^)zHWPUmoa%khcJL?A~g>YJ)( zBfAsu2fUu5Ofe=^9jiqn?DkoNaF`0wd8JUqXnqWVcm!rp=tdPQZT2$S`;}sZj+khK zW2!FlhTR*#uB^1yZ>9EV#W+NE?N+P6A+iyJ6gT9L90u{L5RfE``Sx%K_(gKDy%3c$ zQ=A}>xGlayd&`PN(6LsKhhEo=M(#O>Uz)8&t>jQXL)H7j6LG+veLtNh2< z>2wudz3ul3`_<{H*y(gtY=_F6PFJPu2mVvcT}EB|^y>QkI=%e=KX;Zkm2}se^g<{g7z?HUc~A(Gk0A`&^=CZmH{{g@3VPs=)wC+uDbJi zf;{yKA~3g$IaJ4$gZpUFQ$Ueqi{!y_do>Q*K;FwqRROe@@pP}^XBvm6+16n+;!`D$ zg5P3_vF}AZ{0gGnThs5hmb**r-Q!Q|G95E=pUkj)+7R2_9>?l@NtFDBeb{RAcvMn< z<&EQ5(q1MF)FQ14USUPv&7{gP_}G*z1uMfY)Duu5fvGeJUesHIlA8)wR zw{n(-@1K^1&bOw$&+3i2<{7yvAm{GNc2lf$T|h1-&D zjQb5a7KR~!Y1vQTQ^bC{AN=2{$dfZ!V)sWD0m4x+cLQ~7q>h-Q3y+ebEX0=1JkDO2LPZt_ePSyu0KeCi^%>CDh4a-JVBhtrxJgchrfM!Rwh=?Y-zgC zy7Km$pcgj+8PW7QnA+HUc=wxj=WSf`&Bk@}@a{Ku&bY?R=Nqwn821?~C~tqAz7^R3 zX2`fveFVS{1K^g2V<+U9&o20itdZ~MY58Plyn?i@PNAVsH~A-t}G-JEPpw#bAlbr3DN2V3`igJw^M>Jjd_*)hq zvGDO*(gb`whVv{I_i&i4ok2-16|sCb8~sea?Rcg5NqcK?^pK6&Sb zQca+Ve>H>1Zq|^fz)tLH&JLKYfEhFgMlE409!Ewmdl}&etOR$hD4cJe6;V4((@c7;%C7m;QJ_uQl6b z7oX=Eb@BO$%Ivzx-A6}N>~6@ERsV#}*f_3B1;umQcVmwuT0{8vq*fMJxqwz?xJoz9 zIX-x<0>Sm7FCto$)Qh=7F%Y?8L~s?JU4rW->k?cy#*Y_cdIe=gI4KIEEzqyS`q5_h zZcKM3utc#tPzn07oVr`gX}iUovRe$U_m-7|bJJxpNA4D5V}*k;0#8Cn7fib}@hhH{ zkLe?3;j4JYuAvYBE95qh)5b-9`eUxxE#@J+#aPu;*(>Kr(tJg7&yek*9{>#%+_`l& zgmnMrt`*2Y1IR$NYQdewjg~BBYXx_-8@4%<((EE>b5~Acy*OwqtO^yVF&A0l#20qW2odS>t2<)@a`8=H+}Rf z)-O8#`VyY*2@q?P9JdMDKABqB_#B>1!4(e`+yy{B#OiE@ z+ekTet9o#1a)Tb@ORBw)e1kSs=>otW!Y$3SC^b1)$!SV{e5jN>(E@qio}jnR={TIl zD9sX{+LXZBst%P(9J2l%QlHKmD%Y=tD)H+-15c|To}qFdKtlr_A~1&+qSE;WSTs~y zdbQx}=(klLDooytX}}PNypsn}&&Ft|;(^fJkr#mZAtbn8QELs4Xlm5t%D>-#|M?fl zdjJgo{1#Wq-hcmn_n%*jhN|r94-GDFtS@Nbf}tU6vjtmK8brjNn~o4(9pc_f-*j!& zk=Vc)AdjJ7Lo|8+y??&{e6y4LF}P?87aXYgZ$MmnsaiE(KL*D*)S zs0lq5XFE3NqKuC~**E-;rChg4N1Yl)Q|rbj;IBdq_MU5?d+B z=ingi(>x6#oj-;C9}JmT{@%q`U!8xo6-IJ5mGSXYd`!N_j|aW%o=Rqe-PQ&xnpw)HMYy<{Kw)Y=_S(E~Zu zM$IKu*-J0HSlvy0~e$*H-?ylE?_e=T+V9p z#s?{9Mt$bXsm%sl8K%@bLXo$!n~nXAthQQBj%I8`SDnRZX(TwrsE&uJIApoSeOF`* zLXw|?ob}AC|H;$sOYAZ)gSE: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 IvXO`{Ekq4R`vcu^HxDvs#7Ev~A+ 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%0A(0;JMXidENDua+Hiks? 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ૣ?~{7P;`d7VV@@%lOO4|;0&i45faXDnvsbj$Ka>N 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

iTlzIY^8 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

uDZLVHMvAHxj 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

)j@74`5Kn(OrB~kq`{(hbY0;?yB_BfN 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 pqONKc>GS_SjrLzDxBTp~jlCVoyE=&{D zOlAluDjFgvDk6v?h@zq*0{Yyy=M&M0iW`nT7gW^$!yQy+e&6q@y4|-Y6Nt>1BXBuF(04uDh$(h>5RZ_`~}c zJ1)_{9$44B;n4(3 zDxJx;w7QXBuC2Wz0>asuZ-$$p!oT|06{Y`o5by5Mzi9jg+`W*Kxi~BGW^qt%CM=dq zwwg;;+bARa;!VFc`9-{1O)KXD$+na6mgrB#)@CXa-w4P!Zpgn|GJun@H(l%P~_bk6;%*%9|i&NRwwtTm>B$4h|)ROCR+j|R6Pu%Y7 zkH_NiWHPz+*H?f0lXt#s$D+3lzUh@u4g6@OF>I6!-`Lk!Wvn(%F-|ikjVYsS3>igZ zBa&o2Wd91A#SqFp3z*ea`d$|{dOIVBzXJXi<8KguBltTAe@EhP9Df(!@8$S=C;q;G zzyHGDAR5&f`1=6+{#t%kAdMy%Jj0W^uw4M^=`1KaUcp8QO zwY*`R(`y(%=|^021pyMBTLJqp!{|G~Fs?n*FiyH0&1eVGzsoSL`3iXWqhZ`R6f@q6 zgkSXTm~qh4F{AS=(>U)3rqO$eW$e{&8)y99Hh%L&+!!2ijb%F$#zBX9#;=Y~8=v`7 z*7(#Xa>gNRJB=4??>5eR_Y$M~%X=H287v#Uf7#!7-RloAUUl>_M)2BGjBCDk5#?o8 zvk8-OM7E4K-SR;E;IXCeL;pd4_~>5_(xU+9{l32QxScz9w$j+S^T{XiKm5U$VY9pa z?c90Y&c8ilxDfq^j3>ibyGi{Sl9d?G7QP#@^lr*>1Ng@%{$sJ`aTm&BkB9-8d1x>` zkC+DQH2+S=!qol+zPs|VAg8FJf7dUp&HtRe`y}^_pV=ponVtBzz;8j%1@OcxL%}r@M(n6R)4?_`Gzqw#x&L<9-p4dgv>?Vg~-X2sRNkh>w1p{rRVq>0V{cL4}wz7Y4UK%frHmoqCO1q`b}gWxkrJ(|91 zmW`-US4dGB76U*vq{{>(k$N$b1;k*a=Ja>1{yTVOt|LkLBaqZJS=!O`RrV$MCOo3;@~h`x5sswO#6iSgIZ5c*(wC~* z!21`aulQ=DuY^cm=qJCr>)G=kM)@DIn}qzV0EQO!DDo4ARSfL|0n}Y}2|P=_Sn8^& zz*M-T85TEf_6xc-Mbbx7;!A`u-Fl4x8_$yNvjm6n7t9Zm!$16_HzT`seg#<2&iXoB#FJf}-5TvyqKmf)@6uM_|E)bxapxJ?z;Wzz?ge zpoTCghIJXK3z9-q0nL$~F%jJ$6gkxf6uu&>^7f1rB7s7zPEk7+7SI0Mrt=EH~pTDg57KHg%ZH z*1x2mWMg6Dt+$?knZQ^Y|KmSspu6RvUI~?C)le0|u802%9VE{In1BC5vhzqWD=H)N z0(J{Vvi*OHbGLc@{{#LPN#MV)w*4>4l&T zPG~!&?Toftw4Ky;TH9G|w~FnFWN_|9+evMwwB4rdc5NrL-KuTmM(E(chS)9I&Y|cP ze{D+#jOu_rAO+bnFn|KdR0pa9;&T5n*P1R=z(vO`f*CtX%r!J!F`YHthS6DF9BVg@ z!*PXn<0vuL>;(*`6^9tA88KU81@MHb654BG41>v<8ykp$Q`ps*_;)nmfledVf?C!| z2M8#;McbVSl7LRM0wQ!)TL$tfMxKspwyNw_ZRZ(-0r_fH+pV#Fa?X=k%B;F}KQNqj zV}N$QvfGVn|I)Hi?PwTwh1oRtJLty;{BY5=#c!ZL;qeakD{?3yX?Qr(kv1~ug|0T< zZpir&9E3tRq$qei&cuF)$8wB;VWilO0v$F?+ST?1PGTT;BQay~5@TQ#!KlmH&S*QU z?G|mfYP(I_?P9aOF@6%{m94^AFA00v->WKr)=T=Qw0}zbv;NXQt^L#5pY@ae8SS6Z z{;aR`&uagy_GkU2e~b2S(f+LO^l#Pvt=gaMgZ^kA_A=NG3Tl6rfW2Ixj)7IMS5=p5 zd&SaKsIvfAw^mhG*#|2$d$mSi1A9$%<-i(Xz^<-Xa|m2EaAW8>E#;~n0yle8_*M_8 zx&wzI)}hq{VVkt8E0!K+R1aJ8C3w5-#+tbj(`!dvTJvDU1+lan{)1rmLHiv*b*e_| zI{>-Lv~QD)+%D!F65cWJNr674pw>?T>aag8exDKZvl8-o`*Q+)L7*=#{i0EwZ`emm zSj=9l?PJ7#zJ09NtLztmQwKThSfgCAs@-te$LY{j_6dUDVZTsp*FI6~jD3>!KUwVK zZDpqhUIZ8gVy_bp*9jdAnfAEgx%PUoWA-UxXY5nOeqQVW*!QE|!S1X+fZnB5TR4}B z(T>4R_5Oj6#;mH-S>0wXF{<}>Rdl^e-T(l zGaCn-P^;cA=G_vf!~THS8T*6uZKdhj9}T}?3rsvtbLp>)>aXnIkZ$!? zt-pbnJ8+uNS~YN5%s`$uqPoUfNgU)i#;heq>k{}Q45H_?5wt1wB4%hHf^_SJE!ddZ6~xH6Ptr2=_R%8X*;Fuw6-(a&T6|w z+o&QEzfIfi+RkZvK-&prGh>Jli=k>VqFH4PTQ#r=EU>2SYAXze{7<>i5agc=9{xGE zXe205()nlHsAc%)4qOO2q5A>@lEpvtxlraYM_624g+2pV7Z@t7c_Hw3*npd2z%#Ln zr=}u#SG0kKj*`hRB|uc%HAHOtBJ=@{U88B%jB0A&GIR$HS^;%7^w*mu{KYf}E=I`~ z_-`N(xiD`p5x0{2O9n16V%0G;0NPG<3^uzSjA@ zun`vftqJzgowhECHM?;ZmHrz2iGkk%{dck7>Bxkf*zY2do7`b!h5ke<(N7=vJT0-EPEwA0g7@4vDA;PqZR>XLSQc9QzMKVwL?zWe>a*b_Np|Wp^wHbArim*!It) z%pR-8LKj8M!4S~M7^eLnIl=(M|bLP|9h?%o=!4Q{e&cz7R zjESjyEOX8jf0*!x34fT%-!|tg35AJJm{Kq)i&ke^k!F|#>6M4CqQD`bKSy6rs~GvWF-dK9`T#& zuFiE20Ej_vYIgeYr8bpNc6VsobGXxjjI3HS$64&$;F`I`)Y9gbP)(cLXU*IaHlew_ z(Z?J`H(K9ZpTWSCII45~%7s!Fy^=jssya8oP&RmCBY`pPz?4z~QfuaxDl*~_GIY%+ zvu18Di4S}_m>OO4(d@asDFSf1RCptdWKm7$29<2~LN7iy#5@kg#0G0ak$z+zpnH;| z=DI)!Ql>*na9`%io-2kHGZ%}^?E^Fy0vnj~k=~pSC;qnrq8MXhBU)KSE0Z}?)7aby zTyrDUj=C#m!w*Rq^5Z=U-lE{`3ErY88~YelxkE86;g~m9c}Idat~B7zMOpB`p8V)f z2kgZR$Nd1_ZxMXGt|uv}YazC6@ODx*8#m&u@i;D=z=5kMalyy639(ygo3gIB#GGt1 z46g_qHQOtmZ2FzBO>2tYradLTz;EBrGSY-r(hAOZQI$mYwB*p85DmLH=#lQg69i_e{4HOY_B7m%OCTUdV2Z;~J5?}_|KaL?oi z!Sn-}RcnBDqiWF`f)U@aUZIpA7pz#%mkW^{q0}rF#&(2qR4&;!mFy?1QDwodx zOkCO|7m2uQdt>a~$R!nvwl~J#6SS4vH{>F|pNt#i)j4Z$B z4^48Bh`Y)~;w>zfZ#2n;@%Kb7B)F$?k?|busM&6e=TLd<;>WD~NPgn^mT`%-9fMtL zVjRxeFp}9~my@P-E>$AC2n|W>rJ-X6r8Bmyqp$}VahKEO)4I>t%$f zmD#f~sAQ|Pcj$w@Msf#P9mGsA4b#{UX{4BjBHlgmMu^7r4+aK`%7@nL`M~jt&3^2; zu<2{lhH_~mHEW6!$)pKTn2 zxcv2Ai_)N0s#rb_7}Px#bi6=a6K{d+ZX4`YG<}8BqanfZM=8ot(_e`gwIi9#sDB_V zQvrtx5DArfa1PSPz8lI&%T1M4+G>kQL5+K*gm&uuWZJAcj-_zYz){Y0!aBfq63bH) zx3U>vcgox1B%JZu0c7sv7DJ*|oayC+r9u?JN6bL!NnHU(w0;zeT5UDg6<1nj#mbjr zg;0i+e?Q`}9&0qu+>VOaTh2PlA?2{H=oEWV=T8DI3MXe)%zQEL~R9C$QY zQg!ROu;H!Jw9Fmn`yY#;r^=`D>5^|I-bvz_1yge+wN#?8E}d{jzv)s=mVtsdFo(%O zPX7i%Wt|g%9|xE&mD^1J6L9Igj0`SFTjvD0p9F5@K_#EHpp8B)DxXtCK1&n9sdf3- zkk4SUoVAjCkHc#g$|LiI63S$Fbtn_dfG&t-1tZu0g|nPBM%x@`5-%jlj|GT5kU~q_!bH z8#_VDh%&?&(42m!(_*;(XAmQ#B20kFXG!Hh5tH#Sy=#t_mw2B8&e8KDex4D3iDeJl4#c!G#c;^4mZ^p^g5cnRai3wtq(4a28D9`%dvt(^3?zasM=F^deT% zN6Xf~&SDuC95=WUX{F7Cj@@dAlpT@B=#NYcQkD+dWzd~J2#0WEFvk2} zMhvkV-dIBrZ?PNR&@{wb+iHYw1ViJHV6jiHPwZ7UZQVA78GdwPFCa!MvA5Lc`-_2v zJe8=B-mEIh)j?}o?sd5uTW1oPUlQ(%q$emvSqR3Qk|A(N#B(! z^}Es?l{;)lIx$zw0K>3XvGeJfvZK1I?`S;wbd!DE);6~-1j$^1?EUjowFQJv~nkt)O`{lz$JRNkCrPBNttw|lV?LIihsrIlY+YBMaKf>4P0 zWo_mp^WZ4h?~EHI(@`>wu*;e#S@813#(%STl}_+EasSIKACZUUw}PT9r4>K9dj$JR z8-g~?$uodmST{vW<;OIz9%7)i<;=~*sT9mg8+55o0*)-tb%^3wC@wcGe+NV-o<$>t zI!PM*+1-Agxv}g!7|*{JXfy3Y_D+G`%TBl*;WLcDamg@Tqa|;&uQstT4LVTnQ1ih< z6NgG%T6`%NswB%{|1J}~my~iF#t!D+lI)=q^Dk5x3&#wPG)00@}<{-Y3R zr2e%V`F)MV!Ki;bLb+!b6g=Z&=vaU%3Y=r@QQ$;mtvV=HQETMDNM}%Pi2z;eOR*l$ z>7SeXuPc@-%X6#|(?Y%UU&ahVZ}GRlp`|b7c^uNf=p-`sM8JOHwH4?k8G|(yNLFsY>v3 z4yKP-?^pGIE3P3Z{s__DbFHTcC*%ajD5 z6?s;w)ED2iMhTCmTU1)k=np#CHkr-|u$$$m_$gqr_4kQ$+;j3H4>csYUbpnZc$niU z=6KY!Ft4|L0Td7C>%2B{qGD81R_Ac1WE=yy@3zYa6+E=t`enTS<$Ne9G7xrq?Dz9R1e;lJTG9CdS z`?%;Y{Vd}>>ig{4E08Suezs=IQO(cxd(avkTlHVX6LhGqWPUH3>Mng1d$M9@@%6ex zKt1|0xYkj%r#-GBf3X=Uo*zwVpLkdS!-#PegX;;7@k+>+KV59g-QHf&2~;UYn*Uff ztS4$P(h)`$YqHuZtkbnWr;WLO`iX*;`5k3Lv)l zcCBxc(2DCJeP?qbX7r{L<=%vSv7x57HY zYKKx!wXr>3TAGWC-iTuv(y!)hELODJqBrCmQ9XchAdoBHnn~y4Wf$NofREM%AQiT> zzpY5RrFPQ-jn-IBYosg_xP`_~LBjQ6SekXtG@cjhzd*UK zQbMViolu69JM57BZJ<)zq^t9&ZUvTYLoJdZu8W;cg7_&dqnw0#qVyE)k&f@8uQ08U zXrdPyz;{s)aZp{B>`Q4-mxCSm7qN-5A2b{5pi0?5e>$4P7s zxPdg(cu^k>Fdo{GL2jgbcZ1{iv|=%e2^}J&O5>5ftsX5puyHi0e9u+l94V?w;Gq0G zsR9a?1uTJOAeLI8qm16B@~;zi#zosw*bDR1RIL@qiaT2= zqboyQ*MB)HF8f(EPY`*8_3|0@XS)z;xL66onT*oB+)_Oeb-KfU1=Fa*mV%k4EpK1` zU1??;)qTmXi9Sv}ITO*73(LAxgu1TO!uiqyQI-Bc-5%?BdR|j;{5P0rQ%ZK%+EAnQ zpsA~y-v=JBtR!u&J}+qKsu%9{&{z2T^&#ue*HbNLB&~~7X{0LM6-d|P_#JI?eY1uj=>&X)h5q*8}|tZ2TqnI?1-S!4DeW^f4nga8(|exyA8 z$6(jc{y1y%ABlR((mHmN!leD5Bh;#WjXA+40HN9kvH*ttn~}20$FTn{y6-~9;D2Yt zeMj9LMrOu~r~5Y{0I8e<9wrX3v8E5ralSuyzm)$G{u_y}M3==%2$yb{2}^NwObT9H z@5kDOu@}mblYGv)9JSz{G%G;m%8#_QSp6Mt^Y9#EnD|TJFN;5{2n&^d*hBa$e?17BO!X^F3nTCFZ+nP6%&}_0H$$wMVg8seZu{*wqm(yQ09* z5B?gt*&Ah8tD;JH+*9*vhr&oXX7F6tD?SbchcD=QX*UrZ4*S6Oz$?LhF)x$w|At_0 zPIYzcDMAxHrIb1orzpLmk5rbGntFGC4HPp@`7Utd&!(P z@qS2Lb`<>=&@biYQUQwJtK@PiA2ScHoN(Yp-ar!5Ft2j^Oi!CTn@7coDQzidL+i1X z+X*l&_3{U=n46n({TS+wULW0HZ2Xi|LX_rV#x)OdE0QuXjpeWh*)KLShb=lA*XmdDy{eKyed3)Gk#J%^^vp5PovTOO~BvD3}dE z2D_TymBtaC%|mL~6(-lN7o52geKtiY|nH1`vm$>FBMt zFGP2hglZ}xU)C8#X*DT1ZqD)V#b`9ttOjE-8qFUIK$euF&z9J4bgfW)o7lxYL|M0bovu$V^KRDCD~DI)Ui=x zpK-?mk^sA-D)) zQwenxt)jVo3AxZK(V%q{7JKnVq9k^&_a#Np70p%U_!Od47An&^+bf(Zk_b!E_DOZy791Uq(CF43qq*J$ETr%@3sD&7c;j^ZfLfrIS1fU-Ri~JjI?2)9}&LNEk>5Iyu4OLaSWPM;LDzM)&Quz z1f=|rPWSpVD;Vve>>N-E!oZ@HLpF-4atf|mNOyg|e^B11m4%*PNrVd1~X-%$#HAMsN zRdmyU8v?bbXuypoZ%@&H`w+Tm;A9ROiEVaFRcYm?*1#&BiAf>7{ac~+RT9{cvyfQP zWL@T*rd1>w@{)D^41z1I6X%?UVf+EOYg8AvSU!%DI+eWtR#=v(mJ>gMcBYCh?t3cq zYp~)fbP5DisO_g2nwq#P122@Pw*{R@H?}geE$|=n|A^p;H`ei6Z2t{$FxvwM_x_g* zxAMS76ea7FJG1D&Tm793xW673Te>1Ud$8gRO+(4hLW%oW5OS0(vyPHi))kp&?JO3K zMY3BdQ$Gnzl#^{hvyop|PR~v{uPEoAfv}c4ddetmUF7k3Y(qv7z7wi&aQ?>3CRBaN zy4a(cWYsCi7ELLpSjfh4`ev6*U5>+K{?8zEbK+YNS%BfftC(g{odmiIdnmSf<#u!e z@!3vVMSJ?&4z^^(%k-Dw*oL^V+f+`O`QYV<&*N+b?x^2LVo_fn?Lr+h4a`-pLpdFVKo&uIATm_(yBEA5#rrM(_VB;h| znlKBY2ewgJDY%`=ra+sGs<_3J*24o$@qTtKrr(aTR|lLn5{-i8-j>NTIh@&GuFaa_ zVF!{`Ge2t*jb6ws$7yy~f~V@z3LAPvzbSyi^RYVWaK=TUI{rs7Bo3LF~UN<}QbO$l4&Q`J!^B%$GB3ZUX)-fGKt zNFZm7;V(&pTU{1~@zfIEf&|j}OsOM*9pU7-oF@w2ff|x5tji>qjQ%1K+yO|P_kr?H zeSl{>+(PZ6D9>Vqd({=IHsa=0u*!@j)hKuk(kkO)H2wf`RSqezXwj~Eo#J22pnwod z%&}opx_L{?v3`}s0NpPTXi7q5bkP1%K-^N5`UJg!^BL4TRtZn_{VX2VEbPz6lq2c5 z9sUQXRO_JfA{|t2SM^SfAoGy2X3&Y$!nk0CphmjN?C@_#=U+}u{EQv!i`jFV!Kepq zVQ=!tyFJi#jOUQQ;I$A3)Gk-LjFRJUVpziQzU}ZggE7Q1gKOb-!I-YuX0QVu()3uB z&ERzaYjM(kY}bfpa21W*7S;gf@ibUv@mw>jh6kq(kn+Z=l9Dhq5c&eJK0K-G{Oh3_~-ghm=)6 zCrW-L>#9Cq7%HW~68k`5)haJlJx{sEo!F}$8z}79B=4o?xD$B{--=@lh{z$Q(Nd7h zvdB1n6l&U?s76rP2FmbT+whZq6~}h=N*2bz*Cq9k66!ho-0l107^0duxN^VC3ErWE z&psAb8-A)*3%u-QqIjiG%JAdLlOg;K>^C0h;Z3b%fFd}lfvyd)iI@;}y z_ISSC$+x?03Dw)TC6&Emt%(lP39dxl=qnHF1ya&T*J)t+=0XIIq(Z!dqj;G*UM@Xx z64>wc&jWV3n(SM$f#*?SZ_MN}vIyZ{gPv{WBdD;sOk1|C#UIst=Cb}WINR++u4Q9- z#l6HxPn=UHS7`ybxek_BC;R#}_5OL(UnIb;n(W_(vQ(tRIgi>85Q>cFeAFo^o?Nay znNXPN6`x{gdg7xEg6op1LlQBHa~?qq+#opdjYgDsq1`Fv;rIQBAIiRjl1L~L>C!qR z^Pi3IHAn{4K=Vy!b21el^qy+qBMn#6BQB16gR)JRt}2Jz_4M3a4g*mRiZK#yOUTdw zHK5(YG9AYYx>FXG*06?$lZm-x$;>5kUe3w6((4`%cWMK)gX3fz$R*WCP>G`j|W<39FUI5V9^)s)Xr5geo8lha{t@t9=aNZuA?Lb7C@~ zGmb6stZgQeiSghnw8P_ZQZ#`TlLNsaw5Gm;haI!841J78=lYfs+DD+%&A$E4{<_)M zPoova*K0Rmc#yF_ZhROO4LxuUosX5@bW-1bIEj;ob^}@EDHAO(sIM6_7w1-VTqN6$ zoc0Y5+c~GQ#_bt)k~v$dnPnZ5*yKQiJagko@Y`5U+4kBlx33Q#CjuDnUUsect+etEPHMOLc&}PmH{=AI7?g(wAk-(0xZ%%};cvma!VM5C~Sp-`6_EPFK>X zG{{ zhDW=d%#X%VC?hR8J8p12;^vEPvgb^Q^4GORwHR39zFpToxVAZN)O ztQ^CDWaSmZY>AalOE2_|H#{+a>suOp2=W*zpjxfi0UBWSN_eCbefu1+Z=x?bemK_| zu@WSEIO|~Z4=vwFpc3bSHk>ORlfV$>B~ZuF)t@?cu-SL2B8zkFLcTO=P82qTszYgS zb7FA=%9|5=HK0ToM>gUW(}$dk3gzGySIDk9Yxq2HQAM7W{)N+DW2S7phdDTPtWzmv zPzn5%ltNpaU6k_Fthx5+f5equhbD{lINSIu=&oU#TdR_1Pl}@vYq46q?nEUY&*>XE zU@r$kYH=Wk=fgF8)QZm_q61N^M(FT?EAA2SRH7U_Ty*+Q9UffqHu1Z7c+BaW7(X0+ zx17%320M*EX!%BI8eNbol%hHDrJhh~sP+^4*5yQ~5`nC~gY31zlX7gjlMEY{y*6R5 zRh>~^tN(gb&rGrcb;O=oVkZ4J09M-3j59>fq>bu|-W?4Y6Ir$P_(`MmOT)<-Mr?H+ zKk1mZaYaSOfJ?#cq0+WqkijvHv5jVM92}lAvGWwJ&%S{z?s*FG+3aL(xS*Fq`-X1` zu7PLD-En@`*xoMAZ2NzJmSXwOuj zS_6d__0G$fNwoonA*;>yPXsQklazI`vM~9f=ZgRpB(-1^IRk+c5Ky^qCX3VhksU85 zSO?7Z_zZSP#^HK27gy`JCU$6#y)@kC>M%B6BMbjB2k8Xwhm&_xwzZh$lR;fJwN(F_ zl>I@ho94`{Et_=c=y0jUspMoO&rzGi>yhG?mbkwbvZ;7xHZG`8-%@V5+YKXdanFrJ zFtIs;h-oaw9b^|cfrColo={!=TK|tguL))3`YBBRD$DhRVaagW|I_?X=q8cqsa>O& z6TINC9fL{1vG569Td8SC7OpHbslMb{HJ9ajtl2T^9LfYv1%Li?>Bn`0LC6d1#+)~t zh5*Xz4&)f8WUYz2ipC`qPoV1hhY?-s8Tb8Oh&V?{{Wu*_SU)x}YH4po-Ut`2(gbI~ z&RD1vXTnj2qGr$Z&sak-4mC~jOz{0=5HYVS_Bvqd0|+YsHOhV>SNnYbCZ ztg6bI;}^y*1GSR;o((d60~-osBW7?8+~6I)=fV~D&x2VmMEze3A6xt-Bg_ZZq}Yq+ zFf`~(D>zn$36KZ%F%dk0wzo073GwsjO$bhS)qZHwSUjZms>s{Epog{qdfgGkvW6Iklr%?$WOIM&6D= z-efo3oFukh%3=&wo3kM}A1&FzA=AwmAWb%lqt8BByL!)Vk{c213eDW}}x;%?8xZy_Fa^O!4@?uIh_{#f@@ z8R81VE0BW1!@-ABnOh!-I9)k9LWkvVq|d179|tb{^)QqU$Thxp@?1Uv(eO^Cy6UEN zL1)=2m4{Sm$i)I8?gdc;@+pdPhnrv4fg2_f@sw>Gq<+NAyCRulhf1S_G$11AUoS?y z)|ly)dK_`%K!0y=H7J%bf;s*;g0V#QlYE^~GE`iT%dprlEn^jBBVp4&otDV_{h)np zUFM!s7(E{g?+qqTak@scW})FzNt*eBVy_E}2d=*Xw4m3z&KS!klEI2YHLLVkqLL}3 z>zJiR_CR_>lkQtNwzt!bl)9Qz>QX70`EKPK1lr?MRGY+Qplc!1K$p z(R@_&+FPA>?i<{Tyz^)J&qd*KK5j}QD4UBg+Oz8AmmQ_4^bJGxRMl~~Ngidhs~Bct zc&uCDbO9%lld{=el!{Y1Lem&+jdE8udvtz(B7KkcAX|!msrhgX7h*d;$H`?2jdL~-F=oNM-wC>Ta1}~W?3&3F`IY(-dTCeoM z2j*H>GY|LcEjea@(+LTuXS{272#l8&_db~i>KBoA4h=$jiZ-Wj<#5KF zMo(#5{wq-$jEp^34`r-Vv5J;POVb7#5)Nm3?dg#cF~3l9?$DBnv*)w6J!D)f7vu-J|@H(!?{I`z0%nQi&k_ z_kljr$jLUFXZkNh#8%u06gviaTnG2aKThG@wC`{xZpMxRT>M#g$*S6zc=H?JEx!NC8Rtc)2*&2(b8LkNzZy6%j0j z00++3@bgB85kehuMD8ovdz8Br-0?;(H z4zF|w=vTPwBlSyW2p%rNO3POL7P{aBF3Da5`Qz>vxS>2Tn)1X;&YVWiXv;(bm4FNC z9sYed#!xOf)2AV1uu>SBJ{68x=VWvswby{k;5LT%Hs)G>90sVKiv#kKrplgwEzl%S zVR~3=j*Ol5Xi_2CBj}NE+PqgU8(Dfu=~9TJe(Kd8{m%mL$;ya=`Hk49DXP0^G5sB& zjoXwk*%MeWkVlhyDts#e`juJU&*Zwq0FLjm-^Yj6-yeLZYkm$)n;bG7`k3(SO`!<~W98xT4OHIW4) zWg*QxGuSlHx7$qvJ?fcV#zJGc6Mv|bWiyFY=@H<(5mewj6|uz$Hr@oUl^0>6FXs|? zeuU#T{=)vs&U-UQ>vI@y2C}SlP`j8J+l)#O8^nun`BHz%-Hgf+tF*gVwuTKD9ayYm z*20q&m?_NWhCqm8D|Ol!(pY+&5nl@XTQW(dWQhBmYk|X`C|ng}wS>-O z8!-jFPEQ!iUMDX0*^(3>>nf4Rz!iVQQ+-S;A2tXPf_5qKSiiL76r0@j)bg; z0;fiStD?Y{qrj3UBLvQj0$+*(##0fr)lpy~3OpPIR{SLr=i(@Ea}-!}W(4iYXvmp= zjfC7C1s;w9UtJ$Tdm;*SVCr43iN{5O?B60GYoowbQQ(77;HOc*dpbg3briTf3fvb3 z@Vst=oz+obQxv!{3VbgLjLt;}+!zJ$wrPX(#Zln%Q2_5eH_(7JXDDZF;=y4)(j)?*{M1h$ou)>YRIXep690k4;1@ehVoQ+Z7gHhlYQJ|cR#Cd5H z_+k`T;YH9ci~=`DfzL*PKSY6IDnejw6u2-7+!zHu9R>an1y-aZ)V4-}yQ9EN6v$>G zah6Acv!lSPqrhEJ;73tlC>x=+DGJ;i1wI)C{tyMqEfE5TMS)AAzz3tiqfuZs3Y^dy zp>|Ugcq9sVxd_@}QD9pXcwZEFA_^SU79ns|6o|J+LS7UF-WUZQi~_%k0=*p(0>?*z z%~9Z%DDd?t@Vw3lfvcmyXQIHz+1ZEP`OB<)c`wghI{ZLb@wM`5G#*Ny(8i)9bH%+`Gj#WvlDo%U`4j#{XKh)0P zZWyvODc919!xP^^sB(i?FZTS$U}N_WXXW?^NpK|8SZ`*p#_4m*txY4P1y6Cua9EE& zo{gq@F7BMsg87Yd_eai5@1@R6_e`Inv|p9QC73xeBg2xs9De6K$&uS<Ok5lsn1C<_^Ph=5sxONg_ za~4?-9JOS!>2D)PMLF8vcPb`s+Q}tYxogmajIIZ76VJzOHm+58ctA%cE%9&~qW9V` zuWdKvoIhs&8;~Hd)cRi)G{8FFgTqa3nSpr@Rx9;F9`;^kl}Kk{%V)^pVT3s2F)LXUq6%Mfo@=!XC?i{&&M^BwM$U@=q|I!zMo=I=Ew(t9ttKZ8$RFBr|07-7sBvd2qW%d{gRi$aT8UZ>-d3QgD~YCJgf*{ zo=LHDMI2YpMG&Q!nZgZMSNP=h5s}M?mJ3&fUWQhK%zCA~Z6VSmTM{N?YOzgqbYt+$L1>{;VjCA}64)L3=0oV@Mdg#2-#gLRv00K^AgVVy$4 zV^RqdVt6ai_>$oW&Y$wVP$8uvTlVdwhl+2~*S}vbc97md4SM#D^LIxPyJ2`$1mO*u zHV%f~ER1QI50K`NX%+mBs%s;{@9Kr~2Rion0_;1AeS4i_!HL`Hjl5fOvq|S&i^l;S z$v3#uIXslteaL|o_k|^#kt5c}6jQ9ntRowg%nRcdcBzI;M;?5{inr;CONg0nLJ>u| zaVNlWM;}2kAYW=7bR%eBEe0hqo+|Y_t}|XZYaKTKZpb9@GF+mVw3ayuhH)p|bKGT* zI_HM*x%P^Vx)HxC5`TWYpGqfm2`Xdp5z{Q3-G35(8^*B<(?5pa2D9sIU~H~iSO%6QK*R8_%xf^h< zYz+N@WAPILQU(n777F(Y`far3=H!{^rGs05xT!cieFlNI0pM2wZiQ|38`}({_I5a@ zh>4qa5(7g=@DAc>3RZAi6ZFm|=ypP*I;}ehoUVa)0gzP9;7;>Q*Rg81S zSwe^G^4Y29I_~Sp|K!Kukxodoa#7hjXe)#8M65hhmrOLsvsKDDB6KdJ_nZE|0k3$u z;!z0kHq;cE%EhxF|= z8?!d7#Bm8DpKr6>R?= zW~2*D)jkZ@mCSW1S&tgcd$&$h@_t|i%hJiN(^d|OJ+>TK#m1!9w{#4b9ONBW>=0|8 zZU=j>_mP!)PzVcVei`;*8dZ(!ST90K?^4CpD- zN(7&QZwCCvX7gBUHx<8)`_u&^wY0%6$Ns%QZ~BjDp~0VEpl_mXgsW1224pKJcoOa_ zZ$~$y;M(16I?!%x{}J4HQ!YF$s9oQwyS`g@eXs8Ne%yFr%14CAB$r&<>v1 z7pdUh95e&Z?CR^QJq*XxgD`L)pzdqczESr^Oa=$vBu)r?i-5<=SrTXkkI-YKhVsF; z2~xi5E%;3=zj9fgeNRh3sccRX7WOkH9w#IJ zQ(q-YK`;v5OeMtDxXe}M-xXuH5X|^U3!HupE_o=O`(HMAyZUOy>%}1-k{C`0t3+1; zA7wSkzBx&R+CywyjD^03vCvVd zyOS}#3vXN^@fgNiF`8idURQ$A}{ezeI!~mM3`} ztf#e0oX1I6$N81SSwD?_3(DEIzybr!9u|Dq={K~I*SDfeP0q-+_63vHZ6Q_VT|7jqoOUV70wohCE zzt&i77QU80$1p55!5M>z-oiIwci+(0de+0D7mqjYM2oE+)JYp!w$i{piMaTUp8df~DX`f2mmzH{aDWU299!;x1V$N4I{qToIUH;Cw#XPcfRxt*mv=&N0b}lpP5b5W48ZvT z?umORqAQ5w+$lu{Javv6k23Ta7C6Qm66y@!X6Cb!n&5Lu>Tsb2=o59w+>DyT$GDf` zf==)P5KfnJ7LH-yY@HY2@BwDX_&z{l^jEktBd19-rPidJCT+JZC}Tv?PuBb*`jiYd z)74qh7Z{5!P-DraW=2du0adq#lQA3xn|P#>&UyX%zS-J|2**fr5-n>AN~u@8i`Wm= z^S~T^zYdwU{|PP=1TP}$yPgr%|6~Jm7Zz$b^n=b}9%q|RfxHGQ?vPo-5kDC-*k@rF zF)pX9H=ic*#L+y-Udl!J?2_>$kED21^jRlZAJLKIYNvuA=V>@8=*>&kXB5oVa9Yr- z;h3N2rx<-<%4r6v`2cCZl(camOK9Wx+3skcU8kK90vyv=w_e74N!fc!XDI8(<*{;! zM+kQF9*=7jmZ)+kotJ~omWX`HAjJhUE`FMuUj&(44ch7`+a|r93 zAuDi(9E7W$V6eyBL7w1)L!XlD$#^%-{}ijJIsG`=wx6ZMjxaZ4ZmepDj}fj^d?oOv z&qt)9zX|3bDmD@?1vmwU(>3&mT-awG0(%nj!9a)uU)~hXSz%B#r!ZH8ZB1dt8g}PY zP3)~I*w2Ahn<0?D86jMYj>)`#D`nl>rh?0X;g!-(fYT-XSV3wA`n-q<58^jI5m4X) zsA{{NMpvbw2d)N>Q&NVi&%n{%&F4$WRnnzytQ+FI3c8O)t|iN*{-+_IH14Zu@G}JY z{Q=hbe$bj0TBLx~Q&{Sg7^xDz;$-{8M&n^W2E~N$Q*upBpJ(sZ=h^LqrB-42I8zU= z?CIxJe;7U2-icS3RDP1i;BX^9`+#n{rppSD!s4!8+tp;bE+tERqmOkKAErEi)#zuY zw<3<5JDY-I)|rM`yMlh(7~;3F0xUPDuLNNENGJkzC~ww;EgbKjlz>(jc-P%H=Fpa zj(t`&`Z)BH?B~$#WRVIb-kU_{rU%$wHM|yvBY{|7I1WjmV_5--;c+KvjcG1%N$ku_ zQP*@8RL-hcP-m~Ppjx~MX>EI)s>qwB zJ-BBb1bVd$y|XZ;Y4|M!TVX(XNzzT!x>~ck1>d7qA8k$19}k(JRzjdtIe@0$26L*N zAyOw$CS(NjG6v6^OLf3&H*=}?Bi<|O@lx*L7Cc=19f`kf_{)1gcr7eUWh7mEx(vkR zrRAwST%05^0DAzFgk|cBHT}CV;E$E`Nj%r$O;HqZFQS{g%j)!EIO?T%EWUdK7^{qZu!8=1VR+@F zIZXPMqhj*%9LjPpgrjd*Wb$zkZ)y+*-i{rDrAlBQxS-QsAlD%AT}%e-M3(u&ERm;t z80O@@FcU!$W_!FXp7%?1@gd4G9X9UNRp6+sG4q4o6w@?w_S7)#ts^ko@QNR*MCk|j zup&${03TG}N_)2R7&H>IQ^y0PW$?w9FPLyL7=?-ARa^*nEclftK*^rz!Zs;x=+KwN zC7~>?M-hR5%0Vy&XKJRu-8K7W6>l9%4#FDllJ5_Mncf9MUEXE(ifi_#9wKiy%A0>b zgd2Ta{m1Gahs@DPjefX~Me|;+vTpItx`*3uy7BQ|d}-=jEN)@(X^DRx9a!9W6P9w& zGG9y(Q+b95=MxZ}qY9d@V*T>*MHW05HvM5(UTIh(ZUUkT!u$0q?gjAjFrxbx(qZ}+ z!QzZfgVaO9*Y!(ej!Y zvu+13WzcFJgq^0BDLAjBh!1=aJ_1M3Mc@`bhaoJ_{~qL@132Ygo0GkT8GKL<@l{nkZ~jkR`)_ed%J&rn&s7{W^C1;M^P894g%S%WM82}c`BZmv-IRLqUe*if0jzu+>)1!4 zne!#guns%ZUu3&b0`?zBNG-h@_^DDiX43)W1xKvd7fm$L_Zp(+P@8Il=@v+tUTG+vM0?Yja&|U}e(h?!WBJHKHUjy0_hCx6AvAYKKI#>>LsX^xG zZ*gQmQu22&@?Evp!5ZwCI-AzutaBag+VwEZ+UsG8|0Dx3g4EtXJFGo7>;hn{unnx{ z@l6I@E`_nZ3U=*{K*d8$ZwDLcK`ijU32=fPb18T;si;z`xOVNv258sb0>HzCn1iva z!MJMOfswJ#glCDJ;3l|n%bDV6ci@EwKiymewrrsY8}MSb*RPH;2A6gQa1-aI@X zC7-3KCnt}CkmX}pspLNgzN#)*@&;=pF7{fScd~DdM*UTThdY^QouhX*bM&63KYXgBtc5@=>zUQOQWZXDSJiXi`eEvg zhXWmoKhuEX-yNn`+F|;X3wKP8fDJW1hM6H>wH*!A913m5`0HOA`#c8$ejR0{Wg?jk zjznavu3!NNda@@y1KdZ$UHO&Tbv=m#j;NC1e7D``F01|m3+QApoC}1Y^y$w*de_y< zM$H3Q=8buP6phRSj)6aQ|L4P=V#$c^e=HoRQm@7&a2vGA#ui52!hI=RKYEbeM$hzD z7P7F56AAmOg0%HD1&M``VJE?e{q=cp82&K*kvH{Sg6o;LGL{Wq05e}z3h(vv@vtQ$ct}2q_lDi!A^B4A?&%wm%&hYkn6;Z=Ysjdl8-U?EnQ#Ol(qHvA*8K&4x#bZaUbNkwPU|BH+j zY23I6UPAB^3NQF8f@FBmxTB9c!QYr?WImi{ys06trd3%FaXwBVmX<&j`~+NSXeYlx z>~hAj6T$D`3jPcOp`S!(<-0gF3R}@OMbd8u?QrdOJ4DO1+iS(Prgn&JPrXj;&Z+Cf z-m1|2i;zRC;S$noxGdkZp0RxQL9WK}_YVBwK37=2c36@vvAlmh2nJ7qYgNh%hrw5s zbqhZ8-H0J2{`bTHt}6YOSXYFO)PaAV4k)Nv(Gu&9P~W&v-RO6Kt?EWgEYZN;wT3(r z))1bTeIbN+qpBaThv3T2^c!H+Yu*h2ct~xj6X&O^*@jwTu26UF;EfdZn_!4`9oE2a zI>DPs16oK&hu_A7Aw|6WZ~N_ZB0bj2x5Iu5((QnXQozIQ(wh0|TdCFptxr;Fk7I`m zBV0WAFBE4fVPRC1+S!#)B`SwISRoz9G{%GGE80bA)GcE{w^T}${d`)5@r6Qub{pSn zAoGG3UIWJ!@t@%k6~1nkvy-E*#P851>MbzXu5J?BntH3)ol`f9y;TMCDnHv3 zA^&YK6fO3KZ;jBpRpOXaZx`E|dWYEd)NNvSPQ6p?tqRQ#6iq@An&j_hMe}xqOx+=I z%&B*YZB5-NcIVW)#onrd`Sw5gBjn!&gM$oq?olHsW9*3-wJl1?oZ*{2mJoh*Z>}d#0T3|SD#^Dz#?zAZ9D`h+a>r~0|zTxb~vqw z8;|n8k1QR5B$%2!7%nqvmd9D(?QM!TrrR}w+F{k+j|iSrvJ_&mA5E9KpaZiX&ENwj zqWQXRGE{t}2mPTNJb}8bbArnY!QCK(WB6`hk^w1y)|*>ZdL-+W^5|hnRt|Or{dn7| zn_udNuMoxAdyjXxsRy5fxNk>XGxz}LHFx)B@Im;caLy>^e+aI$19tC$Bls{3c-{-E z@?&-MY&&#nrLe-ucAma=TI)GCBJ(|rW;!QXC(v{=tZY%m_7DO`PwTyYMz9&|B+gzXv6 z-Ys|Bu3@{>jmt7&{RsyMRdIB2*9*FRUP1G|4ZNf{e#(m%tkVY|9nQ-TOZryS(mXql zE+nG*Qq`Twr~I0_&>1YCAl3w$$K=P!_9&L-(GmHdP-t zBT%t~)rl{VkXoJiBAv22@$Yb9b>d5~L=O=ju{!Y|@Ca8YUSF@auHO56zcKQts+(sb zwJ#Gl$xKh;IqagpB`ZgWQC>Ftc$vEcO}ZSX_8_pgggsCQsWE5 zor2wt9ejmJNza7K5}?W2Kl<%LaTrYmw_qMZFyj z-A1H$5^1=0E8PrhL;yBcyRk*W!)DmRvCTO5LTrq?+&HoMP4kI~r?G{rU~`g4+o8L~ z)MH($zMhTz-;O%M{pLH7K&rHsmpHmkS(mnOT=?Dal8EDYXK^oH0>J~R4&IrK1X;ts zG@*_PZZVnPw9HP_uZxV{!%e&kFvr9LjKejYJ9V~U*G!$KDpAcAvJPFvsAH>2T~~*cgk&#_U3D%B?toPi0?XZO5oXG#mCd`+HDH{OLjn!%5e_rCP-;bws6z~puR4*5bw?$?BMYs_1+~?cKnmzt4jZbE ze;^)4PnC{Ame<3@S;|K!g@gFO^aiZ(m0xIxee&P#A;kLoT#7}5% zqwu(%8uYW)Eao!pS~FMzzzq6e1{-12`7d7tn=Hc`hc|AVb)Z*4K# zznb%u)n-7(adFCjWqsaa%6=90=&`2k;D%x3j2a%kmnE9%cq`C2)3`q ze+?4xoav|V1ZW0_#ZQJdG1}@(|0M!1bNug+oKyQNeElcrp0T>dz{{++z)%o!{aODL3(nlcW{IV5oP$xt(*v*mIOyWTPU&tp(b1ukn_iU>y}&Wfz)vP~Hcd*&jpV zxVHmyJEp_Ec^z+!V>nLV-!^!7{NKytI~m%a-AQ`_3ak{fTiS#YXEC=YQ5Nh2Ci?K` zlPcM@@M1^8Qz2cdO?o-J)Q4{xbT8upuz6`GbsE$VgbcsK;*_kMm!_VLlvu8nYvqf5 zC3Qi_{{+08#KvI9-Y8-zTgSknH{Ya0Uqg9&R$2SDZlP< zBmiz0r#kyOjZ^(yde35K%&m$2@g14)ZsIb0CnUbZHj;eZJB6duanuOB4g#6?O?GC7 zwhSF}715RKQ0KZUaO_QLZ$g^58&hEX)ms4U@}&Cw7UVp4tv)n-8eLkxzk6g(obBoB z4)1`Wy*;}gM@{ssB|UY_lcpVrssc-z}o=^;??r7czA>0ii`CIaeP7^m&( z>y3dqLPDf~iPUGSOTuDWORgPBu7|Ok@HdvRazUTBj{@fU+p|e0*^E#AZG3cVa@4c+ zKV4iFq(3^oH?wGZF*=g*r7QH&9B!a;wf>Sxt%gIN1dj1q{nq=~TkP;>PD7;jD~7LE58%(dNWPN!xJO^z zsBE;JioT!v6ltBA2b32tTF+QN&SeX&RE-b1(S3@mgmzI>Z&>hD1Ypu*SchV>L(4}p z;V{+h2e~3|Y}~0*+uT5k4Ohx1&==9PjuXj?XP+(2O;W}jL(`j2tBk0QClW2qKRO9V zg?Z_6DRrD)jh?QAay%n(a8m{)ZHO|Y?S<>lfFsSOdw6BmJ>|yYTt^U{4H%s@c80a{ z=DZ=@V<% z29JK$&(nzl!F|8nTjj1VR#De^{$(TR7IlU;&DXi0p!qr*A88EO*DvC$DcWTq8J+OQFsOU)DEKJ9 zk8D1Nul_BGm3Z$m&3|_4C;SLHK~#V&DfPz}q}&fBh|*&Nl}vO$nDqSO%rh=j?4lTI zaqBedrf>=o)Gd2Qf=l`RIHh|=k!@O0Pa$g}UxgL0{3?gOdzT~nqsq}HMAO zYzvAWP*9`IK`XRh3Z>G3#+NlJ?>6zJEoJz7rQ`@>vx@yNJ+^mPW}dJ>VK0u$8-(wm zH=@kKjiOValjf`m5-er1t@1RE%gfP^|!r8P@W=`y)mBM-$>c};Oo#vmaP4#UF zaZXg6&$W&DqZYK0=8cv8uvbC0Xv;wd4q9qaSuXXVY6p4^-TiYsr=Jq*!}H)fkBu2W z2ot5#!%igdN{+DH6JE|2uRh>&^Z!Ml`#g2%Z&yTmO!BoPse_K_$8?Wa@oH28wi)&r0xCSJC!H*E4I8bxu@o+AK$MpHM)CH zxLtrB-U1rlD0!jMs{<2(Sws0oL-~J#^P}_Pyj2uk)}+V}XUTz=t#qykS7;eJ8K6E? zmQ&&17br{2bsBJkLPx)>H#=9_1G=wJ8569=N6Dddw?_KVr7tGwhm_v8!rFZ7@kh`j-^U+L1fMCI0Yc z2FuZ(BQGs`2azfWDgT*0m0>xUPI0Bf9Q_6iyrbY+v|=>+HDUip86>&=w$)?Gij~*1 z`N+SMw?EF&>h~){mO3Lj!mCi7CXQvx6FXEC*T@;?=^T-@u!Hkaj?`iQau&wC=<{$< zTK1(xOUssy1DHRsu*09Y&8=U%H>Cf=>Ni=tN6?^L`_t0%`k>3jKkkSL+v5)*{y#}? z8>O*KXRZBmC$^M})Q53rG8d_z;+@3i-l;!zx5=27Iu0EFWjGx3bOyGxg*Qw5=wC&A zZaklhI1wDsM`nFPj*#Wqv$uYehvim(!*vq?Fr;v_5*hsfziyP-=7OS22;o7KYM(}< z*$2~f!yJ1z=;#dMn!XF3Ef@7pu2#qR0rGzoMZ@-eymDW+hl^}hu<Z2~3=N$Aj&|Ee@SczPHF&9XEMfDj=D_e>F*74=ucF6?CWlLET3<-n;L#uic4C|0p z-|Az&s`Q0QIoPf)(mFO4^5h=x@p-5)>$bsBW`eY_fJX7nMvp2!xUne46V8LD%jYGx3F<`ohn36JRE{!chE;QRUf6t8l6*& zUy67Zgr)FELg%V?fi_t+_vR4QDTH=rCPrOXV+(SNI4kubf&=@V=DCdQBnx$g%6-lp zP!yq|qQVD?Ks%32{z#E8zTkqyE(aTN~E9 z>aLsNLex(M-PD;)=Bq3%euH#=aXqtby5O$^q%Qc2wD!Wfjf6ql*YK$M-2x5lN**z) zV7=K_Ct#eD_X|^%+lhY(-a~U18D5E73*_NOIRZa+t-1(@%4*Bhhaw4_!8ne^%NE*2dzUP;Dt(L+HZPx=rjK^ybS+0{UK%Yyru{t(CgZZe}K2 zLpGbIE^YA$Diey8^JZW0Srd-4FSKS~a2v5bM90~GMazdA`;8N{X5ZK8`rF>lvY%H( zD*P%8JnZ8nX^A_k(OZPeAe(~}k~ecs#UrxK;_2@-aQl(X-y1%gxi@?^XK(mymfrB$ zygWgviIMfYzKvmbQTNr=$f|5(JQG3nW{+$a5J`DTTWr25T8>l15@tr&;Z4V;I!<3z8smTRjG(Sd4tjUcUxxFFh% zXZO*+L%zQ0EN*E-+Do<^cLni+#z=78_)-UC69%`EVTerWDf@PxAu6dyfj_cYaSY$@ z3O5?vJ$=a|~M8dA(gI2#uLGr}KkWa}vqjnsTaVox8t-J{W$Q zN=n-QM)LX|d8PG|qZ_31BE@WJW^vhc&6E^I88=Ansc7b6+Qk>){k~}TLTS@n)8Ebu z>>f)ySe1(21WT{h`cFhPW?%->7aQx^SU@BC8N}vWQ$FPFS zRI;l1!JSI$7fn-QZ{a|h0__AuL!%8#rF1qK6S(^dLO&ASQc6Ylv%qnm=nkhX|9GW} zEfZ70RxS3!^+b%L%W5!WaP`72;jgR^Oby0Q4f){)!7TJ`#A?EDDN=bHO&<4K88wVz zj)8<4MMdLFp~$pAY4TE73Der7zd8?;4U>0kpH=gMyt@MPW1@A2=6El>6Q`S+E(Tvx zx6|bJfaNEtu3oAZ(wCZjT6^0VRU7!Bb&HA#XYiM=_e`!$WCx12GGgL7YQer+#**%H z5qaz)j|{ia{B%z`98uA1hF`)beR%fd_6*0Ap;Px1^bR@n2;a+a*jnE8sH#Vh4>O|kmAhZx zst>y_`ef?Q=2I5XaSrGO4rrSLdXWQqegbrg1G>TiF{=@#mpGuRfUW@3vm8*}0bT8Y zu1aFhcd@T_v2a=_UaMG*)oy;Md9vn*FR}SyW8df!v`f|-x9O9qzd#@Mjb6yN{LW-= zsTBr;@<^%!EIPQGyd8pw*O%j!PlvJC1_&(~v&~@ZuZ<;XKdiuX6y!1SUN9rb#)Fc- z7MNGEa4LD9XoL0buC}cK*nYxwmsDR4ASc3K$0vFNKk5>cNK&Stu+p-uG?n&)HJvRrpJsTqJfE+1ob>jKxLeOSxF8!%gJmM?m{|_jLwgs;?fY`r z0uaNZ*OH;xg3kL>Kj8|}Yw-Kro*K+?y1E4zrFQ>~?Ncy_AZWfzC_2tPUq`ujTKot8P{tUU|Z$we_0Fw3sM!76C7g_WIsw7sBLHw&tm zwt~*QqCwg5tvN7(ugG?)HRvGZjcvAgt21EQM<|m?!TRAQm4`#S_l-(L@EA31aWiRu zYbj&1-=o)8s_9WLRIh|rpXp+w=ORR%UwA&F2ZN|>$3Be!w;d~&+m5w%s{K>->HcQ~R!~$7)1i?Us>5s#RyeIlRhYS^5kuA#BEKf%4ZGLeI}{4o||vmWeo!cb#}w zI+Nd=GaPnPr6)c01?_FST1ob{6Tx~&i64TtrpV4PPRuUDXZoYmw?y~KbpD3jK zOOyk{n|3HO4qMvEj9;oC(i%4BLyVSTNL3$fxTJod`Uocwk7zNZH4(T` z(A#0Gvy=%Is|?FL9{hh7AL-A>8oV}Gop-^C~nH7jV=_TPkN>b#*ZX<u> zA%m4^tQ_cB`u*6rjW7KkAKw6LUIVqhYXfIo#HlR_^|Xn{y|_v| zR^^hr#IyGah1RE@L3;gjDQ52{+{XL6aO@5q;J3OsR0c{pn<_if&NmMjy=Zx6N>NkL&Q=W}h zwt}JVZUxA3j~uiu&-BC}!xKhP!U~mvAo?MWPL2o0r^;3tBrIOcZ*OV(9^M$c&e;>>x;Wz5 z4rG?J|Dd!r;hyP42BKe+bCL_@$sO*rfyrEX;=e(dTKsR8|A)L8*g!YDBKjZUGTeUn zb|M^d3rJ#zTzPJ2O-UW7qYZz{k4q9m-P8&tOYOZ-T*7=LCaEB7Mqt zU>iu;Cc#@Qc%IZT#q>SOH~KwfAaLr7IbWdr#hm{bK(9KQB}>dmpllY(MJ6rW6j=8% zAefg#R}-jhNZ!m@!0)+}`QA+UP8dGEB|Fh=y*_61)$MoEa~3d!#hyGFjcFPKE=$Q( z7*a08-tx>!72bvi`3`LQda@vX2Z$^7m`*Yaau5Hkzl`lE?$LSbo?9}BhnMTUnN8d-T{}nyupD=z-O?xA|pJ4c`cq3X^oyvJ5Pdvyq(D=G10uQ#H8 zeKPNj9LSgB8zuf_v-+X`rwJF`Ht1@~~75J9x#w5MhdP3E*+y2di8G4KRau;s66KX7Gma zR+kE(x*xw5UQ;B7_^uU&%aj+ZFe10Sc6cOwAIRqvB{iV>M+wJ^x#k}J2^VW$7+t{g zXL;U^he=B9FL=D#Zhpgmmwh4%KZqJ175R~A#D+(+j3lz8$iy=w4}8|VLi3NG8=sVp zjxSoomlgD4|iPwG2g386rdF4m(3UNS9zKs2DoWnfOK`g1cJplmg}KN z^q^~{e$hfthtV^R>4kJS3>1B5HXOk*K3HTToZgv%Ef}XIBovjd{9F=Pj;BPC!xcDo zen8Ai%DlD}FTUq8t;)`MO=h$o>XH?*)-l*BlfCP!SG=d$+@SnUy*@ns8qY37;abck0I zCeN}*lu}FlXaND}Wrm=*v>Skg^VoO6xYK%1B6aI?5v!r^v+;Lv7C$7QL?F(Y{!5uMV*O(RyIku zJih%R-NZ`=qjxmkxbTS)Z$}4Ey9Z4)c6jD~FS#)4`FP3>F5w|I_M2JMmC|cXQ*vqA za0XEtu(~j#J*%c2P~$Z}YE}g|;bg(9rff^AX;ebb3noe#X5|+B+Jh*VJPD3%pdct= zRil$Bn4_45S(hY7yw1SI;kwKcq8*t=7JqA)C{vHP;|9KAs64*d=q(lJV%)7}6yrB5 zC{urnK1@{K%2#}q?Tb_R{vD5+N(V;d)SC{&=@!)Nwg9j`X-N#-Y{l4jxM-%@)M$6sMVwZZt zM@7}W02O39{`3NkYnVGji>9C4bbPF17E{X(a=M{(%yYp1n|Ep%Ox0!;79kXpsqjGTGMZ#0~P5uy7-B4 z2cz5ECDxjp`4dw#EtRu=;_UiNJqQk!MfawE2M#|v4W1M#40vJ=I)<{#TEbZU{y{5| zs`o^19v*Wvp5;ekIF;>3N*#WOAJa*{i^Gq8DDNh(rdsnt`N9*l@P=TXs4wkTQH{Wp z6i7az^Gv?K7ta%8dCv5dXLZV^Vb;jDJvH8U)L>{fe1>;VW;w`s4koN(1Nh%*HESQ+ zqH2_-n3_DcSpK}rMByeeB4%8CU+DoS2F9Dy zp!1JLr^$OT!-~zN<@oe%Q}R121CC2rDYo^r=xx;WSj-nDS50&O@p@Z>FC(du4UT4w zyQ75vsf9-EDO7hsP^Y&;6__0eSpuz$G7HKw|F)7a$_&&MiFWgLKGB0Jz$Pzz4AxkP z7d@n)8)vV87dB_zj$?Q512|NDn5fY?#dy_61eVZIfR33V%ImUmN258l28^ao57YUC ztK(izv;6YWBXf`+{)lYnM2O@w9o`1L(eG7D_s+h9P%rv59>4lu;F(>Q5OjzUbc6`{ ziV>uk=&K1mPXqCv#TPWcKarf(ku5BLqn7grp>{A=mj_qyS6SgNit<{e@rUAXDgGAS zcYwL!Eg7E04(J%oh|bWpy|g;EOSpXIN0)*0CL=ofmMCX@%cP2+{tGntwLfI6Z|w8} zJ7Bm0Bs3Dkn2E&Eq;QI+7h`x>GaKY$l|uhYF|RdnWjpF41RA5LTLAw4lS` z*r`&+k83b4L49~QpF(B71v;R21nxaS%mPj-Jd&u1dt;j(w}3y@q5er_*Z!bUTG>}N z+F$#iYCwlAPy%-1)Mf=$1tm#aK~s8ztWeqN7BSJ$2$Rx)4|7N!}om zS#8IYICFMP1zBBBgcd656&x(-kIN6=T%XpVa(OicGIQ6*dAypyB?sc^Zqs?Bi_xE? zEKL&cz{5$P5Y6g__`6YG2Dg*=MyI;K8pa-yaa`@uGoA`U^QzPMvLJrCVC?Fpx-PH! zO#F4hc-1rHY{9W^ejI(6{sq#H&g9qd71(?@3lCFT%PokWh0oqXngE9n9qFi>AbZqv zGY-y(aIh3dtOv9|>M0(u{_U}qxnzYKBWRUp1Fok!&*97PhKY|t`PW|UO?)ScUiBaN z*5&c4H^}*BIW5*V1Kn<(q);d3rE({ABpp-#Vmt#pVxKg~bof?)$11B`T)Ke;U_+CR zZUkW0LW-??)6v@mzk9J7qSG-aQVWhqEmQ}~j)W1ayD2eIf^HHOS?z@XhV~Q7yswvCF;x%ng-ktvf zfEwlwH+EEK<1co!w0IF+1Q6mGJy+izFFIe}cwdTcqur0*Q2!tUjvqZ6Ftu;_qVwcY z+=nb~tGw5HHTf*P-hDC8bBKwZ7sLoG{K5pmhYf*wK`vjUGz}>z`f291%lz<~cqn|H zVkfIF$2<2Cz!7cJ50PoT_0r36ljj4Xw;cy;GLrqzdZ!MAmjH#$Y(IQ8 zsC1Wo_7>2c=ACL^i^k&pspSDT=4f5W@Ed%AD}#oBr?ixw!)tdmka9009lrLjVin!K z-t#y8D@QX4 zJWu~bRXpM4{6yRN(WM5>d9p40kprm(D^p88MV)HX@V`W#RNd%`1WozqyFNp#8Pc0m z1xvD^y<)qJ6eczeUXhDUe-7ufZa^ueXKF8siw?cj8?B1d^^bud$kZ{TmkxI5H=HA* ziR>&^_tKT#>ecv0gPLNZm*Li^!YTT>%+tGu=AhIN2;t-kWqO zW3a0Tb4ZxGEd>oU^psQC9=_(jDAl(H_u|=GMephMVQ0Dv?149Dfs1E9?&9=m##!L9 z7-o}aM4CNbk;Xv~UV9YXZtddz6o~|C;*mfR5`I8@VLUN<%oppR zzMa)8h_`c}5Ro=FoWt;5+SfiwbT;Lg{UqM#9F>fq?O*Ijb+GO-9z>@R6rIjbX?mIS z6{BY=Z0}SS6rD@t#9#|nhx*wB`(AV&AA~@o+nlnL$VPv!YN~!%1+@0H9-enXFACWk zh^l`EK-q5otbP6ZZT20kf7-q~Ty!{z>|z^PzVMCWGR>m?DSR4a^^L9}bPTyy-*YQ@ zbeX&f3uQgYs|i1^PYd)_fEJ@y^Q+rKT;TwYe>&RvVJU&cFNhS5-Q`0QGMb`7)#XT$3Vg?`tk zXH)f8q!y`x@UE9i?T4>dyo!AXUhdxC&L?`0<)@JFCdD7!46c4mJf95TOZc3C)h2Hi zQ2cgs{3+<6V1Cep;*iPe`;_MWf@LuNsQZQ=(|40M`_Fvq3UrE$(Eg*Mn)nva#%aTU zQUm}WY5^F7Z(6Y}a%SSgE#ZyaKSJQ#Epf`bOmfsWV^WiPMOW%|hfOG4^;Ut3AY~%K zgNlpsUP*ys*JM>F=Ds8j9BnU|?bNJt?h|n;m9<nPGIB z;Kd_9RoV+Cd6n^V1|&YhsCGOtn%f1@lmk(6hk~9gO}7A=I;{wMQuv2dNy7YjLAIAM z_E|r%&$8aBbZ)HPC(IX~0?Zem0?e150?fZY1(<&mOnX_IEc^1_k(=~-r z#XjAa{M=+k5vG=!6@`YWnCia^6Ac0FhOVGx#iKQg83%0Z1-|{-^W++u_G|>r!!>9~ zI!k~eVqJo~QkwNO6m%iXm=w+3gOb6?ZtaRBjp{37b`a2XI3L8pWkcb4|o>Q zCc_d(w7dH_1I#i|C0DNA3$(Uw?&FKyDt-|iXi4jRmQ)Y;XTL(npyh!Fh#cQGTu6++ zR#|G2ov6RF@6ZglTFfF8Rsr}fo_V=_m(0A%zDs9bXW#v1UT@!JGjFu-aDL{^a)js_ zmBLlZj1%3s$8=NXA@ZEcvGMz`DAOVON94G^{efm(eR>;6+`<j z7+sBs44*W;#4DLId<+OKF%3E24+LMFC&d|mB?Z=QXTJu?;joUr%lFlW&-m!xl0Q{_ zlCz2YB7dAcu_b_Wza(7BcYH-UrYia&bcofjkZ=!0FXH3YcR3AXlo~|ro+MpMXd_*z zC7q{3HAi!vg1a!qi0N)&kWM!~OY80!EszYkGZ#qs@MOWmGHGSMY|b*YH^YY~r?UY+ z#OK{xF?WbiM89rH%q;ujzVS7kr_06VL!ST?{ zX(T*b$wIC%Z*juBpMWGbTo}qdd6!$a_w8)kd^q$xy5U$De>t|5GmQ++ynG7ugjsP}s#sT?oX zF^Tl*-zUloe?_ADedd%Vg{Jv{lH5AWnZx*Q0*>9mxumcDH^AIYARzoT&Y`ob|D!x7 zXF0@}j(#KeCa)$0+DT%)`nL*#_ZkQOfp4E=nOW(y`b9Y|gjSYUL`zpTJdI4cbNSbc zzS={Cjju|458}&Ck0f42>c~_O{+=wt%_JP>A)GQev*8AOdc9_RSqz@7D|zhU@i(Q$ z+P)^p+3#_7ShHOpKu4$bS}+E<*wqL>FDAhJ16hM zjriz$md22QQ5AdgMpWKtVw1H&lW(tf4Tz@jq9>;a)cdy)k;$8om8QG%u5tL&#-ku) zMCBIwEQHR^XGDV&iduE+Vb#P%5=n&=CKkBsnhwKA3kfJIegxg!?X9Eiw(Z{ zEqT!AxA2XptDFtk(sUu`WZ9dXmqq^})bPl&I}pt}X~q3l>Gz@EGXb5SLk;@ddGvpf zhXn6Q^YCq7moll}tp0({4$YSPzmh(uYiQp$jyDZr&-lJ1zEpiHJv`A#YVpZWv4-r@ z+bU99w8iVpSV3baZT4y8>bk_V^@ywwS}momD|2q&dNPf>PERcDS-;sXEJRmU1}**N zgdRj$!%}c8@mXLviML}no|}*oDpfnvn%*E zc^0?3eerDdK6nOn1XiVue*d0Bej zj{gccQSUf`nBa1ETpT8uh+g$WkO;@2F^-t+E@?uE-X!`wm2pChra?&zJ+-T3R$O;e zrp4hCD%tfTOgo+aG^eiK)F)luz=kpmpOYSh>UECX+}vm?YRmkpX<*PJx~SjOV&sG8 zGLTc9x%R^=NTe$?9X?$`HmG`h^|X}F*R1-#5CAhzB#T&jU2X3ermKOT4ct3MX<8#* zgdYp|sjv-ec9oWB+k!e}eW4Me4A$(YAVbg^CG!GXx+{}1W8DV7Ilo1(LNvmh?QDmj zn@hH@Bw;?gr5f>drG6QdUW<>)baX z(_;PSN<#^ED1{YME6iqXVQCU7ZcWJC_j7O@dY(_Mf1Nm?3ZJJqL7MOR3FHNWJV=l? zCvle$lwcG)m5;cY+q`;NHW$vPn(dbUbQalgr4${#>0)&o-_TL~>i3e7-e8NFE=b}eDZLrj8cYV)-Sn4c;lzek$Rl5FMM{Ds6p34ia9j3D)`GH8 z4GQ0k=q7LyFrHOxN@A18^U9azbn86m6UM!Y)+nz?Q8rCt<^$iH1PXi$PrvL#sCtQ+ zkHWZh9X9jlC!Ppuu64SuAV+)N-4WE(Qb}vQfD7yA=x1+kBB+e;yVUI>%-bNw_Qp8% zoyy>RTmf{?jHbSujq(t|&_@67*?GR((MjmwRApM`iaTgym90N)0@lV)D++oUW33A1 zncr)cY}F#q`CLr1_tL>~Rm$!`@?zw4V~_TM9bQrC@XF;G)n1c3tCoRRymB#yx7h;< zxnyhi;O882jcfaZTjlcoO_*p+ie@7Nek-uBDZ4;!XH!h3_4%OQ#KkjQdTZ91 zu*5Z1z5z4NlAv^PRp-o0R&+E9QWqi!GdwrOG&mgLH6R#Y7_-V@a;vnG|3&1tpY)&Y z!YjK7`XY1tT0$o?3act;+qkM#bHlcvjFr2 zWb=!Bmyu_&fKL0wRV)Z|Ic!ij?ZPwsbx|yng(LV%7G`!*Lk(70zhYPPnn5a193-}yGkk&0L|-%Wi$>y|;<2kZ z2k~5}F5lrx2u@#~2!Ws8>=W=VzbW2z?(s@0xW#KyCaQN9T8}Pc!&9S$HjhjebBWZ2&I>&GVoe zNjI!MWv_JeB<#cj4@OOP4^miO3=FbXL)E1SP7A5ZXLXZQQNBCvNIiXz68Z|Z@!)Tz zW6i$k_%E-xYN1t6$YG42dNQ?orSB2;&`8InA%`a7FpR7^y~DMgS3{<=U?P|3x~7dM zdLTj-1#9&&&Y$ORmx#!0-uvVT4M~wD;JDTV>DuQtGaFV)D8-Ff^2DbWxpL#;%K7S% z8J#o1*FwM+Nzkui0sC)#ucu<}gbEoCx>Mr$d}^Q0wk{~7(SW`@a~DzGWdhu(pXTcW zp3OL7q1UX#wFn9+I4h(jxSlA)?(5+I_3jeElxqo%1_>D-3X2vY6h!C~l_Vm`_&c6* z?bM}Z#A@lyyw>^7p8cEUtp4py;8Yb|+&)dRd9v#v7Kh!|^J$E@iu^`Q#zhOOtUYd7 zxRa+5rwWyknGM~kOS>uu&YZlNI~hiRInA6vSEYC6&#)}(s_LImfV*;qnGx$HRA`%- zwp42)OqFGcVn%8cf>-Yg<$FB03Gs8f<$6CM-YkzebDdPq<$+3TV1TMImOt1#NxB7OK`Ivv6N4=pWN(62v@uxu}nemL-WV0`7Re``k1%lfy`lTJO4?+T+woDf0#^VKRct7Rtz+4uem@X^|+(A38G zC98G$p7iu$m(AYvO)O#&xv{3!*|Mhg&#aP4Ha3yxO3PDR219f>EH4B-nd$+`oI8Wr zFvPVtlSbo0js{k~o{SZY!l*xf33&H!mW3@-VQVg8sVG*4zq0UmAj$TziX{|&UEE+5 zP@Wy)NjhAsg};5RVoCQHg|<-C-|9@ zc(qt|P$kpDsDfGiSttkzDP5F1oy6jgNxtKat`qf3XWPV;kn=H`r7dVL8-$aj38o)U z*1tIO(}cTt>t29A0#JI*y}*r8o|(UBGx}VXsYWM;$L?ZT*BulM4*_qqj-Q!d=P(R# zC@!us>p}El_XF=FbzmSf2jz)9j99I==v}PCanlG6$VNxt8XwL^NAjJ(xcyOln@3UI zsa>v%fpFKU*~T$n?y}^H?r`s2|JWeMj`+sFE4}Pp{|#^LM5`UIyrae;ZohqHG7tM zJrVW1$Btf2zvG9yuj9aE>@hYhk3Hf=)>tsn69;Xh60YOexXbZYu{bwBd+RyNO26Z4 zgPOjU)x?3Z$Ff=)d*)+%&gHV}88M9V?#^F#3Cz#$gZW94r5?w5KMwb*8z{qR^fMSq ziqUbW1io+7;(7e<6d0#JodHlC%wCm++VI1qpXhV$kH{Si%qhaw)afr-(4>w&p*jjY z-HcDqDw-8eT{=(mZ1yU#ynq{O{zcSmB*5uKN`IizA5Dm|eP7 zqCHylZ=%o8N$s&_Qrf3`lj}#Y%*sg_YAWjFfkuV%L`X9|tk@C#0Ig+L$sz*_zrQ6S zzCS;l>K=D`e?p}4Ii9k%<+BE?ljS%cdE$JgaQe|Szq^LoGit`fZO-HLR?o!Vd7VIB zc zD0l8;icWv6w|H&F8_w(1nIebxmux8=Y|f&$jFK<*hWq%OLc!Ny<2B}r-yjxTd_JvrC&7+Y}K-NFRJLd|1=qLwb@6ph8wmW4+JlsGX`je0Myl z!JqDYAJ_AU8PBD&oV4o9-(>s=rXCOA+g99oX^o}%FROpLF4>ZvK?i^3_5Qe&%7W-OkCa1YiM?qx04`e`lh)8!tlKU1G# z{R}>pi?WuPSCj9?KF@J(5$EooC8(0&qIo-{l~J#z)Wua@luAh)vYIe+ZLPGWZh2Ug z{F^No2kO;C%hYwAK~D@Y=qI9|EgEMk`@1+t({-01zkSG<(QAoJl4XXYChC&2yc~g* z*Bya%eLyEXV(x11%WfrZ4DLzS)Z$EQxMppV+s_a_EuK2N2j`Q7mf!EZmw%TQTYU~; zg~|alH=&_~7vQO0$j@k;;v%`D=L#mem|qthgluXB{`lD~cuUhK$7sK)j^J|rc1F)5 zP4s+zy0T4occnKMT|!{qehry3k}!_NDO;CnFmI0BjBe4rn`7zD988bUy&u3$H3S*o}+)%`Ze(M^Nm zsi}opOX4_P^(&k(RUfJMbxsl}|C0HsZRV$|UnV;lPU19Y_3|8Z)unQmoO?gHGxa6< zg#C(LX3hsSdR%E1n9?I31Zni|pmF};PV;b3PX?OO(SImrhp>iMfWg}#q|RBa594Oo zFi1c8Pe7YKp=|p8tIhY7Hs4pVq)Rxy< z=TEhuEtP;GtIasC8|F{7tSyy*B9o6e)m!FI)zg+rK#|E&oa&+ZQ>|`GC7{UUG)~3f zJRdhk+ENLqjfczIQ%MLc=r=7w@aA@yq;^)dVHQwiGVbUJkEP?dGNx^AehgD>7z7kq ztBg|}+n(xxSoo&fQVB?QC%!EaZ{>ZdJvAk}+=8sZ1<`kaA7ANTz7;UK%|N`;jHTAD4sqUB*iL%)TtyBgAu@;E#k z1`rgCC_`J`cQ-@0L3}t@LwGUXZQ7?7bg+FAeviWH2u&_L64JtZ@wzN>sGZS$c=M#% z%$ak{T3@_puj2W>D?Vd_pL!Xk(?1lqqCZ@~-n}EX-`{+X(aRC{sg?f76Tqy(h@F+B z*OkOPemfX&4Y0meu)Cey#uyg1Mn%>`Ym928=Md3za6-@iE%Y1`({oTl&x%%T4SEa= zdKzFWTfy4tS>75IS6W;*v;`W|W6)l95&Kz$yLK>i zwzZN@zdQdBtH`-r_yB;LyK>XVq~=@5gD|9sh`9tdd2C`2+Y9gj<|KhMc&! ze+zVk+qnj%>VE@4ei>C&AgK>Os*yT;0v1nvN zOz_@0>cG^g2K-}B#<#baGTDHAQXaq6wEY&?c>3i=4{R744JFqH`_WI3neZ19>)Ey# zZ-=IWepo`n!XGK#>eWk)@I6xU85Sg+XgrS)8w?*lEenl5ZJ^VfiFG}bDIN*X664Q^ zECeI}j1snbFc|q5-^sG`Pae7MW`Ki{hp?zH`Ltl zk_)?l*kfGzom&U+{pbNi!bW~4Q$vpSSf*^^+Y~GeblflbIzIdbx{McU1K+fKLO2-F z7J?M0kK7FJ*Tehj&#Btc=4df|X!HvUY0O!NyW^0?fHQnp9MYKo4fn($joIh$f;eQD zc52h`;e~NXW3D;8EDmYt`oqI!~e#?=hu90BK&{&PCSV1@G{Y`Z1zChvt|8M_^B2pbu&cG3CKZK@phRRQQlC& zeLv>{-1wDCtv?}Im-Fq7!;SOgXL)$hc9M>JyN8{^b$Em6Bm15 zirXmIJ;=J-l2!_0{^U}pZE^YE<7~^Qq%BFRSAt?r=&CijRL<%Sxl~w=Ec(?tKG_81 z^iOyg?5|JAoe2+@ds0yJ-ir65s{l><;Dzw^XzP0f&-omlP*k+~T*Vz@aY}D-S1V3y zgd2&|zdhCnuNM_-fcC;S$~kS$H_3UBIc;h1U^z4ODLy<`=$?J~2ViW0aGHDH@(g!Q za*dqJg4M;;WiqCnN}dI+JsV6R7@Q8OHvoNQV2QD==+5q#60|oENZTP2^eXTE;6B#M zE3zqX_+~JBHBqh(?Je>Z>uW_eQ+X9LdMjZK&yB5~x3zlS-s*WrtLL4qo_Do+-reeX zPpjvqR?mA|JvX;{i~=@3RyX+PY=0d`8MRmTJ*rOz8Age(Yu&No(ZXX;)0$+$_lx1p z@x~h!U){gH%q#S99?dIOc{SB)OZR`08shsPD?AgIO)GR>S-pROSw%QWXdywj#n7p; zRUcDm<|kO5#%ghwIhS^RGyMITp8NIuox|UD{%En9f$#N~1y)@TJM(50MykFv<8A!a z_}lq6{IQ*2yW=PFrTb3(BY&Uf??3;BzsG?6Eq?*@=w{Rn{C#+yKb22^*g8nv$={dx z`zn9;@b^9bxP6s+j6Y7vrx@H)zvFM+@A(-hmv(B_Q!ctsEUA*9of@f_A~*QCQ$tP? zAhFu1kt+$10PWNelmtjVt$if{s*|<=OQNx^91QnwX^WDe?p)r2%@Vf;SYitZhWFpn z2CK%fQzK@Qvm|||hQ1^~4Qb~?Edgp~J0ETdP$S$q*Aig)X@D=Id#*tc!KJ2;_{Ka^ zfx{2*vsa9WpFc)eH~OG_=!9${`Nv*n;=_UGnJuRzMQCe>2kqa$|`xb>dG$a)r+Sbbv4 zo{OQw8>X3sHKd{|yX=D8`RLOyD>c2YC5Aa+0}8WWEuKtvc<6%s@WKnu?@ce`CqsIZ zE;k=ldtL-K>H96oIFP279F6xH?ycP`*As#Bmpb#*>htxd)mG%yY*kdwa{V&BbPGB? zw%X(J!kCKOMiiWF5!1A2}vqNV` zA0vFUdpyH&q=^i-T`T!~@%3t7tU495)qhqp)|iYqt*iv$tpw58X{}AY$tLA9e6U+% zP+kWwZmrXI1gQF@#3tPbel-(G7s zu~cM?1+2L=bmnBs$#|5B{sqMIuGoZkqyL46h`{+)Y{GjKeXyec@2=Q{-xT6?LX4{P zEqM-&J=kojgonkR@5pm_?7=)!B|IYbd{3SuW6$^HIV$$tE6;}5bDumLW6%Bate2;C z#YVE9HX8v?lN_*Sa~UA0yPQu+nxHy8GbFlSR_ivNU-sQ83|9Lu1^VrcQ?DDQ9*7TS z{HyQYm^%U)Dtp)Vqf^`X>fXyiytHoD?K3%&o^VrRy8m;Tdw?cCwTy2J*9V+y1sYD? z-T;2w*@oB$tOk~MJVjVF$#*_QSoNsydWx{>1fD7l8mXQt4XToPXjswYS+T)04L~=~ z(IYfye(Xv4rXlU!4cI5=u|~W1w8CD{(lLyAZjd>bl?V=r?=S^C+@Jamhxm!*VIwr3 zjO@8VP+Hn2LCThV3-}_yz35Yfa|umz^YMiZaPEkFnusj3ZTg|s+4hxBX-2L-Mw*rW z@f-`N<}@Cbiq+4`t?{r_a&C=^#W-AJBQUoKMq?x4=C-jB^;a6EOa|3o2?X{Lui+ED zil6GM6)?j~YYKS{KNc7JU#m!y{}Jd}qB(~Hd>s+aDJ42hToCOPFcU0c@}2Ln*q4s3 zZHv54z8BBFoX_sy_54=4Nd?cY3*36KHq=X#A#A+X{v7 zLg99IIo$aDboEW!?_)65JvM!{Zns60#Lokpdujm_Nx9q^AkS=c(e?CtJCwDyD0H|= z8IM<3mR{=I+1J}*hGN}anu4uSyGS~`@4Iru_iU!Tq8*DYZCQGujxAYHZ9MgCH&%U? z?}FEi`oEV{^w(sOyrDYZQ>Y@B6h(GmunY-no_O7J25FKj*V9=HMse>1G(5q zpR3sY%?P5oW3~r3THOMA5=oPazlT%H|sFr+1j7$&Glw^4IRBF z_pVZ*mkty)h^uek%=YIi1G(P(4Qv?p=8M}D%aObOd~ZH)798DpEgk#xm_9Kl7B?2K zjaT7wsAET8CzIS}vpe4iZUHowvcL2~4z%)&dffDa8+2sUh%)sdmeD#mo=KVZ#*z21 zR%c~$sMzh^+F9C`l>l~OiDX53d_i2yoGW2D@m{>uN?cB}Y3W2FE?w^YGh-15l8}qH zp2?b4aa*e}aXLcGDY_5Z5qk!4|4a{=Iz#kAMxnGV5H*~Z*jn7S+h>K*brRM-OPgK0 zO{dnA=1kJK`npyctG36m6=?OA-BQ}ZPU?%OJx(&M<|Naacf?(hYI*8=L6xH+h4PhG zNn&>os2^>>chH5`->86M{U7*19q&cmAlK}h^^44V zHormFhBl?OlvJ3KMV|+Od-;(A#1?WVArNiuFKC2d+>r-M>R*(Xa;hDz)K~qlS5wA3 zpRm~|$QIJv_H!wM=u1lRo!Pelu{+oS#npc$r223C%!$f4rrsW7luuS`gw82xW7KkQ z8O?G!EnWSbP*2*7vUrVv5@Vm;xwifRCXo1bu53!BlW-_Pxmn&qnb`U8FwN?B|JwK?gBNwj5Q(ME&;M535 z`r?2o0veuaJmJBR5v%6^!TG!Wc)qi{vNRuc;9yGKmkzVI_~iH)bbK21{#}Lqc#wA& zs8z3S?fSK;@K&28rmU1FkOz^vGjt9x>~B!c?ROFq8wk95eS&>^@6&2gDUVjk-}isC`ZIJy&_e zFl{+435QaUXW7MxBNjv0MbPaBOE2AfpXm?WSNesG?2e$=V}{Mqa~${zrn8!;q6!?! zS$4`)^mgbIo~oZN3QkvK6*O2sjUargDBfh^w-|)oKrnxFoHM>jqjPz@o;;py^&#Mb zZ%;%{97;D@*2|_X4FW4Gv0qKV!BO_OM^*MyU#lEvrL^ho>OS3aXhEa4_erC*$S%gn$zc7BrH!`i?t@NTQnai#A4ILw zh101kI#Q|U?8SqY(qmt_=(>4V%(!pww*$s(f(sh-%RL%@dbJT1hrPj;5NivB-f5z-n#@VdB&KOmB zmFwS%Yo@t~AtC4Je; zsNV~y7i|Vwg&KV*rB->_uot$l-B0S)nz7j#0)oX4$% zy?YR&q$V}%zD|kzuoi3V)C9oVOLoHzjm9@RG3W*~;+*u9Qq)~{!>jf*ehE{uRo%=c ztXWZ@${=W6PZkGS{qzRIe{r(m>Z>={A*AsodDraXH-DMJNQS5^2@ADnA0Gcf=Hu3z zv1K2QRH)h0$EoS|W{O9YS>jLZFtE1#*Lb+%{~r%gf#>Dnd;dlrUhx!psN$=!Uae94 z{|!U;gP|z<$}m|Ik#1q*cDruTlXj!M5r>iUB$4*Bi>6QLr3@6dba)PBD5I}swD+94 zNOGQxS-v~3J{c^sL5g#yzhlfA4;Gu3oqV0FOa?Xc>^ZLa+aG7dVOc`YW4f&T?LQ`n zo9^eiW$JvbYWc6w$&!IDlJsTzP{y$$5mr$f`t?6`DT#~6>px0L(DZK8L?QyDjeI*w@9Tuqp( z`coZc$F1%?2nbroL)*U5(#CW9I^wawIxY-3HT)V52B(hdOUJ$2Xd~*fhmnJ;_2W?m z&je0GP|_c>Fv1ql8S$c1ye^WTxWDRlo%I0`?VLm6SX~7zfJ$HPYM16CcirnSei%FE;ZPWZk^|M6vlc-1OMPVOfk4w(FW7?il57!`oyZXn{cd22z z*;+qfyHW)DcUe|8g&VLy_f{5r@2Lf2ss5vojT9$cDu+AwDNM+nF6M1l$^n)T{uWv^ zyZgUI%Xu-wbX&(taVW@{Fs$X$-RW@BX_IH~31w4(MDA9=!;9g)Q~uEzbfEB5)n84D zS@@_1|MPI6tPX^qWeTsQa_7*zhW*Rb^GH9uq52m(n*!%~tGjW8w*wkPPiQ88y%rbv z_p9|`iifP{cy1_N?U0KWnl8@$qt*nzJo`_4%%;r;aO@7gphW}^sL?saRDC&1QJPPb z;YTvyna!5xlfRx@YCZd9ejZE#(40|LF6Fek%L2k20lRuz4_k$wQ}L2{b1pS?n47aI zpI1QtCG+JYl%>s9hDyaS&#HW39`qCT3RK$iF0S!*jbWAPK-No(UAqo#QZ@dcySk0C z(iTH=zvto#V7OY~r9BR%>8_>+=MR5Ys#|>ZI39lKOB}6})jKJ~oLJacW|4ee4%{~A zr*`iEV0>Fp`z>{|y$F8#`b9zQcX%;F@q0eeAN2FT{4nFU2nT(6575yclgM4ScDdM` zy+jxNiHNaX@91`c`RLE)zqah|mgZB(ost^74fe`v#&H*>7M_9|OK9UMq>Z;I9m%!i z`yu(YEn^Or??0Rbn1g_iBmw3i;Fcu790c%0m&0KW0zQ@mn1g_SP6Et9z?}-<`-S-X z#rVrRNLtj_y3?D)bp9o0+v=Yrj;)ki^}!I($L*V`f5N^&{a@^xt$)hCx%#K=o3Hc4 z74U`nXYJcrzs^s{}1=qiOA z(pwlm%$qrk!_F?--h#_g+4Ohzb=vzy_WDhn<1fHy*J5_z@bc;K2l~2Vhrh(_M-iB} z{}Mrx7Bs%eu{9UtPuDh4)@CNX>DmSY_-y3U-__R@vbk8me{`!q>W2|69E%Phljv@K zMx%Fkrh>)0JNh$vsy@)Vt{51Nkb<`(`-4WQbvSp}vPYf01M`ypJHRy&nWzr(;c*<8t=^MlU8V%Cm!Y4yQ_P z6{2ikHe_Ok@>e++^N}SvA)v-)XL@2K4mLT{6N}Lqv*C~;;Rm5t6B@CkRTv}DBEl!W z2*!^KBUAo~_vG2EIjJ|lR~{>qJlG0?lg02Mh}Aj=`fzV&E>s;R7{5h&!^jfK#K);G z+3HwKUfDxGMS}~XLzG=tZ&%16y23=iH}f^jK;m7EH!xH|bTBZ{IRx~xrrX;cohxUL zH**wn)!WkoO5CABb02mwyUD8CE$ar++CA8`A}PWGuXn*f$(3MX??RPeVS5R_?Qz)n zgQO21rd%#gdVpIeUfgluF&$la(aD0;`Fvm8s6Qu9(Yd6R61s#^7b=I*u`I>a<;@%o z`MDaq)9IPx&B^w8Iy$t4UY%ixE=Ym@bD1{mTz^>D$PW8W)oRgGBaoJaltd^;dGgo1#p1_c%g-=TFSmj z*7(V6$4SJDF`X{)L{Ukua7kwQFbz?Xedm<5Vj93TF4^DnX(7ee{(ss*#f4i(&XQ>> zO;?x}rv%ayrPkyhAbH+pzchK{ zP1t$k%_X~ObZF)l3s{ub18=I#n?{$Afsm!c$6)zQdb>^e8~(1DPZ&~1>Zj$lRBcII zmNTCt*5%_$CjD^?`jJ7#Dh)I!pV6=cV}R*0)r}Tv!9g@aXtGCs%=~HAH~};H8AqcC zAC-V`bje9?c*1-LMZ>qicPa80zCR<0ijD%1i=fltax(3#jPXz!g$$w4k7a}Tiz_L`ers7B{+!QOKE6dp0(x6)V{2{-=T5YMr!AG zMN!k1rl6)xk!j@CwEbL7O?i4S?V5LVD)jQ!leP6SP}Yp^cCQSJmyg5CnfA6^2*-r9 z)K#f3VB1UMZFl9kY;*t)?D*D>AOl7*ec07{4TNl-T9u7LqTR3)OmJJhb|mqY#8KK3 zEnpGt{gb+n{al z9&>invfy(T=vhEsBW&I2W33n}gul4bv25u4f?vH5 zOf36KiJZuDg7iiBD->1%*=R~7-*uXqnyFqw)Ro(F9T+Lco?@}mM+>QP+H5-l)qzSF zKU^JJ4%zU388kQ|^9Mfp=y{}dceM-)Qvwx}%>otA%Q5vFgduefRC1q46H;Ec8(Ev` z{5_~US%G|YZ92#ENpHllsXg7tY)w$xVyu zECBmCZ24Z`u7FlQdV;|2e2p`Tyz|zV3D*HXu_#~Tka@b$5`HM*c87QO;F02Mc$fn6 zwYRq=>}v^7impo5K~i;2&1b6$_4Lp7`xpED6Tbl+VS#c;(2R0~>2T6>0Qll0Wf$?z zU9<*Rz95NFdv)%pTg>2GovM*@2(Q6A(a5_`k(57cZ~y!qFG^tk?ki?I%=zk5{TYRzIH5d`Py;zdxHHQZ@(w<8x0{kpganc z6E}M`rHK|1MjdG0KSLe7#Oh!@5QT~w+Xh@xgEoo`W)nyA?W!yV%Q3i`&9KIq%XIV> z$}>jXvBaUy^UgFIv^)Buu)A_8v>Jt(Ko){j)zM<8D`h?anu{H)ZkqHw&^+*0ZeEA?Tg z(i6Mefz5&kmC5%qyN1O4J)!%_)PB}N0gjN95Nqmdl z-baXM72#2V&1mD{52WJMJK9#I&hxpL@~S_kNb5&ODJyy)XC@NB9rnz9<5=w!g#J=n>35tPGiqLkE@{qJV( zM31b#fUvn;z|Qn^Cf*0-J-6XiE;Ao&cw-vefmzvzDKkgaKd)NJu+rfnxbe!zxct8S z!z0xRdD5|GQXV!g63A8Z2l7|Z1Pb+>IoHUUZ$eGUUyy%js5&iAkHH-zXTQPSl4gzb z;Qx=d_kfeDD*w1|?wz^Qc4up5(sv0Yx$ev?NtUt+E%e?I5>OJ5u5w{Ffxj#p1BeB| zf{Kb1sR|+jA~tL&_5!G2fuLBh{q4Pk_xpR!y)(0$@K-FU<@me`RKV@_%Le6AF$GWzuqdn_UDYCn#+}^G=%lg{8_& ziU9OcQT-<~3zNT>8B9JWBQxnKVRmwcVRe_V+Ews=O{m&HK#<9dw`VY^cOjrE{(-FL zxa_0_JTn{V%4oYJKpH$J1XnyLU@?)A>|26l5}SMvva0q>RMJH8unnUj^J@5u8#l=1F(v$~^r8Vjr~ zbc=#=&M^vpzIirm8I)6NRSDxgiGmJD7bT4M!dY4Rvs4~yzBhN&<(sZ^hmrRtYlkWI z8N`Q>1tOyAGx58qt$3ATQO?DC3k!(aeJ~RwP;1yiA}Qk%Z_eH>ubWdidjO{aS@UMh zI>H)PU~;GDSMn)Dmts*>j6+%c2=c>C%4D< z1)pLqAIAG(d9)+QjPROK8G1(9#QWn}+cR-|g-OJO>%NMmFB9gG;d!(J3VOT~@bLk} z-Ij127`nN4trxw9-Mv_3mcDPR^!2%{><0k>3EP7)q{{S1!txLth*ezB%jW7(>`>O)u5R3go)B%~ z(-%dTDn}`kHRNDnoqKD zfAslqIrLPAi{><)gT8t?F2{fi=kw(t96^$5%ghnVk)sn?QFT5N@2=jYzH}hzUt{UD zlxbga3>au%VIslN_O!L>{(XuR{)FcHTzo81K;BY>@o~6v@nRxU`RP3ST41)upxVuK zm*~a7VK`P0Q&-E3z-n>*2p$qhLu3X~Oq}S2faMNtyrUfA&f6Tm1NgoU*a+st_mCxb zBL*RIy>+-hkh(K+J3a<{RqqOwFV4~yMEbZQWy67PrT9qV7?k5fiDQ)2S0uwb$7e?mWk2>*x?x1&2d;eOm4@6BbAd!r7X5? zZVZb|P^%ojRjY6vARm3d*(&+8RV+mqpFo0q+A40{)cSYjf88!GRK0DZUFvF=)oLW| zk;Pv-mbEpoKA-e#lxoClh|xd`v3h;b*6ZmH^0HpPsAT;fVF!Ub*$s=pv9?aa%lTX1 z+K+s$O4|RMYLi@bILyr&&ewQKbzQNR3E?vM@gu7COgKmON1c6v?2pOrTHp2mvw`;p z)qThc zAQ$-Y5hUc*+W1J!p&-7V>6RgRxLmJxPL$5bH)c1lpp!`$EQo)mK>)rQW4b?yoqnx( zo08oO;thr^M9EE9qkjsVhWeglt#KK6;tinPpjp<|sEk)xvFmGm_OG;<98G3 z<%a3*=AdLgxF&TcbJE*VcQPNqI(PB&F8y_>JDDHemAVIA_*+x=D(Aj6b%TKB57B^X z*Eg#y6WT6lwm6kKoHmE&#$SRbtcSFxZ)PaOcL6Rsjew5S`zd)NnhR-Dn+3C`Th^@h z@~2}%;OD0_68?75^fV_;cBth@$Z6|?VH3t@kgmBtxb^fXZ_x(#Cc@M;NIN0ne<{U4QATrq)41Mf^BzKvPMa&Z-vIbS(iZ82{fQlayUehPsRbHxCPwzZ8L(i8g0NKN`)DAYubRi zTM%%sF0g5*ftpG>ip@1}k&QkG;(I7%XJI-GQHUnUKN_PPwpPK1k%p9Z{KMwxu)2*- zq=G9It3gP_VB~m}CMFac%BFH^9MFV|*3nJEq~xQP9mar5;IJ4}S3mKFCrQ3gbhf=qpt2H$1y@K@Dl0NOxp6k()JfGHy z7r8#nnaz}rdI5+}t>#76Ng9<^qNctOOkjY)!Fo-zmXT3u`o4O) zui=)lyTjKBH#_5l#D5tr*D&gwEsv=45Os#HZKe(#Ov;tFcWJIy+CfC)yy*2rs*h%( zD>1p(p~6h;%v9n}7<0zH@h&0cc=al#Cwo~Z{tE|t@warkr@Cr~8L)Ewe*v>-YD*1I zD_nK8JH}i+$el=U*-JJunb7R7psK2?&5<$3YAe;UeY5{ffyPj+cV5OG*t>bFvK>sF zyZS;qYErh9|E9i1p0B=|_n-2f<_)TkHZ+(Sll z$U+^(SJ&(>l{uhg{N{elGXFvTOp#t~q2~13yl^((iZ&dz?r<*OVmOa)CY&!S4dA;0 zoF$CcLf)-xGTN;eUG95(0_P@;@A%tlppe_lVI0yp@eirx$>1_7fd$#5eZ^;{DXr+AAC&%P#D|-^Pj-N2%*( zxt7XxNPC#EXlyzP2hZ+U~WK0)rTgm2OEB8 zBdoDJ*sv5o^p=hW8+OD7Rk3HVVHq}cipD;*qiLgN^Kg=QAnnp@65P8&95lDcxR>~d z8-Qo@N=k;i3SAa2m&YdOkr13cS!nv4oip4n+~9Tk(X$+@7_~M2ZkCPWpwuXuwNx>q z!x^23PH{U#L_nTLl{oahmJD14$CoM_ZhVE&yPBSE>C+3HnTh+Eo~z@RDHc~Ba+ON_ zD(vNKPcFV3%h6#rel=z;W5(tev^^ZtD|x#O64SL)`5EqDz9&Dvs*AIfSx4CB`TdvOo1aXRozr+`PgZfo!*JFx31xf473q0T;McvpDc zAM*;=(zY|aUwft5GrIqVeJ(O%+>P|!qdpoPXEoqa>=l~{^rK_&m>9s#%V4rQ3CO2e z_T$%r7<-}JXs*}En&lEh%;9L*AMa1`bhC>+u%1BW_E3BUQ5uNVQS0)FvVd5eZkHaM zwq0^-_fEuPKRu7LvcJ#<^pk@HS7ME?2ioLceaz!nTewgK%({eU?H?dPb_fFnH7rQ;)p3E#q5Q1@}B3$5l>I>}H zho@A>xw+x!>Wue3n(4jPc7uRe@fx+7m8?&UTsIPz!>F5-B;w5~zMr@6hwS@)edEK-{sH^m zW8Zu2d!N3U=!53C-@Xs%8%7^C$4Bh@QGIEu=ws&mxP2egH;6uIj!)V56ZZYIzBKA* z%=NH+AJR8I-0YvV@8|6M1^a%{zF*QejBddgV%+77KXIqZ81IH3T}?#&!1iJM2C5`} zBcCvS6W>zprMdXcSQ5IQ8I*}R?2j%ZSw8NoRkhN~R4sn8+z?)HsuO^Sh$??-wQ;we!e*bpfh3`mt>^bkfw9)&ljTVB436X2$ z#mJ7bTF1Au8V_t)TMFaD8MiS6S*R86Eo9QjlYAn;i1HRgxChq-kZ|rm+-z|_!At)?De3P6vTht^^q(L?RivO@1 z_}xui1o1Lem1;qUd{zr3f8(u6%gs67@m0Z-6RaOhJ;8FkzYcGQrLNpMuN6P&1Hi3P zwWFX?s;%Zk4ogQS&zCzX4;-2P^j)j-GR*x>y#VrJ8?IjwZ42R@$a*8^jP%$!noIBbEdT$qof+Woir3D+TG?Tq-q7X zv(}41mf%vq5I$B8d<^nW66EinhP-R%oOjd-Y5&f8+QWX3{1f4XYW!Z>km1YoJ(~Xl z7L1pG0BhK(81ehaak2KW>U$4j-cQPv1u#rB%B8z z!?=uv(^%U8&hjDDn}mBVzFtFDiIT!R+FlqpUB*vnsMnU{?#vj68?cw@m!CRilp!nVky^+_Za&@71K5-sUTiMi}uJ!$4 z`~U!wwf=L|VyU(w7eB0ebr|KN)6{TIYCa#m${fj@b{{0B>!0z5g=SLZPqi1>aAQ~G zd)s;YpON;v&@^{{Soqkw)LgsU*fsG84JWS1M^y9~Lk^#TC5eyWjQyj8mPUU_@faf? z!_kqSKzy9X#_2$d`ZD#s80F`JHi8j7ti@IY?YA;0Ou1bCIqcC(Wy|L$Y9wt0RnaEi zpvQjj_yn9T5}@&SH*U!bS|Neco7*x|jKcgxos@`kd>j;_2l=$1&C-P|RQu(xT*5xp z=}2~^L3LeD>gbYut4UtFs_*Mm&m=b`%l!!eN|67Pm@E5`v`oj~Y6|`lYgZ8p@wZ4+ ztnD1e-&R{X$r|Gg%^DfZ*%^Cdmdl#aRwqR+{v@p!e+szCK>KX_Kuh@29p2uDr(+`U zo*~bVPS5keW}bGmKAMXk1TY(Q3HW>hYqWvvxI~wa)?g_cqO?7-wpM?-bjQb`!SS~t8-OL@}4E=^`RCG~iZM0x?QMyp(r8}=hAH|Ol2}%e;=uvEhiCT*8B$K3pKi%HI z;Pe>LR<3gssq4STdi%XS?Z2Vj3;&e$Uv12c(kRx>4~^1bUNv!mQ*-extWgZ7x04&J zqB8YpM^c-hNx3y@-NbnrDPQBgQCHfu98`grllk}^K%o2P<7O|!G=z+J!dlH z*QzDxuTKzCs-47I`5kN!g(lTA6Pi$#=qys3zz+*az876R0-Fqi_-JA@0+#D4(T~B= zZ(Xw|QwXA$HM0fucLCkF&aJ^&?+ozg#x%6mUPMZ1E86aRL`x>%?;Bdfx%f#eO+HF= z9toz;wihU;r-+u$wqKqy+k$UGPpv$u)&4r`{j6}XJ~zOdnG#u#H>VgR?x%4VnGn3_ z2iVdiM|9lQh1N#}%& zcN+emv%1;4t!`>z{3F05b@OAPQmg0UpI~X$P13FshjGZ{ql;8CKP6IHGhdxjGikky zChsfhUd<-*f7tTZI8NGTUKl@{X3rB-$v)!1WFL|AhG>igsR-3g^e*~@2DhX9AOj_j z66D^B_X^?lGsCO8x|HlQpkUhf8P;YCy<<0|Z5C?ZrI%jlH)6wZ5+<%oI;FFR|2Yt6 zotQHceb$Mq-NbHjZEflpy^6x+ZE-?8+}0xQU?%nUDb1b#(7Kha9SzCzPg~7kN5!8f zWF%WfAycoMpE2hwoWY!wMuH&TMCLt^#t;U^sg)3!%~kO)6q0p|+wClFSr)gfTijgH zSDvM-Ky9UWC5yGc=*y2H=Hj7!K${Gs$?f>15B-HnPIt9oetL>ICk<@e-*31s=7zRnLy^eoHytMnHpS4Xyzd0`~ImqFmdv{+azb`7kgn(E`GxjGk62`H! zGo}ZaM@zgk>#iE+qyHt7dc_TdT>NWXMVPdwFvRsdg@~W{H+XgikhZ_Ya*2Yl|4uP6 ze~+olYH0YqkYnZ8r!vEJ;=7qm4w*Z_5rYfY z#>}FiySnm@s)&DW6>;TDZQ^LJXg8-1de=RemXUWHLH(=EGA6VRd)~4NmeP(A8kn-T z5Cufmx@%$!UHmtqZ)Ly z@|}yH6VRl4{dg)t>|l0ygY{M!Gdo*dK(A$Cj z_82(80PC-XnemNG%uprM5VCXJgE+6#x!u7sAN$=)bm6u6K#n2 znfN$DGV!sR*}5#PqMEc+T7K~ZA1A+7A&X5J=BS%ATnZE>c9lOxh5c6#K`z9h!mYU` zY*$1lyq(H6Cqmqd_4W>X=i<!Ol68io-e|vOppnSfw_0 z(phsT4d8XCi|koB>mP{M>P5?*fR3#Tz~QyXcO0EFaY>eI-rduU-h6y5qp>zSXZcF9 zOKQs$LPK6GZe=cdj4bffmEy2)tJ}sK#QvKLLy7+_^0spBOTOPt^3@$)j@i^0x%v)( z`Zl0g6Lgt3%-^ax%w6VZhV?ewWv!c`HOs!U~GnG>L$?KP-rxWq#L`c-p)spYntcxw~^<}|Cf3G zg9;VSnV6F($>q}|ZM75_5q+#d6f9 zeQvFYofX%b$IRWX#^eEl>KenY*Bcm&c-M)EU+i1O9~|D-Syl}%b(T#d$FjT(GRb>u zqi>Rni6Pn51v`InA#9^p`0+kMB3t8CEeT$^2_sD#pTL9>|B{YN43vepJx;7A5mZ}J zFJDKGNe!wh3@wMgG7J(c{9Tm_>>I zT>LIk&qQlOF`6gWDRlen`SL?q9%NTO`j(>WVFh%C5hGflPnvCQ7iC^sn&ik+OV!nL zPQ+(HZUNs}xmkRB^@4*AvE~BS4eK1I+*;xG`q#g7BGtFFV0)ma=r4rKFuLeyrd(fy zQ7%4$s_E#Ok&6%4QX3y&-^1*CkbMv3n`fHV>Fi8l+Cn$iin&@-76LUBUq`S_rTST#RV!Bj|{$d>HvCc+IWYPN!5tam$nj!iDb(H9?79H^d zf|oxGl^4YC)ABroJBT*BiWF|=fEz~{&9=NlC{UXcw&lE2IZ;qmywZ5rh+fb|k2AHw~z@7VR;5#knW5;Sg3+ge_O8rdeB?L&dMS3hF(E84DESc!%RtU|@5Z>NT4A%JuYsDJ@o;AQM(+j(1KvMY; zwPc6)7Sf+Oy$Kqt2O?kbO5Z8lP{ ztYxC-p#WE4>&fS=B?wrFv$1(7vmpy^eaSG%CdE1c+)8MQ-A!qV^(D~wIy7r=3aHV9 z^JJV!WQh7`cOvp`ZBHrV>Ry#lD}etV1hDyJLQE1_@#}ej?@7>5FJT5d+RHgJ>&HMS zzLyfZ{u3Rj4zfz2RG-nW)ay@GuR(k&(d_P)vv%YMxO1TU28)PuAphmbKeaPw8RI)Y zFtnQlVeT8Fi=*LI}DUk=M*C{u~|28(ncpG*L^okfz-npuu&xl)4q zyJuANnMA&sU0)4Rto2ofU%Zc!#%oCgL6b)WN*;o#XhNWwQ4pUd1eVwFlr1Tr5UlL= zdT?&XHdA!~TmdS}&rKjsiIZd!#HSnJLkN`30ZvBg8F&~GS7+ICrI=DJLqU9srS2fL zY_3v{K>Wy<&(=(?P~vH_`ShNpjaZIpJ`+Ww;HHJK163iCO?8SC^U)t!oyNF=ecqhp z$`yBL6}&GMWa~5PG83=;T3+zWEEYFR(pa+-uLGK1@qt*`;Y-xhsfnGP1#Lvmwpbrq%L1-F3?6#lCuKLWL%-GQxwBqKX zAJK#DdRSjZw7fd%AoqSeQ)r8aUSC#iE&Q``Re zx76P+RDT4T&w>=I z!BIe9k2gEzL>_F30CybVx@XkhmD#YKC>*5kScpGFU|+5a*71~^zb_=JJ&M(nYhC^w zLM4-RNA`*HyJk>V@k-(LEAquI2LI~lcv6CdmR=JLIYA=ZcC@9X5AIMl-U~~;3_>Ru zLZdl465T_uY^}xzmL(cURlz#{+MCE2`#572Mzls*Y`ut|XgSBDLQ%I;x+oQ#L8Um! zg6vvU{eq-hM*AybDS8oMeJC(uXDT!!M1;9g%sN;xHhND-{9^|F~<^f95Y?mu4HSS2;_m3*8dUAU$)H` z>Kn;KkkTY#39T0}jf4$Y!X{nj?t}kI>1`ks!+~CI#)r`_Gy;;IF|d1!zPrGXN(pmE zj$A0eVCf8#uLT|I9|D`xMt9RuZE+0$6ZtRXznuR*{6*EK|5LFS`D+&BgvL9Bf9)(P z{eLV!G$kbFMTt3)m=`DJWMXbi%vUDnro_A?F)vNb%Mw$x+ECC|t)f+RkMe)16ZV9^ zWw%?@lY!Ciurc>GFZG;FMW=hcvothb1*mS#&A%sR<7*T}cV5+tehn;lbrOCRyES*r z0qN739{%Wz13g;p=NzeS=VEOEE7nbnnbq444;xRT%RmPkNi3^AuKPmTPzB41&V6%ze6x%-jxc&bDC-nkpGo#V0VKoHWF*-Zz3&|#Xr zUr*A-PaEV||-}Lo!#oTBr*-hLn3lf`fvh>5^{j=EB2#Idi@aIHKPHtDHTb zz1EEA_t-0e$FHJ)I)j$-Z|!?FY+{#IZ-fIqwxQw}+Rb#) z+W=#G9mtg16e+$2pV24DoK*Y$C#e)Ee!EiLPO8E{X`~holr0|)^18#p=kPY?=;heR z$n6>5L6REp@70&%75z~)eKU)O=%sfOl#fR!Nd1M|z_qr@EoAv*kIo`D&(dLXR ze^wg6lG&cbpPdHGn-(xP4Y+1%Krq1M>+t&F^pMUpD$%5MDeRJcy(k^>gRt4S|9^eCm@ZLqmUbs}c|FJMgt z^^>Wf3a(93yfWS^!HdJZp6K16%E?|u&xJO+yh3y)@au(KH9s)0_SAKy{QQw}n0qX~ ziFk@u%b2W5b#-TfJ;o74UjC(Ay_iO+!6mzysJzgTsj8x&8Qn?h z<@Y4DZzqXKFL`Ea6Sy<|q-z+iY6F;t^o@mzigu98*czheU{AemJPK2TzmwTDt|E@OhqYns3Ul}0|(f1PO zFzQ~y97J+-(ah4!jxcagPi}Y!X*3tLFJC~JOeLY0^3lCSY_&j7jw9E~vL!r+k^<3N5pr=DY(V8+ zW66=$ni|b~n_l*k-5bCT)yb9kKJpoTE$!mB5=8-_xyp`1EiZeN!XeiLG;ttVx*Y4% zV&>Mw9|Ulluj1yNZwtWwc$QjD#o;;;&)_ogChfA_?rkI&H$Xr5YO(}4^ zdW0Xj)h3?o5T*)d>rudqEuQyJaIks)e*87hOHG>;uvi@YX!?IypV!+c2*~Kk5~e|E zU8&FVFP5Se8{`52P(~UmWi_UM)rS2wFFKBt_qq^GOp!g6V+872;XpipRpioG(iVc18 z1_fe}hcF>G-=JvMf0KwOB1Rt8VcPEwA@n49yYt-Ly(KSco#(zET($_8=zp1Wi{S(h z!)CPf9IK^g@76Sc@K!z=VE%E1brWS$@MotM+^I%R$~=J%y^PxKg#x%=3m~V$bf0Lu zZG%MjZu_#!s&XuyFrCGmocLMb{+!|N-V~{~=`iXp<+jpbH08yS1oc~iYKjyR_s^&1 z8^#}_wUcaBe{^ZDu*54DFtrA~1zrg(JmhFvC7b*xK$6X?lnuebLVv{}h&S;TtHL;m z@S~3dIC@afKf!0T0-#6!3@qFK#G?VBhp4$fMQG>PogD7WGL{BUWN7*5r{j#F4f{NV zKb+%996{Sg`DxydOv8TN3X_th=ujYU1+BLXfQxnAe@lfUEk9-pm1Y&h^GFwejzZMu zjSVSg%P0ON*d|#e-VeEm+|5cO%BMYIrH@0wB?9`WK2Lz{hO1I0{xEW(+4u&MOl+Uk z&21^^Sf@RA>b)@ao@L(kzOnPj3v#use%j$b0Q^2w1GaK}NItrzor5X=C$iGRkQ1Mw zx<_;?rDNhDtivBV}l>xkq~FHPaeZ?`xqz zFjCw06~-P?4rx0&6kSJ&KS9+zPfta!e)|YX610yJ-KBs&f@w32b~fC93uuIQ{-$R6 zEO>N`YTuWSKZjj}$HSQM-wECDHnj>>ze1v0j6}vkxMEGqUX50B2HD3ePL`&J5xwCW zrQwWFBF7cDg>y&~AEVES`kc8UiBhw+z;sNm1T>=v1h0v z=YQo78T~xz!1zEox)$+V4Sau*he>iU92R)JzPcETb)H#|NnDTs@Bta89ISm85wdbBIwL3t9H$IhPeI-qgA->_xDj=!L~`l3Ex(&rYCYkGfKK3_?_ zSwGk!NxY#DbJ|kuBcjfsj>jIKpwCx{np{wdApqKCa-OFr{Bl}PXrC(gW(;eJl8g~$ z@IKDJh+V&c{-HaL`b7vr7B@*{=sq|bQ`=j))fs8Si@wdwPsZ*N< zp)5|OOHOa(d_7~cwC{SAbGV-A?8$DVJ%Dqaz>BRWHHFWlfSJnD(pbHhcaL_$b&($| zYIH0f+fyDaT*Zqft7PrZoSY>iV|M~3=d{`9w%O;k+2^;}7hre$D(;q9ox*DnkT;yY z?8v6Ix_Z`$(N%<_y;gx?1k1-Z2lgf;F>t%37B- z`g(>(yLL3I`U_PvC`UQ#7Q}C|tYCitWXAUf{G`++^5~P+XT4y)oy_DBZ~=XR+?h$k z@x*~G<3A_=MgHW5c~F$WeT3~o9zD?0N<(uZp7^Q_75$-Nzn%gVptuW= zFVm#K@2`8Ec(&?TW49mEXFYMzq<6HNm>RDALn{-{O!N(k#^KL32wrJ#wZ{0~bewoLfnxHAHh{p_TD|=J$-T-c zYW~7_4pEc)ck{dp-{O`a_0m7OUV5?Xr5n{tZI5&b<;qen=H@dgO+DN=S0Mb0hgC)M zu-8wH=3{V(uVE7}EQt@;&x^cRI>NjkKT`q61w=_u;GLl;@NoEp78() zCY6alp|ARt+cyn+gNbf1W&#acY4El2JH-2Hb4ab1(~fc0AQOz|Y2xS+jRYb_bBUnV z--VR3^jtvdsG5UxXQ-TLq&yu{%TR?GH$Z!2Ih*N^&Q@}8(f)le%uxNM98PL~0UA0Z z({phnW+vX5NvSEX6cJ6A_G9$II)(V*q>x~^x(Don$=&4C92zvw610_nwGi4quy=^v zi_LaCxsurNxr7~E%ak+yM^}fKcI3(Av;sqZ6^Coadk?tgz_lD!j`1f(32rQM5CeOv zJldP3hzn5J$z25@GpQ)$uzE~Oddv>yhL{;LcGg_)Lg3kKQ3FpD`}WQN*~>vl0b;L3 z%LpiE8{6X%UFHI!S7A~GT^ZZyqIr$0xE2)EiJjcLp?pAt{(9Q-~$gdYbVb zroIZ~-OpHF4|-y8>)^RGdJ`eQ)VZ^^)2}DcuAFDhwb3x$)ZkePMq>rFtdQtwY8erc z8AE8XTTU42c?dMQHb`i%q`Wr%V=9c@t;$J=O}ocWuXvFX3Z={EQ?c=h0WKZ zc{<3$J^biK2DoIhZp7$?EscX{m~=zYsiZ4rop3{KF83quOPcj11jMKDfw6`ck`K>t zn7!08I~{K~TYy?BI%&w}SOY`!Jv-y_1wG zZ-wi~)q{NF@m!vH&G23Z-euwK&PoPWUByOahRz&%#b~mFiA*kEz0SQ~mz+NQI5z|# zJ-NGzl9}8?Ms{*f84yH!VTuMZZxg#%qd8W=VhYscP#os~PV^xP1DsU?ke$>Sf#B#^ zVCZA`i?58oSheyOV^njjn5LR~#V!SzgE5q?q7DA~H(Ow*K~n9n>v4&peU_x?^g~L4 zOdBVRjdpqG%}s=teS7{mm0Nb85*I3Sl<$=~XTEt6>R*(55;n&-maPkmmgVT5V`G4A zo7oQ$atnBPjZBR`UE|R3{DI|;cKmaZ_3n70`Qv|)^+Z|Ih2cm!GLtWqLCKFbGn_om z%nafH|3VyK%j8jVXD1KGP`}iBfNL?kXkX1^uVt@Qs_mRJecthYsPc~g!rIJ3kePh3 zHb2Y{&qfLuvZ&VRj=HJ1u}cTpC7sQzaZ$2%qr9%Qb~6iYTwl<%mg>GPczYk>XbO!9 z6r6 zp(g$wv5u|{WR7xH2fsVIc`8`0*KC=2JxvzIdqc)=T%S)?jd3hn!l!35+5DB-UbIOe z(H&X?OVKR=8NUNDz9iy;-_hh@7j(v)d}sRc0U+hR@ez9RBjSWIWQSqVbdWgKyB#Cpr+#GI z#hZz~r~$4P-UwZ20?b9Rntd%bYbtt0v&D}%6ynEZ%HvzIFxJ)K2mZAM#rreZm_#4O zTldZThoYW2#Gu{O5BI<<+Fr!sZyBk(sIel61&FHb=n2xY`;AWo!$uI+0uF)PfU;bs zf$tRfyZuK#O5bV;$~3Be{CAoX9f=VuL^1vc4o5;x#jeY+Q{SqATaWsdCE$qmpGuFu znt#dc4IMoETcA_{n^ghJ{rCr%S29)1wQBj1d==cZ{51733ti=B^02P*i!|t0ve3Yq zRb*;bu{B)lYp>zP#;L|hbnOgXwA=z_Tw0zxR-t9bB0f2r2qWg!qU%L@<5f0B@*Chu z%x%;niiqse`x#Tw9elQ()J-%xD5KjyM=s0XB*fz1B?xNz8`_i2$}i|0Y^gUfX05o? zxs^L&EISLe7!Ez8t}Xl=QbEMNu~zr}A>WUFPlPK0I2WD1jCxhGOG)X}aWr?nLj8yG zKQEXTl<^ttcDMxx8BmM=1nMQ}vHhcJigNn|HYyQy$^2^NH>}zx)+u^y+5Q+lR+z! zfUL7*WTEq@fOMD%jd;R%h4Ul-Yf-vVM=KRDQkO|hJ^RLA0 zw|-`G#H|F`%mE2{UiB&omMy9b3|}9=j{e2IEKhj+3NjIuGBX$EuZ?cP#YHa8Sqmj2 zRKho$U0t*MN4d}}*T!p!U{rcQQ?TQn2~kb?kg$Oa4_OK8Q0qf@X4O>B^wa-m7_WAw z@Umg1c{(JNw{_^AREph{1({;wH|#t$q3)nU$y$ln2D@5ZEXzI$)()~9#!(tFB#Y*! zi1Ksn1nsExU%V2knhryS)`L3tAb{n9Nn*D)-^sG;zy zDMObsnuCRIR`gkBsjG18?q*?ZuDTHzvw%Ugr&u~yz8N=m@j{e@VccH+O0hQDg_x;W zE{>c2I%cK%U_>_z-Q=XoO0JmOyyof+&Fp%1&R8s;3^s0BVi^u!hP(nXsT65SwcheOP5_Z%nJ#E_SWz z0BJ{8g=`%uDRHd}_WRZyT_xTs4U_}2S$kc`-kY{7GxD?XsI`vfyU=dCZvEUvJ((hpiw~wBrLzW$>g3m(1yfnEI*9ycc9zRNMnC*9OhTjfELI z4Q$MbUZBQOxLb@YruA<>Fd)%&^%NoKjejCcE7YTdkAYL(b9ojegA{ z0-YcM$Mfhf&O@t0u>n7Se^S`~0fo_oKB+Re^{wE|U+ne`ce*tG_^i3i@-s;ZtthZ@ z1$$zx%6sTsYUQZ-2i&mi&qfCU8yCteL)c!9cR2z4x!}e7ZH~138j-l=e6*J3+M)UQ z7%ZLHdO2H&cZO_@W(m;|7g;YdeUbQLs@4Z`4c%&3NTfy|mff(_eco=sjtW)58N|eQOK_~YC-OKZ#-kV$-{*5y>Uh!xJklOu z4h4)4fL@=}eZ_-71n_nkjT=yNjZDjFtnW@3DmPT1|49eD%FEVqROR)#dw0gCy|R2& z_RW}slsyBdG0Q7=naS<76JUWojGr8KNQv#H>cf|D6{{G}sQlC-!cd54O zC7VwSd38OUHQZYpFsm` zcGbg2=@r}A*lErTvqw4tz59pwSdH2le_@`H6s*{un9g&>EUaSg7suHqNIMpkDKaMN z1bI87=?n`K`{g)F*k4oFvT1k^Pairia$9#UOzcl;nr_ZJQ`(51*3VD!Uxg zM%&JAt7_@VwUy_2va|J$G4Ff(dhgoo)&t-Bt#|kyPRAYGx*3PxU0c=gWad~jaybSqaTv2(T57kK`{69at8*jQgGpq_Hh~T0U{21 zo46sny3oiEYTiD#h7aaBra%fk2K9WtI-JSR9hv2#tn$vO6}F=vuA+;2D5I-5f3G|7 z-{kzw7m>en1Q3wt^yOT{Zs+9z2-#(2o5otDSm1XLXqo)cF!NEg8=nTJA5Gs;d6dwr zva6;mHg-u^F-Mp7?Cs*km^y2ppSVky6yK{YA3W_&u!f&H_&M;zQXf2xl^x6Wu7*mr zIfI9}pq>ie9l0wdljfwCvZzXqR#UUNIjqjdV(Fn`2RTGWQkAh>CX@@fHzpRx#j0!k|Za*V)s! zgX@a^{vn~WlD}##{mYMI9V;-=JNzpp=jdt%zKu($$eFf8sk@e$J;b%Mwj@{k@kx}p zF=xtv?r;Mpo}g1hGJHOXv?Pgi&-16a$feM^zGU^W6{JX1E{zeDVQ4DjwcyGZjS;l6z(U{ z8BYc8Y|JI}3m!xuR%Q8qj&oe!-H+KJ^NugOw8kM38u#JfZ0tcuwqHL4UtdfxlE@u? zt`hbK(HS@wo7R2Ua|s9AU+fsziyGL1=uD!hJi*eE?Hz@KV+x3&1k^I`eYC~VodEq> zamqO&<usb-Vvy`5lww%mvn?z$^@VIc;S+Kv49nxC`PWo+-ZZbGx2W>`KSz_ua}68-^Ub*IHv*&LI!;{1@h^P zUxIscF7L*z=3y8pbCbsSHevOJesr|Vbe*szpfjPX4q)Eu%cNQIpyP*`x$6dg4}`A9 zzsKB^YHpT2Yg(MM=3g$AJLJrjJ0?~Ehl=RQP}=q6#$7=@R1%Kw#oC<6UhVI_@LD&Q z1k5GkpXkSU-FN}1O|HeAQ2tO8;tS{ri#91F;UP2LV<5XZq3FHLB{v?>>1s_IdpgOx zu<6R;x~%CcEAYmaQ=y+|IU$PNSTsOWrV+Z_dCGb&c#8)OE2$@o1f%V?9mnF6gvXDl zJtYTGhMXM3XUd>BB2z!qiHa3#!=Y_MY!^}AE(K)(W0+-bsYUJU1{gEE2TVv9`}xV+qSLJ*YVVAl$MESO4=1$rR|KznU$04BX-NAd15sU z;4T7Ko(3>V0nSP!PkPFZQM0IutsS&@N6!cP`}EDeu4$l`rJ!f0pu6IA%seRK>*RDN8W%GLEPHjKxs)b4NTQp;Rff}+}o5lMEQ$iz! z>QTmy%_}7?5`B+maqrkfk6HV3)gv^k6rD!m+Pda6ZSh(2c(SL1!MFFtAjPjnHR?S2 zy_maW=GjTL`=j^MI~tEmrupwoEVu}s_)6{Z--PQZJU+^{M*-||yt}X%Y&lUiUoNfdU_C9cnB~VMG^$eo zTMG+$ErjKAbW{)3i-1t`YV3oMm@=HU9*SGDDM@>q z(iWzr-Fhe%ri>R@iQ616AhY>|J{oHZCR-1dVso$*n}ek|eXs~vn~L6^+>p2TY3eba zcO?IH{6E0Iy`QH3zr-JYUbCO3{wrwP!|_l1<4Wve9_TJu5xagmD;6(;VZm9k_&+); z<`@}m%>C#zU+!PL8qWx!=$h6o#n=Ak6N=B=%?2}w2l(n3>7pD<>jWcw=xVoUHs%Jb zo6#%q3O23*PFw?WCVrLyE1eR7w**)X`d_lh!iaCB0Fk-~);!X|KOqGh?h^wOeNQa>1SGAFCZW0*WR^Sc^eraL`V^xRO_j7sz+j%kZk zUZdi!ID*4+MqpMe+NnQ@zKGBAXTqV2#-3nVb%I4*GqzO580R)m+i9jdcRr82cGP&P z2WawX6Iqhr!O++*0nn5TG+5)ogEdprSgdsvi70PE0pSaLY86qcgCHBDm{pevf7%WOgyP2}6#tQaOAGj~x+chcTEOpC7p z5(0wEm&G9o8A!9(E(&;QAofWm7rzY4h8k-QN-GiLkVHUwN8p($a)vQy+sOR7efUn^ z!sFeLn2U@C(jne5^+`z977mhjR9^K_XHLuWQ?#7&%v+DxcAg9%m){QF!UJ4>+%=I@ zCb!xQ9jk*~$bY%=x1e}um9xgnEW2PS1-aYQb>m%eBy{Uf+UeG29v$95&EGgnH>Y8|^eDfu@k={X3v5l?N#)^65b5LlfG;3HjDRZqDOQYP4e>OIHtEUr zct$f;rrNQ&k`$9?ep=*tg~Kjam-D>E`?zvyKAF$l#`?^9_6&4zDYt(XIdg@^oJkCfx%!0?6sfStcI4kuq3m#{u9%jMgoYccCcrbyuY|VlP6N&RM z3mz{|JgM>*@hC^76DegR`bzf|-)x`}S#XQNwWaNzhJGqbiOSjL+yXVG2{F3nY>UnC|;;<`a4`*eU7+6tnbLle)M^B={s_i zADIBf6^zcn32ncH)LzKL)w z?Zxz=TNXO^@SNHlYHL}YUxcaeW|5i78*tG zb?rr8-bHIk^j^>v(J49i#yNg;C+>P9$Yk{XkK^#9JK?dt=+zKfV{2u)Gh&`1D*Dk~ z|3RXO>51+k(Tb1SfU-=NyUe3gVVH6Q4h)v07^IAW|1Rg75_Gr9`EGJ9AY>nuort;2+`f zN%PQm6|@o_pEeJDqchlFtUyW%--pas-&IBPP>lz6iD6E3rsDm97IhUE#H!B3n+J^W zRwD;?rJ+A!`%_y1TO4oI1Eil-2VFoH8}#F$90q6Kn9G%RDqeRkZ3v6 z@``s`qK{c3eOJBFJf=@Y7jHdbo$W{8v}F3a3F~+^G3KSO^V*l)ntAE#yq0b?t?538 zMhfTOd`G(c_`BxPmw67_uy5&n?;}(U=e>+)bvD<}T<3BCrQ+TNSr&3HdH3!6}cq2Y})G2)8s`$QaG7NaWmP4eZ!Q80N4vmdwLE|rm;yiA7p z?`CEvFUK4j4*L83{_#axeTI3~q(8M|n_>@K94oVAY*%O=-SBrte7!5UO(unpYJx+r zcXY-&O#OV*ni|+QdYx#7Lw!?s8ratjF5YhzhJk&f9RUPoVQNYlG8$~ix24G0 zoB8g(jeM88d}aK{`R>t{uchC1zTDEEd^J@XD}<87onT$<$0dds#f@+q+_+ebxtFC+qUD(+_a_#20QLBPR6sFywr41NFpnO}w04$>Q9=i(Sa*-dYgtbrFtQcR(P?9u^_X99i-NrLt_o z8SPVS_i(X9r*~!ldn6I0_9^D1vRLocGw;azD2w4FbB?+WB~pUwBUFYT9e~G**UB2W zCp!x6$qwEL;ii?^4ymdf0#fLw(rY;>%%q4_)QIss75X;%I%_XL0sA^x%RL=+9ck1k zdEI4R?d!_*lzX|Kpn?$5-tYK2iS>R*vl?o9xISd6)R$HIx^o7yQEzAF!JC*-$O7$_dJmG(>mp(`}71^o+BWvNc@7IHW%};RhaWk+Qs_EXGsT< z2MQq$LTr^m438oV-rbE7^-KkfE&S?jvZkhB|ha}aO+s168$F`d+-XRr za*Q2O+QZZw64c@PXWO15Qj_nTHB}W^$=92NQXL(%J>l?t-(D$lMS(A3j};{as~+R# zt5;B-eYfiGrU_r#a)L|ImQ9x=mZdjbXLNej3A8N7QSHaqos&?U!yaP^Be?z8eg+ z$9)^eAm{C`bn!C4H^}CGDq$$vjyVOUq#P)*w{akr=R&+))NXEQJZ+;KNzLu?uCAfm zx>vWtLc9Y$4$nemS=o7~qo+XBLS@HqhVdd|C67+QYR*ix?p0*_k1l5_$FVp}C{hr=g)<=tfj7x9(u*F? zH)A^*zVg*FYX@Y*_1)sb>3#B}S-q6XJqolNxh^Vkmz$?2u^wFufX@srP=5BPNdfXR zM@74Q3wFEFm_e*PkNrj{RH zLuMC+8xS&LKsP$Z-^+l=jlYZ>F7n5JO0vGpptlLKEQ<^Uvb+n{a>BlWlNDdWg>_Ep zP1)n|gw`sS`XcVaj9mdTJPH}_hyUhW0+bPx8L*+1@TUdO0V*9(eatmV?!o zqH%JkMoZC0*e8~rx}JbwFaU|Aok6|stiz|(#)82Np2Ks3!4Awd`v;!m{Vv2@&cAk) z?_c~@HEXm1kfqJX<9=J4`vBb6w7GY|{q{EZV%+a&b60{Z=Wr7vkwk4OZB5@J&v`e! z*YU5%d~O2xvxc+02GKt>FgWC2IjD}#oDp7hY7&^QneY_nALnZC-am9jTR<$Y=sbPf z(^4vXuK`m(KdBbKUU$~v-FY8kFtbV3;(~1oJf09kB-pBV*3QPBvh_%G4>e3%jWVayt6Xo0&!viWTkT5DG*G`wK8u6%ug}-6RfdAY5n$jT?<|P!l&7v zxY7TRC*bX@WxE7^6XXpPCIQI|&3ej-Yw<}=W7D&n(CeD%;OV?7!v9d=7i|ESBE-_A z5rf7CW4F zaX>h?RYft~Xp)!0s!X&m>S?mkE9HM8^Zm7SbLQ7~$;eJ#hhdwm>*dZ&-r&4%l)>ie z-DYMdZ^C3>lC^U-)xj9LU|Xl66G{!U&Yw{FmZ}tiNnEH(5wMo36oGUucN*%}TkXXT zQ=M$+U>IpHCR2N{%T$2oUhH5Y!Oyp>1N)AwaQO#@#YoMcQ2v2^N9Mcy1H%H&#)R?@ z?CUriF8={w(#WhGDpGVNJ0S;DOpTqGLT!iMwn+YoXeh`-7m#d58pMASs;-}iet4DX z+(thvM`m37{$DHzM8^LlR&q@Ci}qu(j-<$E|O-=Bc+AJx@0O(gH4 z+ec53uIY0hKGWLy`EUk8mGwp{$> zc7*hfv_nWI0DmS3`5spfM_N7nA;s&D30@Bp=Rc|kQF1A)qYTy$Q&`U=us-wOz`Czl zi?@(0x{puO=Nqc&zv2TCc`JtIUF8i&z&qOV{*&d+armFHtY5{5)&OWjVES=*a^{}% z2L2z`-UL97qWa_S?Vfv&WUrZI6S7Mnq1l<)Ko&5BD+NO(wl#$!@GJa+r)45n7|%n=E8wyml&iwO$9|NKmChY}Rxr6BKpjb9PEZjdE>|+V+ZGznjtVvO?(bB#r;XX{amS zsx(x$LzLZmqw`6!!L+78cXW%=p~|esQIoJ2X5)g?6SGb>5Hv` zXSAM5Xn8V4Mpy9U*5)bc*VMPXu!Rxear0lttFhxy_*kcT-)Tv zwGQaJzQvEZ{uRiykpM4!3-e{)G*W(NW6EK)Jjz?$e>@*Z`l{pMo4)D+D+Kjbo8l6E z)X{qgucH^3ojP>F>1VzxdQG8i>4l@Ksj)Dwz4s*UWH9T<1y#*{BeXQHTfo^v()t_V8WF)OOj%-b;enweG+LxPcIVB zY1#&8w(l4t9&4M8*TsvWdVN~`*j)Cz{6ZW1vvaf;Ss8Qp&dt%j71v0M7(M+QZMvDY zuTbFeyd(OC-0Du6ed5WMPTq=@F{2Qd>L0<`sy40t8D!^5m60ZWt$ordM!T5MF2%I} zw6(O8_Woj{)0xoeis@{1StNA6Ywe&rq0K9RB;z^nH)Yo>`vp(Q+?W_g{L@Hju_Q7v|>>O*w)hes9)v{CN&AwSD=QJ>L4 z0{2J+9jmzEo_H=nQ*V(CU@?6xe$B2~n{)q_ySuqRQ=RZ%%5K~?Kh5`aOG`Viad|u_ zgy#NkfmV9EgJ>_9(-Te47IJ`c;pdQE54TzUk@ z_2+eHpK1Kgc|&dyz4l@B5yNYCn$N{-%@AJ3!f|-bOvbHIWzS0Md&SKdLMD6zXqo0) zbc&8;1DGnWEI0>OB^u8IOvaM21SJIIY8_ZwfF4eu4r?!uNm}&4Y^w%lXEkG}jUz-v zmRbKxCRx?b=)-dUDSfk39+M4ABV&5u=#lht*kt>MBjlXp?InEjh4>9+*($n`yu1v& zaxmhd6N0ib*)8#q6;~@u4z@1588p~dZpOH(*@;!Vb)W>apb);7EgsaWi?L%!Z)hp$@wuqBmC(3#fUQoo z@r?Hve7_vNL4O-^h90>;Gk7pfurL~42w$Z^?%!*Nsr(kM40OnR#Y5eFS-r0(@|w_= zR!J4Z!xHlyc+>#wt=I8RAWs1~wR6)sT!2}a8=mPa%?zH0#PyaMt0=+fHKefV=-%A$ zJ}2@RA9r2s;M+E9UEKV-{(|%l@-eOcBBmyE+rRNM`id4J^OpOduwp8O+d%m|JbJLG zyw{6SO(;LaLx0h0Ni5!P-OqdVSG{@fW(QOI*t%knpMxeaos+B;yiasgj)Rf}WYOzkEk} z;$l#au0w39N3&tP?jA}qOK*Mj?wTU@>UApsM2VagYM!(U45BC zs}uxSuTgbZ)*l_aPQ{X-gY|O+nXj%$e1*PZF1i?+<#38>^kc7jT#Kz1iTj; zcft#_kvb4b(OaR=$&-;C;bpjxqN_}R^3EaIxg2=?LElWUo8iT`0pNn;B6xedoHVD& z9*b3oUCP8e6z%>*#$X^x@tp+3a+iSSGGS&893M_ro`wlddmIxodf>Qlapau`Q^PYc zjhLhF*#XYANF~}T84#i+I>I@V4lu)^MP~~vXc*c`1NqUg@EC1I;_q^5Z1louEXkn| z_Hu53HMS+hguk&A*G5q%!emz88|ljB@XJ$qKJf#-bchRr=`YMh^k)$j;t=l$qD92jc4Rr2 z{^Hyifnw}rq!kh(aMjT}nGwg&clry1>6_<9$tcRs7DXZ9dmJ~5g6S{KMa&9ur6DRL zyxJiy38ue17cnQqaYIx{c#RNM-huZ%%9}ezoGn;ca-tFXfEJrLZwvA@#mLInwYCDbw;*9W$BJcOV#<)=s9Fc)q!ag z8~9@HXZEm^?$9@Qct28$(PBe(9@Nk(*!qE)$Vl@g||Ya=2$idyOOS z($7Z)D!X`MRlO>j7xqQB!oJJn?+*H2-qflP8WJTeve|o z9P=J%-qOHmsf?1hSqKi-0vjzYX!8%zE@#8_1VE_Ni3fw`Y!Bbj!Yc|lr(}QB@mAF* zGgT7?<=SPop~yIUt+NIu%=$-3CSK@~{GP5UWKs=Zvbis~udu%EPGs4PObl z@c;O+bzae%BrpF5oihI#uK`YW(96!4b%XBWg0Wn2;n-kx8L!xI5xUq!|F-bU6uu@7zg(Vu@kr>0rs?ua$%pa_yd~7* zt0a??Dh&1jrA7I6uuu(o2cHX2Lvpg?n+>J&nz-uE!*_yWc|^i_eUs6u!4D z{v4d}+Bm)|lPQa@%8$$BeFRe`*YUaFFG+iHyiPZ9Ev@&1VtB1((uUJ394nLSaar4R zd76V4-e7@AnY`N4kq}xs9}tZXy6DX^nS&F4Xiof%7GHvE@jtBiH@3x}gA;xvj_-K8 zz~W2Ti64GcVQYEZ2Y(QKOvJ2!0ZH0pkjhI~l6Nk%2+NW@fmeGBv>#hF(I*7|q)@rE zBY5u=;TAp@EKuVhcNP}i3drEfg+S3)M2B#-#=wQ&CJ^BQ zHN(|FgXpV@e|sD*Q1mrQ4FS8^l3X zGQ;#HH#XuNB^H!Ch04*2o*89#Q*VeycYqncPxGzTd*e#O>G1S;d#-i+s!5u!iPIbx zfp0><()`xeq^Va-qi_FDX$Ib}8Kz!qa+mZ^;hm6RfLjka_AYnHMc+~C)k-0{3kO&3 zC84~|ohgRj1rXbqez?{01PkORDUawP3E$lyVHgmrz0vpNWY{P&lCfp`eY}ZTzlZ0V z^-CzcK@`5OX!+_88@ej}{sM!ScqsPq%2@aVQHjg>0jO}egx6HA;@0C&s-v>^tnUFi z`XN6_0&i3TKN3~!Vq$ye$8z$>d=jI#E4&vFA-f}~btTYA0-Z?$))xIq^<@3sC}~Ty z=Ol2Y68MRz_EeW*Mdzn-&hvZch3`P>W@7^QnG))83H_LadPu0pC6uuH9#NBA^v{Rg z`H>`}pV39VR)1e#UvF=CpQy~AWp_SQ<~u6bDtIpQDQ{bEyZxQq`QD4X?OyBb5c=Nx zy&djM+?kFYsvTX3D)^^%tay9k{!GUX_c^z8>)uKD>r8&E2jcxg7*Y52bGV4^=Lb7*Q+Pw(A7+Db9!-fy!q^}R#L@5Q9e zu1^{HELERHRaJ0x=IsKOY-*arN-1wwrE2|2nK-`{4AB-6t$rJdk}i`@3w-%(rX$OA zvkXq3>pg$2_a){%EGaNM7JAWK7?0QIA_wDq#!aAK1rJl_@#6=LNx9GGM=S`&iw{%s zVsym3(X@QXxk!F^fuI-i6Gx0t_)!``V-YgW3$FZ1 z6+IhngNtS15&_^r--L%*uPBY8YZs%td~65m)b={WlUEyUr565%?03$^>+|zdC$g;^<4Xzb21e5GQI!<^MaE-Da(OrYGzYv7%5@4& zT!lZ!gP4f-Am-PF(B5v>nb@zP6uZ~0vz$n^WBAoOcljev?ISxpLu}Sm>>kXCr1fUy z&6aAmo8xRb?aiDlPa{{^iiHPARnJyq&dP=cuY)nKiPWDfa)D`K&TY2mI0tWu(wpP;;wFChTS(>0D@JEQlP@M6quv5L zHGx%YEl^?R*GHdG?wTYggBKko0&R(OX!Mk;tx6}fF=>ysS`jiM88r2+qe>V?}ppA znyelH$K|($e;|ocFn#2#uQQilkvBj!J1wlP3T6#;7QP@BEcWEfZ@b6#_k)5xRo0(D zma5~rJ#!_K@##kyBbkgpLdte&!C1qVeQ!Rz3Ye92Qh&XfOV3#O4Zj%IoEz_@lcu^W z>nT18D7t|311z~yzV^75?{2$2V(lXE_6Pqm@}<)rweXfE7FIcW@-YPUXR@mA6Y=*i ze5qq=i;uz;)3`qYLXRo%{ttSW8$B>YFw!ZMZLqm+BljbJ}Gfa=Cy{L z=KD6vA|~_);+3k$FtPX}E)0K7N{B7vnaPuJF2F|ep9msE@*4gbcV_aGxgiqGlsHg* z0`&U(C=u+=&7UoiWPRJ^of5e+5pQeZ?d`^!#*yeR#4T~;?}bm|5^owN($o2?()qDV zr#CH~6??dJUf+C}Z^hLc)gYSw7hb(l4TruWxp4RbdErU(;yd`h1KwmC5UXPTqypU{ zRw|gt=v=@UlSV;;=xiob&YdxL_#3(fT~v2^I8HMr+(=~_(5AknjGF=Hm;u+AD~VDr zI;}}5Z|?B7P)cUN8Jh@q7i!xUlNg2QmCYDMbGsNiyi%TY-tbQ4$@G0%`K1NSl%J%Q z+zFPh>X(|6^6ld6I40=m5OxNw*~2buBfDw2J+87eMrY9_cGB=$FLADOg|0WkPK7`H zb7k&NDu|NT$CdmhT6lDh5MV{8XtXVp;NvZiU{6ByVmJ*R72Q^%7frne_3&uq8JYkOjt0!&yu(V?8APj>1>!X#yRwR(_0 zh;&y&@#TxY-|G26tLGkhu5*#2%W052Wowk8x5*>35RSwTg~(RC`+teMCQY&%_G3KP z7yT0ZV#L%RE!qD-=fzMz{z|!1*d6iru=p!QLcyhas4oq}zTNtAV%E%;bUU@1sJ(RR z!Mg%k(4<@2{RxBd6_1|bK1fZfw3;QMrJ8_NSUOpl^I-T^_=tP52=YBeUyiJ%1mG;| zzqIx#16uuOy;XeQ4S%S@1#3GQv5(H{2?Hc$WQL&e$~0@bOnc~Mqth(?GP%n}?=&qe zQ?gt3{a5oiitb>RHY#*@I0k>L2^OuwmA&hl5Ghg?zJ9tgR$o93y2I z<1-#p8t+PLx58M>41;#0xY4iZB<;@b2hiPf&tvm+D(tiCM(bFA1|y3bF0mx?2*_Q9 z{MfcKMq3IyxfNTmGwJvx(MJhy{Fa!hEmd z9XH|j(|EqiYfO7Rx?4=yi&@oyvO^{Qf})q#vc*@#TCQFnh5>a5*K>{IMc*HucOnw8 zXy=?iTtv&VGCJhnBiK@f1VC_Xl=dDp-F@yve-tYoXF)<1J#d~KI}y;6oiDKv-b-^i zmvS}XO=R^J`VGnItz^y3MV$;^70WQ^I?n*ldZVm;-lO`8UP|KDZ}tbVIt0oiF9TRR zV$qu`6w|V@jDSxpUMKr%SjZRS34i-x6vQAQ6W)@p@Y*2aj%_2<9;HQdl%TseTQ+ciLhf{*>C547RRwZ zi_^yWkiBV#8Vj}nwkPB6od-56dY90Pognb)7I3EVn{Dg}mM%j@VwuW6SE z7OSWzNvER1+@!?qyus-&05ZMTsdwY@2d1v%W6YbM`^)k({OGIdb7SfX(!R#}E1{8O zFe!&=7u71$8=2|4D1k+c{?59GOxiqPA#vYJ++f3tlws~1>#IA*ucNMor8IomWwA6` zs73$K`pJ?a&6%<^nr0_%qceW^T1eD#6W5~1JUa1Ne*N>sm?i;A`UVd-YYu1R!JP|F|E$gCV%i z<91i*OAn+2KX$V18@-j`UG37|{8U|>058{425fMgN(9?h-0)|57xtSOiLOmxQ5G_c zv15h&0+~3dVm{nrB;R@^aEcyli6XmD<mcf2o{49%zC z@OC9o9({!ahIind*Kxkk!%_WMvm9&O0(|2~U22Y~)+sNb>`FFQ4KJCmWm07nMdwxY z(Dj9sjydMXs?Ydur}GZpX3pgpTsfr%W)|5qXd*(PsU%4r^ox&L5(vVH{te;Uo zn;FjqSu=f#@o8qd>n_V=`DxPV$*lYh(QS?_-9E>ovsc#1lXL#1X9Sm?5wp_c=PnC! zvylm0`M7Ed`5nEN<->}gHkzsJ zz^L#UBqC$K;a#BA`Z>5akbVb36v(R7L1pwN2X{sSf5nu;MU`H^F58Ms_+1FNT7feb z3k)}nyOk~~1emRB{6OwcwAR#8ieA^eTpz{2ZMu%U8-}bTs*T}&AgEm|aqu==>z7h+ z4L+&_I;nIT=90f>D3N%UA+%_JwM|OA=Vb6ue|dn2aRh6I7WBQT@t+(7SFkdYHEpy;)*; zM{Kmri-c6{v=$#I~2leQciXj|)$fAtZ4eBVzw zuzU_r9noQExg5R}2gX8%i#t~){=p1`M*k$m68=>`wAj+RqnQRS;}=*d;L78TiV(jK8fDDvYuXi#qaV9R(9p` z>oGW(Uq4*lIm_J+)}s07<=}M{%Ek|Kt3%LurAq6IishA+;>c61l6IO`h$mfcbI3&v zAbfQ3bQ|9^4-jvGA2WAUa8TX%QA5u~7ZT)n4ZLzY-gvQz;%xtAyzha7wfQ(dynnD~ zHw4Nhzq`!QdRecCTh_+hwkb^*Hn^{K=Z&J-8mnT1j{6ptEd%5# z>ro9sgx$_FPjP%$C%`IJ3(rU2ml83uk?~$j-abIy%3Pi*cU7MSo|5k_4v&p3C=TyA zmM;$PJyzg(05+tn10s#x6CPOQ37|q{{R+R(Y0q@T+tjylNKy<;K9BH6^NYtTbJ#8h z#`Y2HnE5;wp^7*H(O74^G23;P&b$4I-}72W;JOLD>6rEY(BXL>gil?MDU}+iW2?wA z(LOl3i#&K^t#$XWkey<*2B1Bv#iK6OZS?x(zChvzoqga#El7mzN0?PrF!m#@BP#3W zcO*1|I6TZUTJ{&R7|tq0zh?2EM>6Z3-1>2}t7E;`aPuqDpuzGW7rz>q>M2G0^J6S? zL#RMqCipQgSEQh$yV9bD(UZv?QP};DaLlX45X&~uFfR4e0m{ckw9e{CZ%H~e=pUne z)7KU5fdl_d+_LNK6h?1ndBx8$eTb@Z9B+?nAXveM;u-ngZWptsx762Taiimyb@b2c zo!8qv_Ut^*N*QHLBhJGnqKNZB_gU!rgx^J)LmsKAMr)NoZ+BnU%;29;PwVY6NN+do zp}V)+vApul`ROa>#dlHOg<~eSfv%`=2yvHfR7mt(oXdN%`6Fng?tEZ@ch|3+4vJ)U zTbQ@DJv`<||B!9lTzN%-8JZ-V{pXy&-nH>p!~)gthdb~zPOZ}~M{MktH2SFnMlr$y z821@EI;mn?gvidhY!Z+>>qUVXhL&fUY@A0gmzWgKH9kCm3dt`R23y|Ta{bExyZADR zKKcj0o}0M)SRSi!O$y(i%vZLCDJ$G1)*u7N2_w|SOfU|YZ(#I5KRlLQ8D%R+0C{{O zW0LJi1?FB?SvS5NFSxx7LP=M{y_2|ODe6MfXEi=b4?TQ^MhV%9I)L)fKeJ}I%uJRp zqwt}zeA&dsBtLN}KhdG8x@8jwEd=oPCSZ7M_{0bs3Z><-bxi60XS^3XlHPDJ-Zq%H zk|^5GxYoW4CO%-_g%cmO@6g1j?Yn5=3-(<+ajSi|nfSVWmrUHL??#PVuESMFyV3et zHUtI+GU0%VMQ&_gChp8Y>|V=BXf((}veMTM2Zc%>S@6c-Q}U+8_@&QJ*66H9!C><^ z7udrGk`28FhWXxOwMJJS=Xt|%9%uFN%gwhld0>+FBrBGVaQ`pCC7s*1Nz&2ltGg^o ze0t>ZKZ_F|FCi|gcP_X7HVhYV%$MmY&V}^Y(^-ZAZ>EIK3u8RgAb#DeWxV-yoH$0k zpwWR$heKkCbKy+GZ+dt0Ek?Pqt=>#q=||kW%tZr~R@0-RbMhZ}+86(jjhRcq(_OWo z@ih`*IF7!-7YO?=iwVm$UJK(*B4rUdhD&w?Ef@!91jj;aum{G8RzNuy<7A7N37xAp zv)lAi(JXPtcWm3-;P~o^>#0;fS`IMTJ7Z@u zo&`<(^l1X!ZkjFEE}xu7LH>lb+rhVRh?Fgs!oZ6Cg|3^*y4%0adxt_cj~q<11${a@wgH5lv)`F zk9F7$N88H`FQhXkStQgM*L21=?`kK3kGcPeCfeq&Oe z?`Q(X%v!+cd?0APn8ztD1k#SREoULHlA=L`2PvNiDqBvbxPIh)MD^<;BHdFES}qYb zND?O-O)CMDL#<0bYH`G9op;jM;>v`lBFg@xnBvXr=+&UJg)%7=saGM{GRq#IW??A# zXrmI!Yw7V_@y8c!;Z~!t^0J>{p|g89-(4a;Wb5Kg`1qLdaW}Bq;Sk^(eUG0Knx(|MqbW2*|V6`#MtK+k%O#fQwn=|*A(K6=Dc}(~lARAQ&jo-?pAPpFo zD05S{$VV^e9LM^T0&Kt**&?g`@K%L4+xaJ~KAI>TKn-Gw*hRWQ^hO&i*~C8&^Iu<4 zMCJc9^76^{c(oO|=r%Aqxq{vieic_&fccHvany?0!UdvL871gzKd1L9J#St#3S$JbcRPS?LFjv)Gf5mcviILz*Q3C zknEu~HMyI{83~vWkH~6tt{mvS##A5Rd@KBWYb;ZtFumzntft+eW<0Z)h~aYC&J4U$ z;Q!O`-?ZJnB4*X>w|8>Yf)wh7ygeRJ>tn4lnesY51ZMEn{=gm_A{3%yKI$KrS);%2>1xQPt-%RbfZrJNTy8h zgF73c!t>$9A)DpCPkq%N~oABv6Qut#_@e+Qm zX0I0P&-^s0zF818h9J5u!Ma$mukj=KlpV;E`RX6idl9J3$hxl--o#H6q6^mz54A#c&nJAG9};{fn_hFxc*(GrtbB!Ug0HQz>9u!KT!Fiu@p>xf&B|1K zYa=OL^;r(X)#V=KU-glM>lp%_QeH+}npn<^d-2G~xoeTeSlSGydLLN-vdpQ^Z>J+; zd~@hX+eUQsjp-Q9ES&?X2PKOLwb~~OJncGtF10US5lc9;bj+BjrTLQ@BwG7xg$0pX zoYeX3C5t%L0uA_ayIk`+5((^Sk=hi`)C^Q9ceNV&pB?fs!+ME@`GHa>%#H}~TQK^L zY;9;W9+V@)Kvxi#$TBaCuhYb|n-vph#EzZLBtfm@%Dyy3hDMHgfc0pWyjf# zmvW4=@fRdAaZ=O!OL=c>dVeMFlT9y*Ihl#Q$CJ3|;bbN*YI@Pg$xPhS^rD!PnOM9_ zf{emtX5zG__qXzXvg!Suy#H!?AIHm@`}g{=pm>zxV9xgkd6}sE1#ja${Aej+K=P#a z{&UM6?!%)#J<+#k_$#pRp#hf5xKDHubEn$U){u!S*fV$VQctFGWRN-h2-Hgtk18TE zkBD;Aa_qPqiHP~Z;o%3M%S#oR*cIc}o)zQP$Fd>UV%af^;~XAdM~qr$a5zzx5`xt> zOj|+e22o1l4<>1K^<+SNA7MvU;R*M(a@#p+;Jt!;-lXFOMw-0%rjo08Z-6&jeaf zyRly@{F}6nmJPV@dbo4*66UH7?n+OMa~30i;^^!B2=zK=`3^ISuA*43mjQ~pJIl@3 zzRu@0x5$*2bsm{N(huKH8Vqs4bVhk4n-#b^GLxI!2DXosjQ8)9w|$5&sB9cQCoyyI zYrEzqhrqXIbFI8`lZ)|(^C9L~%S|o>_q85r>s*EQZz zlDO4aUk{*x?%p^EtYpJ^knJigkb#J&7SrGN;NSgmcr7d%#vp_Pb_w_sfPq!k^xqM5 zS7WuK{qrT^liWedto|%0PH>HLcQPY+t`D_>zmSOY?ouwE_K0fPD@{KMsm|)zaWemy zP3HJG8E#-@>W8-y`+h>K);nBMHr}oslIg#RQY+qnX7M&l5%J^QX>3@so@fcWYHrY9T7sgvK`PsX!?WiG{k0|N^0`4O$0Qb~RISWQ3X-5Uf~vVB zh-13eSpQT|B5oW1h0j%+q;KQD&+o}~uHpoLBR|H`*0mdlMZb9_(X8){-o zs+wZGu>)UY05M)>LTQ3lNpJ@S%x_{54I0v#s(1D?BHf5cO{;b*<&lfHyW%)bp=OAx z>t{kdM#-ijsv27PJ9ldl-?Jq|i9;(z%W+!L?TD5cN#`?V<_;yjHHen$G{n?gZw;d5 zIt{TsGnVVEK~y(mnc1eTu8l{@Z7eyhLUBIZx?3d_Pm9 z#gj&{9kEp?o|a;(P&_SSt5D2AOwDy%g-?svDim`N+cVQD6icP|ekxJeIEZn6rG8N9J>i?qWY9FLRJ%el)|6`FSE~@y*<&i@7HL zag@G#JjiT)6sC1LoK<|1WwjZ%rqvnv^` z!nO`wE8uCZ%(f2wlj2{iwN!L18ExW{Fk^-KKQJTeTSRZR%!GR1*#E@)%BMx&jJj3T z7MW>wMhP<}3|n82M~j&)Qs1l~ZT7iE^v#%g?bBv;GxY2KH}rd-miM-T+^CJOMz6`{ zlZx03kNONae?Tu31VkpElaI18dFb z+FFP)k4Xcz&2Jr_Zxv=c&D+y}kEPM<+BspqCG{{3cx)QbM)vmVxHb**t~4O8er#Tw zHo~^k++LXN**rQe`p46Ncc%gWl}2;vcnV9a(ts~a1KPZ$o%yzL+Etvj$Mzgukw){= zX~3_i0iQ?%F5iV5HM@gYz>ZA=o}UK%P#SPk8gOXWl!OjX174g4{7@S3jx^w-X+VFs zl+?pC;OS|=%hP~2r2+3w1I`H8UYkSDN&)Vl2E0(fcCoSHqn)M=679fi(rDhB1{_$G zQc7#nfET3!zaU^cpHHR%SM8pX_ag;tk8bma_8i%;-wvEkqj_^0&_=KJ==Y~#u3VkM z=YKSdXy?<$+xB+!3Po=RUY7>EKP{nwJyN3E45^*w{=#g}(V1z$Ytn$sX6|lWJo=5|ZtVzLKmj-;NfbA^(Gz~bk zZwltgX~65!fWH;6o%x>qQh>*#0k25|-Y;M~^Q)ho0z4)SczGJ|)-<5EKQ!B=ZX^wO zjDYPdU7Uvb1p(U&sgcRL`3=7j>bN53r%IFklkbzn;LbJKvIOane9V0$)KJ|~6d z*=fKV(|}J1*iLh&gHmWtrvdL1us!<7!70%XN&~()4LB`ed%b@=4fvxp;QX~I(Xphx zIn9k}z`N3bxkFN-uSx@+nFhQz4S07N@E>WwuIHwtzI__-=rrJT8t}$6;5});o1n`^rUCzx2Hg9I6q*xhzz?MX?@I&DKQe{pVQIjN(tw{%13r-k-07&4gpN!DZcGE- zmInMo8gR+cDG42v2DF`!_TI*JQ|5MS8>Q(a#V=k<#SR8)Vden9+n^3$4gkCn>Hy{d zfYQAKm;(R?)*Qeb0I;p*0OkOIRW=7O2LP+<^V8~0L;M-aB-$Z9h_aS<`WyJZC z^rBMU>FMDn$;{xLTy*2Lc8ekU^Su$`=wEuAp6-Ex@Y_O{e&~C_Gy1V%x$wh;_!%sD zR68o+7v;%@x9G!-l`q*h8-B*Vx$yJ$&4-_}Zz24YeT(5&?OO^zV&Bg2WA^O|Ihd`6 zpD<6iE(*PqymAZcY?O?671ImfrM!Q|!h6E6*>_&}4ZeD_XujR?aQTWp1dyjO?Dxy| zd$aw1+J0}c-_P3bC++t(`@PYAKWe`px8Ga&ZCpXJL3FzTzRs^Jo!$Ik!&}j03hx3$ zS!F!l8~45}Ju*|s3mp&oU9$rre&~|b?-~@$061>+y9RYM0FEX7uE9bi0C7i21d$x! z9*a;YlQyIux~%DU&7B5txzw+j3D{jqWqv6Bd7MMgcaw|Vb#L1bU0LYY;i78>)RlpL z4O-iP?HY@&-|?6Dp(_~uj<5Ga6_C{!PoE^t=_T95H?z0FF_XJu4~p+f5?;1ZA>sL4 zS*dN~hpsI3i`|e=Wy+lxeo+)OJ52MvAH&iul4~nQS9TJK0#{L7!MW0MMPxS4xU%5v zExFS1LluTA0<<4z%2)()hBRFPxD2~Iy1cnOInyni%~c(rj=yrqQBKwU9O;qsqnbam z;2GMF1dpNX|9VImsyg=ose7>MCzWof@QKFxOUtc zte#rI)-PC>P-_iV->P8iAU2P!{$0sh=QAf+4Fn3Y9&JvD#sY;{=Qk%rqk}@M)0-2b z@nUp(9?xJlyS+JVY8(-p)?;nXriK?0w%%(FVGTG6v7T&Bh=w4Mv~EAVmTH-kq6Q^J zw2o^|L=8gexjZmXE}vP};4JaY4U~D7WoGc( z4AgmOuD_!q_ z00Z3R@VBHSGf8v8Fm=!#)}6$&u!_ZVdfHiUJ^j~L$*UCPgW3)}3h_Ir_VZj!ILf7k zS~rdmhla??=!opCl&Xs}^E&8p>e9CEaaz||)4kR;ZmuKE3v{FTaR@1zvm2Hh9+CCU zuH49N(2%n`YkJ%DLu37IP;*XQfA6RG8@a68(-A0;&j|G)$eXN(9_HelBY!| zya(Y3_@hIrp9)t}bO&Rj$;sYa^_HGEQ*UXd>v2{oYMZStIl@1I3JcTzq|gHUmDw+0 z2li{j_n9tS7SB2=F4Wu$PQprMCL3L%oN+VY&3tt`rffE5cSLS(SKm0jJ>iM>IJ-a=AT%*26B4{s$*^ya;@7lkj868?60vzey1t1s_Lvo~MusaSzmdCX7+ zKP%?D^=2lHhM*&1QvX)cq1yG*Rc7K9vtgaIh&T+EntVr>fxmhkZ#5M1jX#k2?pAZS zMajXw3{Q*~X4s~e^26YyGu!}dZR2v{FDplHb^K9=M73UfDjg<2YRY!u#(I(>hN+yGH?B|>KbwMZTxyBl@`mk}CvUDu+ykb66 zk<8R`{8(MY?4g#CA$9`n9+ALYrIOvmOugTiSw!y61cVNRzrb+Cau=kl=pn^d4YP{q z?!w5z#n&X0emDkH^YCy4N0@(loNb#pCkHNSSOa7ON)QzlS@(y{vBZx`0&xGSlW+8> zvyS3C56dH73ij65*Tu_*cVoh?wxTDa`zhNngQ?Q`7xTr`a%RDsHP={H&SC@yySBaQJ z%;3Z7Z_15rlsVwKLz;x!$hTRz?_CMrH^?J~yD$WTp_p7v}|)@mjVvKYRzB z*F^tGfVtdJI*-M}r{TUnKYXVGp0!!P&S1O=b5y135(bzLa34yquIGsGuDKBi{UD+B zpV9qcRa15^cGM?3g$+#}Lk&Y^WUZFWq4K2Vu7M;t=U}eIB!h{7EOW||zC{an0JX71 zQR5Jv-nH;8g}8`;i^B$isErOyJcpbiBNjQFkaZZsl!U%jeYIs`4*G5K=K5_p!ciqJ z!?n6g_iV~o|NL+nU~c;AGZ20g(Z_VNkqqp2JWkxKie|>=W9iC8(8s#%zd0Iiy>uiz zwPxBsU!2dBuYdz*1b249q=nGva%`GA)>bAit%68(g|f4{X^h3Z&M;21k?sNy&K62q z8@2YgtD%_OrQujRHk`CJx|<^JM=!^h8XsuO-KG(+7l zVc{R&VtB}=O4X2P_oA!*_*TVVtFpy&OVcAE{K_1kD$^li!a zjlTlNWX2Q|F5cps$^8v~<66qL@oeFqDdS*Ao!G1*&K23JTCtkqh#cUxqPPa}o#+tkZqgVB9!)Xyp z$2ZD}P2cxJdF6Y2#}q|!mU_KI;_|s)W2bqR`jy7Mf-dC=XmcRJhY6taXpoO@sSTVz zPBH7jz*6lwes~n&lfR;9xaVwaEzeCqhId&V!#=;pF_ZhJ3hV~(mu*x?7?FI*k>O28 zl4mHFcufD2(DBZR*QjWY!}7;@JSZAhsU^d7-@R+Fy2JCnEnY0%YOXHwu7M<_G{E$b zC(LoyrW{C9yRsE-bSI3M!TEALqE?)9|Fcr{ORAoZc8!zOT~auYKlQ2;n@^JV;#lUohvq; z5NjF#e3e5lcTFFJA#SX9ZF*L|HeRUjG|O73+Uze@u`5}OFi~BKenqS6En;dB%ar-( zBY;-^@_tt|(O;lT7t&g!N`f(^gGHo|EwHu|o1N?Lh^O!f%8IF6T$y)}v*-*!wjk}Sj`n$ZM^GWWHGHPR<`<&V_(spe24O{u zQhQp9_GNA2u8QvZAL*AfS)16qG0?qF&UKG?zfsBD5?&5x}Evo$! z5^ca=-M;Y(K6(nT6`aJv66-4ohNw*huXFvC*4f{;JnyMIvx3mq4^M!Vf$(mmnr=s+ zfSc<|bvc$N%s%3=6upzZRnYi>(O4}SL{QOEZm}Flw8DL1Q-(Kg9!4mH$GhVEs+5@b zsqP}{M4_d5+y#8~uQ^THOHndYd+U>(+D9LrbXlXXKa+bSNi^OLdkr2wE=}zpgD;*7 zK0x4%8PUiz-irKB9b$B{ZZSV~5WXHd0)KiZ$=H5)B_Pky_hc$p4u4WCII~?m?QN1I zh!$b{@~tyEzJz35v|2Vi-8>3H9I&^N@y_LYkCm6QF})9cxZVve)v&)MNciF|*~3uY zD%0#0W*S!zTB`0s_pPKNUhFM(Zptn%cW(0X_0I5q%C>PVK!yS#xLDzpishfLq^ZmA zt1jbx+m&9=8ZWB_(%8glFHFV}#ysl#!p9S{V3}(YsCqWdM2^VWW=h_`}lTNUq}OODk_c}L@y!{asNdnW;lU&G~b`L<2d?Yo(85R*~!HGLgcEpV>9gZ zB#eRlWiV3Sxw~Mt!SgmB?#$bqbYu<>3F8STO&V5?TjKZlCcj(G(~GwP=jIk1@%6Lz ze3N70NNB&rw>%>oCV@vWZ(fd!Q>xL{LOLSbgf%mEL=Rj1p}0G`CyPsYx!_4Uzh-TR zuYt_m{LfaEB8E%#h7LTaPKVNXiBkygra_J#OUwMAYnhxxWtIg~9OX3o|7qgiN4^_h zhO)-QH;_7?i}>WCTL3n0<)6iLO>;7pX?zn* zUT_Xy2WQcxcsi?lz6G>al3D+6*AKI!-FA_UX^2hq8FSI)R&XWRI0yn4ltWkt}N?0P8yucll6TS@7c%B@}YI)1LC7>h0hdcNBC*{93tU8^xxB*%eiF}M|P|p zKTX9p?k9BFMumhw6b@&0tvH_%&I5*{knl&~H2#GJ>(Zv;^2R^SAt{$!=-=t5dqwTW zYR>X5{Kk(HhG`D}T1kIaq_GD{@(KwNqbfX)isuK#^SuDV_lc=H=EnS-Vm@Rs6*7(L zPb=Y@6#TFSDwA9*xuh*`slWTxR^U9c6*!M>1Kq z;3WOHY;V7tI^ATlu3mI*hc~?7M9peygT2`$V};)A@cgk{wagpLBMUlN;^$@t*%anU za3(Cr=)lN)d3*=a5&jlNG@tq%U%i3+IA3*E_Lk$$0k47-%PahHH}61a?rHpxDkkE* z<#XtG@%$&2#W%dcn0{|^FA%UY>gSA3Cj9Db{kG71)&C##>a+YEpGxmx)@v+x z5>~$ESZSBF6WZe@vUWc7**HT^r_X7};e{{er6Ncu8=G@WvljZfOn4K)oq1cX<|p^X zxZA{QS*zK>VlB&o`2c3^iM?U7*rNSK(H^k3Vg3dmY?O+R$<1)tXtLs;A7_(!*XN0< z7YU|+Z|#_g7>l^_-XDbwp+8|_Y!CaqEQ8X*H<{rto6LgP*U8%|FJvat+ey#S)era& zYWMkNlYi8=F!?8aioJ#5ZN^7?i^GSHZ?CNi9(`eb8U0y-rQXuy6F8VhlqUazqpRB4 zd@g9^TQ=1;Fc0jIMcs0Bk={(P)53Zej$=71;7L->0Q3bD}?vChOhCggOj0+ zk9)z_$b|NrSMp7h`ExQ_K?;bHCo)Bznzp1j-{fiQZwRzt~rFryPZ9 zxv$^~i=L`h zUHKcz4t;B$hnX!Hl(p5lbXJ$r@Kh3Ae!*owaGgu3$eVG+WWULJmmk9f@5|3J5zq5| zZ-KYsIWA3|;eLhk{jJqk(vp+WKxamQmA58_2LvDf?0_py6e^0pmWYXwgvY7I4&!{ALJLLzu2Y5_wk=|tZ7T9|CZSrJZ z1nK5`3g7VL zF0{YQ(#dO*v#~i^1is~JxbnFOZ=W}PsKQPo49mLc z&t{Iu<|fhB%^dA09j)M(G$}n_-qV}jW8^(UUiHNp~XQim$W|M{4_4UCACo&Xxy62KQAK~p+6D4k;P^Y6=8yTHURJRl- znak;wmD}Q2C`4-9SN>Rrdw+_{&DKx#E(TmE_t>~Q>t@4on&`Hth2i@kd>0$jneb|0 z%iT1oGJbf>pEWTRiZwCRTePOkTMN_p?}}oUCOwTA;7C*=T`rqS&8} zXQMfrj1KqAboAya?7o|$mJV)sL1AS^kZ1L_1^RrSI_3Y+zT{Sl@79SB)`(TyHiE6 z$Y1D$*NJXrrUNZ$^=C|pd{zAAXip=iyrV4<4_pCu`{zs0gYX_`NC8E4ybjvD_1dc? z@|!3j^!lxL&aGU`Ys4WPJ}*o9hgaTwBsq^Zuq}54J>Cwa;_xaf=kaDR5pB&r(}Cgd z&P|2o;zEZ`@i~&`9d?*kaQ&d~ttZXDC{0UgXytQ)@MlmcMAL7J+fB z1uGRx0)G^NgGV(3hAe=mQ%dTf^{ne@j@%LpxQ~G6E8xuME7Ovd=fnHoV&1>6obIhW zn`;-|m$tgEjrIkxYosrhhgz8#PLZ9-nIPBbpw=(gNcls1+D|;qa@BDD_m=wGKdwK= znkr^xF68kDy)24ig_942G`a>@v+{n;b060NNEY(RGGF=dy`xCuA1!I@yIC45I8A{y zr7=HFBYGdx(q;m`C4n0NTyO~;Dmih6%VW8J3H1L7eO}Lt4{~^0-Buu35oIsEBh2Aq zJ(dX{p&&Jj92~1)^S+S>Udm|>@opp`D&PgX$jA25nLhoAiGbU-c5R)$oHp)z6>pCt z-5g53lTLQ+J?;eA7x@_pxpsL1{QV35(2o^k>M+GvsX9VK6=TfhGU21(cNYi8ItxYP zr9ZQ2N5YMjpD>eS3%QLIcDe^?N<5D{+G~0%#@BqWzE{GR=N)>e<4gU+S@7|1_|PGl z;-!}sQ?|6yDkf#rEFUp7r+m;L+SJ4BNjrtc7kj~3WZ9M1HeP-0EMLbTKg-wi;Ojr| zRo+7V=^?AQ{@f;?>Tqx@BPFh+vhLrEndE%2;)VOTbhW4bThjWk>S9s{|CMoVNr_jT za32h$_H2K0t-gE2rDNk?SW$5}3ctq>51)84%2bMwe|zCX#z~9Bn{=HZj-tU} zyQ>!0>fFv#Rq5T;y;&wGH~m>EE__hp$h>xNY&p6m;>qWI-Cnf62*}7~!f=6jtn}wM zjS<^K;)`UM6-Jv#&?{_G#3WO_cIIPp@hb0-uP5byg7=Cax$@V(2pVzTjFpKpRImEy z>+A9moxp@fv*<2Z9v)do5tuU1K=@PU|EPVauy`Ede0>|;APs~+n+-wH)HSRgLQv;4 z?lcB!ukb*=C)pXlrOSH>uCTArG5r<_yE`uRw=faxC>BmChGT3F7snrjsAPP1Xg;O9 z#67`0(iQs{rnH84KE2d}vCLrCrUAAW_F@dR9-)i*2QZJB8g%3R=annn{Nu2gm|n2! z$%YS8z;?ewdy^h2;M$XB*7X>0QmY0a7jb&ji-%@oInK}elR~&jO^@JXg^A)1!5@bSmD2^a}38A%Y zfd;BRh4H^s|BCBV*c5B+-qd!-0kIR`(sl>D1J)<9<9TPCG23=O1&{tLj~9}T`nT6e zYN}_F)@yOaJQkwY;gPb_>-h#D@2r&S2e$Aph6(MZuCk8haP!bULYdY>p;jt{CrJS@ zOSAC8ivZQ%>~i(s+)i7$;*k?_Wf5G~;(lqsd*z#E^LEu$NxKLzCPVc$^A;HQyl_HN z;@?h_XHTQWv>n;EoJNaP2b1o%bqTJY*SL`LZegD!WAc-kypRo}%;anMWwkr`I&B|G z&g%Xky$O3xf5T%FYsSb`XDj05Ye6bp*-dGG9iirGdz`&8~R_7zaYz>~WWKtXZQ?Rbuc2 zmb)UPhNao`g7IA_=&fu_ZHbq{wb}y z>>6I^_ZEQsY!<>9v3rs}ewhB!GxquS%u`Rrg~0Z5rg-TY<20Fhn-1%jo{`ohxa-Dv{j-xa;#FND;DY>Y^`}eVOi>(URoLnS>^>vH#GqJ zCRka^?r>>*e?NPUu);1%DjFnQ?W@eU%a7tlUzk|0Rf^g~J!8*Ok-A)LkQ`E+P>BF_yG(TO;J!Eu2!dYrGh*2m9Y%MrsZQK z1rN!@1x5ys=h)Q>gJ17*I)N| zSAWFy*Jy~_=q-8BJmcMb^J?2R&sco{-nc7U1aGrbzyskno&wrjKr=wz5q2{H>oN)^ z9Hxh*LCiI+3^V*f(IyEM&QVuD#byPca@}A1tibW+c#-yHtDf1gchp4E|8;t=yfEqi z+?%d$e`30!fwJ{%wVt(|@^~X4GyOb<|L~>SO>z4a3{COg#`HupE>Wm!P2u5Jrw4YA z)ON?vLXD5yT1YjwL2j4G*ji#KbPFoiczjkg^i(I;WR!esZlx@z*F8fOKWzNZ5HAYYV#oxkG26>>^eoS9p!SeqPm~glHMpmR`*pL&AP88 z9_rrdxows{N!7t>&1)LYSd622D7R9)`7LRyTs8Aq!B=_4%#E9$eTpurmK|UYv%7Z1 z1rN`quAAbvGZ2%TPJ&nB>B<)x57Kyul3T8b^q|fD_QVstoch~Dr!nkM<-7TI8J?{C z8E}%a*Fe%Hl_oAK3(2J6&!UfmZf!(!qs{74?W#HI%qrzI(_pi)nJrO@cyF|HM6=EH zwv^W{1ea#9cTL!|dfyFST*o8uv01!kBF$*cy4?&HmY)T=ME*ptugOQ!hF6IjFn3Sb zXwsX-4Wa~VbqhW9C7a>Q=Br82^2IZot$j)VW_<86r}42@3m<{d*2tV)^?JHvtJX3@q+T%3}=@2W}?Qs zB2w>~J229F1I_XYBFT$J)o1fnP3_OOUS#6DP;0HMojG@*@)kR6q36bM&s(t~(Rp)p z2V3YW_o92i{|CBBTeO`3Ym2V@$}Q<66TkyWCn>+Z$zuhaxa%Go8;a{Bd=6NaWo7js zMM*+d(BWI>E2a;2#8h5;L2H513&KH4MDes~&&;Q5({dNtjhpJEw01z*@o?0(I6T$b z7_7N#k)~UXyyC4fwXcwk`!iuDG6ULFW_Q_du509eKJE@5{uw`GlUZ1T8@jKK~ zK1n^SB}=8;;5hTZnZf1gO%%E|m2-_l0C#QbUM`aef)?BP9UJqylRayc!M#N-w4W=Q zjz<*>KDW}sbC~EB7OX!&I#5~u`uNisl=d`h{GG&~_8eZ$pY}7(JJO#t_1WjCOsiFj@Nirb#v}L!vF!+Evkq_s-y>DVn|25FC|vcs zHf^W9&K;UMF^*!;7eq%BjuupKL{VpAgM*D-nW&96_iWUvR>e9qw7FSjUgI_6J)e5t zM!Xt}s}IK8cs?ZKx{r>*Elyv+w`-M8FpG_Kc$!xu*5k2Vm1A-2{*bCN6CQ^<{21k9 zb95erFRi|V5beu`+fpdZ&vVNk_zaNVTzQ|5*w+tr|E<5&SF-DGd%i>X)=D7wLI~QJ z+@HsHywWV7WUy9M5Z?pfekEE_EU{TszYIrt=lQ*zb_<}_T?6RPqhr-qbVY{d)#L#j zQ1#}sJh5IRDa}Tu1mNPwfbdk2adWcmpuxr- zTDS9$~Yc~Kt5a3J!bgU0RXN!%O3Lq^406!GqWdi7s z9>9+Tc)0*NrU&q20nQRYhwlLH6(ABo$L|1iWY;)b03E;s__hG&2q3iy0N)j0LI7#! z0JvL#h5%CZsf72jzr0a;qoarM!m(XP2q%SeE;!h;a7!7xtY9|@M(^gPC>w>kOZXyv z0_;0@-p;{LwPV55$rjKGIYp$e1o_1Z%1)iC4;K$lvu}3lCHe+ar}M!C)d5`3Ixqep zzv$CQ2SxuTKEH3r*+a2S5`R+EoV_>|5YZigfH-=uavE=L>g6hi>$k=8ecR z2!XLP`LsY^>Yy(Zl)H<`SKu}VV?KL^`(^`BX{?SecwoG46es0R91VR zL3UC24<-?#hoR`1I|w?Bf8q@}a+cmk-un=J#uEDUAY4n}{ElfFB`@hcPbm&`4s?yc z+eWDonWLYD7SBa+Y+D7@89yF)@59mSIozyT=ZtbjnHE^(1jFde3VU> z)sBe$-7%gixA&s`8d2nxbw8NWw>l5N*)c%h-u&=_b#%;==g5;O8kfsDqyLb2eHo-w z9xic}3EQZacxN2ao89^7*oih)$;yqRqilIaFZ#A~QwETda^9s(9G7&LC0%I8T>_H@ zhgvcW3WzyQY4r~^2z2$LX$E9ZAoq`;Wa~Aq#o1rT`Q>tNo~!@ib18i`T%$+Hm|u>r zBiJ8`cxAmbs=ZQ;1<&Gd7vjE@KaCaor+2G&CvaHxS&lBCV{ZHSmd$8i=wgmWIW)I# z%trqOT*?g3Uzb~Q>^kj}PeZ&X7hO&IJ(+d=S?(%0)Iu}^?uP57lp)PWwx1`@f?7A< zm-FqpEBc1n%;~^Oq2;y0esyT}QyJ1hkSocY{b4vbA!yGKSi7bTbuM z<@S=*Z8eWW?V=mIKOh7H7Np9yAc3YXZB>yS~ooZ%ylvQXRdp>l?U;^3{vAM z*bli8iU{{$;o#CUEEH!U`V!%>&y}GNqFabiE%fAEZNyZEj<5f|SYBD=>eBluqw3DR zy0oAc)SuxLa)iunJSm}^v5CeHtiU0eiLQVoWj8IGzuR?5QtEInG zJ<1gsGCW%i%w%f2_G0iUTUn=Lww|1cQMTTd=M=%!13EdXgwDB@&|6{)pSCMyg%7x~ zKjR$&?;|$XYgQPK$S=v6U{tXRByfuubQf#=B3_(JJITY!yE#bJ9^bjp-4?oioO(^F zH>T*Xr@+Ej{6Flycbr_smG|9qZ};smv8QLcM>CQ}0!CaqjL-}gLVyr5!9+_$4Pd}v zum!d+Oe1X5>S18lS;jeGgRuw>ILEcuIcH~&hFU1$0I{!ZQQ>5*V}pXc+u z??3M|Qr}9aPMtcHt4^Jwb~9F+U)V*-IBVU*TKD;M`wey55?flG$-a_lB>Utcsz*uQ%47}zu2n-tf`c$rTUnYgrd|xhPf)R8FI~35E^7)XnWRLV@^(E8cPcsP$ zc0O+3y&X-R&Xgovvrnb_boP=@4F-eh=;kZ}V1vkEMYm!@9IKlw)JmW%^dXWJaxpI# z4(ju7V8{F7&g55-d==n*{i5FioQ}=_WrK_*N2doN(A?2+IjZ|_4Ot99_mPZ_<8p5F zd%Tm;k4aATLz~Tg$y(3g$ll>UanO(-sX%-9Gk^-+Lj%cTp(h=^o-_)*na2A)sz>9! z_I;0iKWJa{*y8_jzItCg(?B;eZnXMRneGQuCc4+Y_vzc5?E4|U^&Xf~ z=3nbWZ2H`&kHk4ZTN2$uLKFGX=(##% z?T-3Ic2BAnl%ZFW%*^>{}ng&jSC;{ zmPUS=X>rRht6#x{7Wk9pu>4G@t$2N@!t#7RPvg(` zL?|-MIj)53l&@9!{G(<%Xo!2!AW{0#3|#rBfR&^MKsNxgA)FO|sIUmd!Kzi?(C3@o zaFA=L-&8e$uzau8_Kx(zv!HMh1%27@3i)O7g?vBCB?cUHco_&`14sY$i)ng=p$_&B z=ZEscgQe(F1r)gD(2tE=*boxg#j%k3K$IHSt} zPvnQ`Uadq9SyUq9`SJZrWW2tS_HrGXI3=somAKODew8?scHdFp$aYd3jLx_|V+B|7~xtY>T_#zH4`Y0NRsCakG6tBaa~o z1!PE=wL~38l+R#JBMbU(vUrE53u*!8nih;KEtpdl!)zCf*1ltuk>=zK$HBdB2G&qu z^h$=736}pqW2IpF@7=hjwK<|7C`?!w4y^a^!)MV-Cvr_Sqab8#LB)6dLXw?Vf7Qma z)*sQqYz%RuALYox>>v7CGPON^bOl_!X`9X;7c^h$tW^B`Sx^PC)Wm$_Hw;MZ(`-7T@|%G;)B7`y2YBVWwQ*SAvsOa%v(pBwu zrp=Q^&X@FTx>gFRLqT+!Mk6Wh(ed@CXeWe>#E7c>Sk!JC_mHuhwh;vC^orX^c`B72 zUolf&F^?UtKUG|BbaH*tjl>7gX_&Ue9SW4%#Ko2kUPB(fec?Z zc%=F063o#0A^A?!`q|7!X1GFwm4}Z0+O)hTre%QMn#{FxEl$j$yOKhLY2+wGBDjKq z(5?(*YbjNLLZn#D=6LX^-z9+3g(@y`oi4^mi*atl#L#taoh;6=5%);JwmRw9p`eJZ zl;drSmUA(-R!`S5jVGS%->-)!ep1Tkecu02%k!hVs4cmq8Qt7f;9?w;PXM*`r*hSv z-I0oC*K}iejR2+;6ura3;u;pbcj+AU2R)i=zmX3+e@ zr_$k+Kjrz}j{l%Ohfmf_W;LJiJtW3PI{472+ zjpWorlid;~4$|STLDrYTgDsB?cS7QpcA?iW9LdOc(Nh}}^K?I?<8;ZD7pD^?J5mAN zv_pDgV3QH_?azcCWil-=wf%4$#N24;88(S`Tbuyhf{D~2zgEs;QY_N$bn(pg zOm}Lyem1$AS3b*Ughyf@oeX9(0}PNWjo5_sw{vhEsXdhzd)$SP%c6qh*?BB>qB{h3Oo(x^7 zrLA#qdWl!%;FaUC-;uDcIAi^Ttff}K@8!x`z<*%fGrj$fFwJR&NcFI}ApH+%CGiq) zlf=7}#9shq&YtW`X144}?8)}BSGC1>Ud^VAfm_|6NUUCG2ltvx2;;XO?dxaIZXtlnn7%Tz6T8hnqA z5N(y?gJ?aL?zFA2dNMa{D^0J-6mO2M1m+&yy>pSRs7BKF@K(u~`9xO%aE+Y3d&UB% zsO!C*iy{+q9x8JyQ~LrQdE0W8TN^2-J9Z?H6-#to?$u8r{pKBHpuI(TyKHFUJL^)KiM;zikGd9jeaw4XuWG9}Eu@Z-rwC5H$03}mzEw6)iBxUn{sHt1#sybR7B zaiQ3~?m9FNsAKn2*|W+w`o-0LaiEK_O3-XBh`cpv+_LCR9N*+tatvX~<9%|elbK$A zl5nZ4_WW&Oj`h+qT9&Q}`H`w$F;$-_b;7d6VEOcX(-dD|$L3a&U? zdfm4f4Q}sYIjOPi(!JHa!wnWE?CTivE1H{C!Z*k-u1hxqd$IN@I=H`oSuAFLZ?-m4 z+3Yy&O7BJ5<%+fld1qzY-70`ZrIHQ5Pnl%0TYHjO`0ZF-d40?hicCCO<=CD%iz)PI z{mt~s%orctxV+s?-b7J&ArIc}o$^%iMQmV>&7T3G z5QFx3g~@c(G(ScJZ&~xB80A~Na2azc8p#*rn{0kwM*TeH@QbphnqLwes%;fA zQ5&O+`ZBg!x_&vmS|vAo2Tj0fX;)c#iDeYWW0Z&R0%+O(MUrMv>hY|8gcss>T~J<2 z`xN5(Q(2Wc8OJK|eoI~VQKNsaa3WNUy5I0pVt5Ua=SKndJy|J~G(52!@KB=f05=99 z2X%?S!wZyiaX0bz>SgXA55O;?3q#!!dYc$^=+8|noySeCXw0aHkGrGv7O^cLtU1rqL?P1R! z=#GXjbc~B0-_CcG#;PqW!*H>(_H_7Xt|#JJgTRg)esqb#z$`tN+*nL7fEqs^>fonJ zg%;M1-5vP-><{-RqiI5r8l^FGlAMVy1uJSrIh4^BGF|kq*o>+k-5-RXpdlC6Ok-oO zgqu)Z98DzX1lDie$PO&T(>|NkYiq-~AX>X$v^c$VBGbPR zPy6tl@%-p;BCc9QX)C>4ej(oebgtVk!B)HlI&-!+)tR0+RPs5hEJmm7i=Y*Ma7ioO zRN|@7yRO|=<&vf)gDvTNa{F;`w0darPMPRv^8(K5!>d3_+x9c{v#_P2(=3s8gW*I8 zIC@E*V)`5nG8IMwU>eN@CRcAuWz8*_=_Up?I69C7OblP->ZImhT1OoLO`0C4-{$Ja zL-ork{_x3sSQ4^SQ@X8oei`uVflq~3<6Aq>j&oAcPdF#XFUkpbE}7V=->t{AyK0J%@%r-vGXBUOM ztR2$NjW3}4Q)W!Ykvbad_D|bTcZ6hKV_+uZYpze*6>>>JWHMR*RugeZPyInKPX(cL zO+8ddg4bNg;m}!TCJNcAiMrGRI?oJB0<%TC1&$*?*BM8qnW&;HCx;5z-PXmXosm*c z%canqt8s}`aVkw+rB@1&4>&||y4`J6>xr%J*r?g?8xz&9O4LF2mnSyf=lV=9@$AIe z-);4u&rV$M16NlQiC-m#y1Hz=r}2idFL4yS)%g96HrM={7!Bj@$DiooR`yNXxV8CE zcO{!CzL=`i^-wpj1b%`DKFgix7?I}>_3Z8#hg$2g(M0*UgeLC%jV4x~)GF6U>gNs< zo<$vGtNkzZAIXHO^3l-DoB((p_u+NJt^34m#p6Pft#h?kaT@V9#CiR~zIioNkDAvs z*^Fi$F_$m{f|Q$sHZ0`xkjMU?OZUA0t#my*cj@eBqb>U|34XNrv@jl|>DgSHW#Hp7 z)WV!&(fHaPoE$(h(pYE82N2vkbH9XKItL||Zfx=85$Ize-KY2;fxcAY7U(<1%HMhs zz2W+K8ZjyjiacEMP;|V|pzKq^?bcW_wl3(+P887Zou^N==E)ukDn4CpF7VRcU{_`k z&B3kc8KeVU^dU)I846@5c}0?I**9$qpGJOtbh11h^9D_^f@?kt71YHk(zo`hikj$8 z^e=Cvv%#Pl%f0Pd%3S{|fHK$rs*Di*5tZiG zWksF!^?=tS=%`=Cr}?!Qr`FCZz_$@z)vqRm38ckt2vrchnP`Z{3k&nq9r6sHC)$~` z3P&_c9Gxy2L~C~$#ckYJf3D!pgQ|M~gsOXGq?+HrPz?FXY`GOI_XDx{t=RmwOq~Ur z1%U6w0pD!}n1zK$cnc{;RUR#4%@ri>Ctt^^4j^)S-U!*R5mKMjn`Yl6su!M&$a7PX zy*h_Vx#suGcbK6omGe^3>%dk!FsYrzTy?BunxH0%v+Hy0444STE?x)Kx&WgK22rExufS6q5qG3W`Dkfy)jO- z*k*EJsW=6cMG*=1N3R!#Tje018lScQfSo??Hhg&!gl}%PZ!~dLFnicA+lb2~^zZ_Y zSKe))UOqL1RI5hn@uMcQUU9i8fG>OHyS#|GQ!YH2%uUq%RYT?Q<4ii7!mWwoc;%Mp z`NS&TT)sAje5pZdQ#jT5El-z)ZxCHikBQW7pJ9xq$Wb)SM;Z7sFwtRhtfhi}4Ojg! za(&nfUy38<$y(SETc@zrzW_76=uQCq`cJWIZJM%nu}Njkc_%@+`a@g@LBpEZ98fb} zh?$OF0fJRAvPtY*!a;*;Uy1{amyv_|{ovaoRWruV?iN4w1atTnFgSe|pTYmJq{XsZ zO+n&1&&RBu9Il1@Zcy@in5$t*K58uFplQ~Z;2TGd4kt=@0d=Nl&(#Yr3wS{)d^=FR z+5as}2Q$TpC7TOLDwlGfN9yH0B4-^ba_wlyu9kH%`H~K(^;_J2sF!$B;_%nC_C_;_ zTkcFO)4s1{n!iK7k8}Bch?!l8jA0H*DJqqONnXgDvv(b}NjgqV7pvyRNffibjZ`%k zLYZk0a=DD-1Ai6j*HLGR$J>Sp%`oSA3zphZ%#xzbYH)|dbUW&!y@C^?<&p9VCA=*W!E~cF*I;|B(mqLSXWga8$26G$5*L{MH z#jn1JPp%_i?mjvc6T`a~%idru6xSaM(8Rn#!k4S%B0h^`a`b&<0HWtn6WK-I%xT#3 zW#tC9S{!>8o00^p#Z{-<&f{^`4r)08Isp%+1-_G;ybrm_bTWFE5G38v!kf4|kVFJC z=?Xa=ok)!E6_A18?Mc`RLFG8=J(5QXMHWd?J5hnbypA=Y>jG``n(A`o0GKj}xDb#Ry)< zEDjOWt8i6CjGw!IF%u78V4^}C6CY0^6JB(K;J>*Te%%7RLJU6I419=~Aj&c{-fGQ# z5_I_XpfL}KY(E=q;6&vNSLd1DM7wDjI}wZ-(OZ~Q+vd}*Z3XnQCkzSxeAj_5gQ!|iB)O#Eyf32KkYo= zG7Z13ZuBIU9pY&FZ*d;=zmD^AUg&-?IYb!EhVRFdD>viPm>DEqLmp0{EW)3Vg!-tUv)rMTys#X1Fd&a z-N{PnMc-iZKT*u5cKK|Qz8~;apcx1(RU7Jl5?cWfI4qmN@cXae9eNV*Yt< z%RA?*z4aw#*yKKqeAG`MRt}w~*E1@|#6L|0XQ`a8CKV1@92=vS@2fg}x5<~|wCEN1 z#*kOGAYbVqWA7Qft*ZO%v#6#^D}NmJPlQR5ELHy{)2ME%0X@M`^C#4H-DfZQ=*wZN zdEArAMl05fh*B6B9I!W9i)$L4{+VEhVuo)em0GWtQHt-wzN*Bl8w!d3qL~9##!#u# z3ibvk!ixGi6k>=ZZbie*xvEEbl%D6qt+H~fV=(*=qS~O3?+m`RAE+#;SkcQ#LX(vm z8M6fucdhbpMTHwD^<SXHWcjXU{NCVZ!Ya>@iD%7sGM z@qQJZ06RA6!IXxEe7DOPO20Cx!Jffhw1s^P;Cv6GO;2<_gm$2C4?hs+Q`&{*B;QNLK&yO(Pg`ZNQrV~ti zBJZcYoUZorYN+LS*0&M1r?NI<<7;m}Cm|OpS-r9M2P+g9c`-i4HGQU&bSZDfM^D5< zZ?iH-W3pEJ)SjF)fx9u3%6o|@JC0X+*7hU6uoxf54>7*spx;l2mja7M$wg?>;CK@L zQ=g#eUxpK^PiUb##xvDhp`_68@Z20sP7Au`_;yIOBmxTjJ=&zx1^-o7kK;}+_0 zkE_EEF@xA_Qy}g}akDb~C?prsEi(Vibc|*A=9osUHIV@UvM(F`E0A0EC4Ms#XRdj~ z-e&+GK3n>xh|F=3-Zu_GY78u)5&o|n?8n&B+2RbHOrZw*(4Qod9@o4YLdxxS#zhDT5s z!D}cw84BxlA{CZ!U1bS0{~UfIKfC7uADq9YJKQspUqT~Z;;MUo1pA1yljm!Qx<27v zTPX0*0Uc%BEHe3gxSh~}3|U=8AJLy5h_1zBaCGl5x=P0Kql06vYt4_v<-Ml>Y&t&> zJ_9)J2|W{IHy4jsC4F2KA`@5O_0NGjech!OX*N1h?91IDOZY6nx77cQ+;x`O!bj>Eb)M-6<#FHxguRvn?V z9oLB5Euu4$n@f+>*5X<~orR^JhV~doCVDYRFlkWFpNU?g+SeKfHp`*w(Q$Gcac80j znCawOAcx@<*15$H-H&$xwJtV-ENs3Ev1Q^mUk>Dw*GB+SozB&U^V|b-?#--y7e{{_ zSgY$=BbZ!$*(Ift&2|dhR$}%)9;f62JL?g|h1Wn)t=6hvE;RC(PK4KSE2A}g&L?+8 ze}v(-6oWBTN2C5(B)F3a|5$$6P~OI26kvpGF6t`5^luu;cxKd!zk&Hw9^D&67-DS|4`qOHiU zIO3;NsG-72R{D=;0o9isjVF7B1M&ydQV$|l!0h&b;uR(-wP&Popvz?bKmkX`kktn_ z0h2#K?oRfs%&#mkopQTE3nQ_zAAU}CdZN`qrygW^WLe9vROge@e9)$g%*uJvbM@)7&*&}-J?ev`a71eH~N90S1oZLJVU4|*%tmXql zz5+v{9aQ+js=jP~l}#@mk!yQ0`Q=fC!FKmP{QGxxSK0bU=`RWg$3^o}ibfe>t2yaH z&?Reyb{rvvL-L2jp@+E8@?eFYL5q>i3m5;Y6S%fOZgpwP`(3zd>c%g?(l{Z*4b4iP zrf@gxjD7&03d>YM@(1V3`EY2694*UN$ow^cQ`iTSvyVY%zRU|UW%6N;5J%W@tf(H~ zSI6^Vm7CPbNSz?S*bgx~ceUl!DmQP>DXglQhEi$of$KaW%tKl{-=GrcD#txRx|;9H zrX#jh*|CcUNLNX;OH}7=Rc31^zQJcZ(Ei`!Q59)XrGV^M!ZJDJjv$ji3CzDwx0V3W+#4x znGzQR*NsA%PXE7hI)`{z;#&MOgzHcAe3!Y!d-=VH`AQ4^06$q@8P9E`fA@>PZDuYL z*9*&264F~WOf6co9$k=x@*DDp4{@)dHCp(qIFxSd2ZW#GgUvU8zJbR zptsG`o2uz4=CjdnNP)s5IUGmPQSMH22;u@}vE+4&=BF&|*o=3r@$JP)94S=Kvm_J}GGtfgzPlLaD8anIU=$MG3XDq_T25`#GWWg3 z(KaY#r$tjp@7(Ui;m0UEW8n%ZBxkp((j+0+@=!?4zJODU*(b?YnL=tP8K#sUiHS=@ zi2dGJuajjldJ)(PnRT~O@!7h)Nv>=@JNMw?gf}W-$5w?HTXhlsK+2uJnT_YA&)-() zMlrH6RLY*aqZbPq1hAF%60Ffn^?4LJNOI5OB#%{+FC)styh6e^z{2R|LfNzKUeaVW z_6oVA*!dt?`Um^N30eMUbj@x_CaxmxDxyT|X&!UmUrfLz5%5YvC*~Cr-Ub2g4cdnm z13q@4R1^~K5+JYKaWS7)U!Fo)#L49Q!pmrzkII7{ryJz}O+$O)6{j_3S9P?tPW1I> zIo&B-|Ha3`%f}w(`l=!w)=yv#SLRv`)%vifP`vNuhpxJ|zxIa@0k#G&<85v`7>-V) zzU20>CU!?QJVl^+!G8A(hK3Ra*Zxz9P2f3G?e#Qx!BKznXJUjlpyNp@@t9e`xV-U`06z?Y1!rW2|1=!~-^BOO5b(IF7TMjzq< zT$A?Wb@OeEi%5WlpU0O2!DLhiwiTnY5TiR)N=DBhjBUn~h|{xYBhvhclGlJ)G}Ftv zoz8{X-kza_1EPif`XN&sr*j-`G9(6{k|?_|=$yn+FLV2V(gu0S>z)1PWJn_oYGf)E zZHEkwqAgS91rl}IAwF>KnK)Z~us7V;t4xJoRPIoB41^ajyS3u#-c#j5j!)(_QEhG3 z25i=5_RB&-4}XH!o%I(Jy$3pa3x{THyd;c!j3J9brBhC^1H9i9*te^_fA$ksbxehW z@(Xw+%JWAf&I5AQ0^3Z?xM`wVXdMG&*okd?zKb6G=Lxobdg-3P8>`oC-0A8Ccoj3jwR7Krg z46Id2ID=1bCfjCG^g5!g%FMnE6waQG*izIf1&<+zACWbknf(I6bk4%(pa}aYj@tLo zmly0UR%jfq!DnW_(nb}&UNo^OY+C@@^3Z^bSkp7m^rsQmHZXKd8j3i!J#uzv8s4HX zu4kdF<5sNU8~DtILyR9P*yuI|_b^T9oBf#x>$93<)Zv|o$?cx)8zZpCPPSvJGj2?u z&)6++t7}WuKi!Zx@hfCULY^Crdx*qK^9*GV%#nax`cQCiAUNj^e z;74zSE*t+>FhxcHD%H?QgAOz+X&U`;^eQNEC9FE@%;@Dbw`dp9+*=p7W1DE)!MD3{ zC*K|)JqiV)aqU7$WTU(AtsB#*VSakV68D52q z_vAo`WKA%eSlM+|eH#_#Iz&All1zi&{E>`Q^9LB^kI}S-!h1UK46_L!gdDY+64mC9 z1qZyDmwVwR)B)56LS!X_*}*n?WIIx(Z+AxJf&|RN%iA)8ev(O@yKSFFSSPmCkDH=I zKP=d_Lh}?+>90uK#(fR-)v0hy09s%Vbv+qdKfy<=JVr6i8%~{uXyr-eBFGDN3vqlzzmU5L9u}G`b``~5e2J5;q@r6=PL5{yQna_s$QY9AY7l7X@o@B*))mP495WP0^OsUt(-Xyv;Ki{X)L3 z9y}5L^2{MJJ4V~w_sL}RS9q19(kbn3Oy#bpQl_iW=@v5enfNMNua^#r+2|+W^JV!1 z5!2bN-RaEKy?c5L84vQ}xm)Gw&PE3lo6d4mQ1$J{;wpdWm!*KhlctCt$C|_g(zBv2d-p)mSJmwq*WGd@DnT?{u%TD5Bq}B-AFD zFeNS&A6y-=>4$`xR8veZi(RU+*A`o~!WF6c7fr8F&!UQG0hyWJN(Dj6thtyY@RA>M zY86;uw!QFS6=!ZUy>|C6J#i8AN&fi4h5jq#g&-@>p$_Q4a#PWYh47~?^U+M7r=zCIjk!dnPBiB%D@Zyy}-+}b6OR4V7fEYzX#dCdWUDz*Lkj6!#SYD0l_BD03e!KU$(!#ZS7gNTi2 zZiTv)IlnC<~{ZY zld!V>;2N=Q&!8}Y_CC<2qZA>#^Bl0Z)~u88}W@^yz?;qTO-HqgSYt4oEym;2|cwHL2w&pN#6Aly!ra?!Vb z)L`QtQY;Ejq1<==j2@D8iJ$ls>0V6T=Uy={XM-?2gYbzcP!`jCx}yx=p2{=X>&jx& zk+;>!fcd)$G}wxYMqi@Hl;P4rw%cM?s9qYWBkKqXsYR_o6?O-3i{|J5xDkltzgdSGg3n#ow%Pb1kPWe+8)i7s}enft~@r zON?I&!wCW&8nJpR2WEm9Iwb3ldUg@_I) zI$T<@!7Kb{VzMtyUo2fdZfrpXr-m54n_}~Cy#s0%WVJMf@a;QYa>F?LhWJfqSx<)C z_(lNCkN%F2*7PZE%q0>}f__u(6DMMsaJ6xg4c-OD}F;dg<~FO+Cwm% zyBmy67X=${FQ=xxe3BQoQhN?-U1ZNrJ*@l3aciD>XNka42b0YjkJ|QZUtDL_B+h#w zLaN3i&vf@)36K1dsmr|LOLM^r9h^+A3s&rvi5sohiOJ#0iC*cYW}iMfIdWF`HaefO zyaYB~me<=`UMz?c(57lbl}#==%hvd1HWr4;yXIVnezc0Pk0Kna_w$|C ztfg42f0F)XUi192$?2a92K~+bn8A7e7x>Tq>>L)if6=G!To&`BQJMecqJZ!d^7|Ej z_efI6bQ{cF->YHdx4fiW|A_|rArv^4A8y~fMvz0Y^*@!t+=7&X=FjBt8Zw$3n!v5OAA%B9N(tl^Bck!BaQO%H=KS$Q7j&53U#aA=E>_@q~pmm z61d3ghbiK@@TBRex=iincVt9+bn|43t@Rr)t`~dMI)1NAKCDcBQWaNwLXQLQ<;0^q z_zPLXfIVon@}gg3c4PiKCUUmXZ!mi?e~XFQ->^vPg;c=Q!Y?5nma31kodQlzci0k7 z2B(KCOXcxF`sSX@_8SmHtR0hyIO;<^!#>I;YOAvMu>Ii*#59G}hO(hawck$#s-?5; zB`Qg`q-h*ecWd6ORhM;(9rYoT7DQcHqLnRP#ZI9KN z6+`q3XBWF8jw0l*(lEPcCBkJuKQK7@_zCBy7CV&YVMR{b*Z|2zzb2~b0j3L_dYFPy zf72k{ZQ_OLP=ur!)$5uUli9c?L?IrnnsAWpR-^pL?4rXr5PG>ahj{UG*=egH5HRRy z$@o!)sJkrrVCv`P&Kk*bN42edi8Ed192;B}0>G*orqV0F$GM$r5;<*!hDWgDL5FGe z*YWN5)C6t$ss4^kbLujHWr?Y6Jb4kIs*EnQ2)orATFH{hU`{QuJf}8V2D3sHdo<)y zNd^7~o)=;a5WVRoUL1f4>Rd-l; ze;r&`P(DMdtH`IT{iSc-uI>SWMQ&P#OM%Y?X;?gpZCB;^Hqcd?qG&vA#VSes&{X%N zqC9&mD2pyFU~uGSqd!CAF00BhY1^ir%eb75@wj!R)-{zb>TA_w{Tf$7dmM)m_prv5^Ry`7<3NFR;%|Xb6z!eia<4%T{N8SG+C8fH5HSw-gn=^J2FQ{G` zSk-Ygar*4Q`U5Xiui!KUZE9f&VrYBInf>Vkt1FT-pkm-%td^rlWtxtd)?T_QPjmjRS({ zIXKE_1y6;~?eu=0ylFRz9zDO)@d7!N#=(oyV9&*+(IaI_dxtsn9xH;FJ+~JUqr~$F z4%tpz)Do6rx$@`G!BLmnZ(f6utYy5RCR1p}a`ba)V3WgZ=o=z&UQtC;1XVN#2#xZv z>vXQ{p9fvTR%aBzs~P{eeww)tqo&;I$1TltuCml?DA|CwvM()NgiLK!xk12f!^7Gp~r_dzPv>G#a=}@}5g_r`Xbb2C!uL znHX_Be{5V|d;_TVJJV|ja=ME?l?gqU49K*_Z73=`1%`rV&SD@3$7G;7#9~zkow@yR zj=!94Yfed2ZW~GKX=)qeD^?dvz8(tiCIdp5zSt4f5taR<-Z~3Dk_#+x=A6E=6s{%0Gcs4Ng{YnS4w=LQG&_DIGQ7jslJpFQwhXox)$r?Wol`0ve%GR%MNs4 zCgKji!;9;D!2*=Os#p&1+uuvKjuxN{m!##iN(?uslS?*PQs>aZ;-hzkaZGQ#>Eu$* zSJG5*vIxtCFA-GPYY1BO-P)p$gNIZ|x5_4!!meS#I%ZUdFI5zk<$CykmGQ*U-?K^@ z2y|gVsp4*D7q*ua0=Wu{*pO5A4cG_&Noi<5%gQI`}TxpYpYF z6Bu%Y>#mlf_|XqEZc0DKvE=y*+P5EiBv@M)10L!}-v$IVJ3(|0mTu>twute?il21u z%F*=VHApEjzP7b5*NNZ%e+9qV%++dtVN&=v#PqNAqt}zsTt#YK%-aD7@8E;|PTB9`qi3irfnHUBH_7|W@?Ouh^9zX3Cd0QZcD_|kDkJkC>SUtc zuET7bKAyedyM-bJf7WZ7RMd8{yrQ@9Ve-pt9t$UF^hWQ%hRl6S`25G6Ck5&1<4a}Y zzEd#Ab>gk9U5v8eP)0V9oKETCXw z>jSPfIHEL;y$fqmoJblg!gu2?Ujg^tgM~{)El59npF!U27Vy?G^yHRnBT36A$A7Jv zE(72Df!E$>MI-eG&swqr zeg_)u)yOGbYwI7xULC?yjU7*G^Z%mAQo!klAHu2wkC+x@K@!)f&TmI!^4OjFaG7l) z{4ih~u+qc+D>f7?dRL=Pcr5&gFs*eChfHHYm&WzPcGVT50u+0T>g=3W;|*SwZ5y_Z zE#(rOncSD}@G@l^ zTjv;XRIc>?YA9aHPTM|)wW-F!{c9`s8k0(e+i+iFs8*nknoHcr7F@CXT?gq;uJU=n z#w~EB(|-LE3Z_yRdW%;#BD|}Qg%dE`ht_Mzi~f?y&20i&iE#QSdZJJA+2UWVj5soS zVyrf5cLa2h>ZZQTo7%)z`$@yOqfZHAdHG2F)1q;C$(b9_WrpnU7@YZx{681FeI^7W z&Cklqk3NTiyX4%=Y~&9UEyj&)3=Mg^Fu$QN2hfp(;bWF)5i!lpAoqEI(d!={!hHc3 zdhD23$v^h|qCAQ6C7C~WorV;l>=3kTu3?5oQeEa8Zf`!*T63;X1RhNowa<^(O3Ca z2kiw1*I~tJ$K%{L9(kOrB&IK180Q{=4t2QypVFaz>WT2<8J+x~JNX*UbWJJ6N+keXv;JzVjUw3_xkH*tP;+aa%3VOY+40<8=k8?+`H1vbFm2W%@(PgsHkG0IlzM7>Ob8+ zG)Yr2tc@1^A=eyTOZJP_u3J5W^$#K2!WG}D6lG)`K@1ib;Al*Ht0q}}3b$%e3wCjy zZ8Db}eU2Y~6CVsN6l+blxyA<4W)xcZn;FzL`ZkrxWt$Q zx`~$d>L(I}+G9U@92VPP_>PdCfVve-i5TZx$H=75hKBHa3TL@$V->TR-MF2n)dBZj zz_VyWtu_#kDRKL7mA{vYtYIR0P}sCT3&q60&f1=mmiqB<4;H;Y)EeOeH^L$I;>I;i zoWkz|)HJHy+(xn<4W%Ec-Bpw5#_jiNNuLMg*eQ7kzg)a$=O?CP*pBQ@Pb|)w&?6C` z1Onqn_yep|2GOj&lpUn?=uw6YT*8wmN0ml(%TzjP+0VFaIJ!>&S5x_~7CqaVLK3Fn zZQsD~*psOZRBQoFnfmE1Y@<*ywxAZe>|KML!5I6%jc-BL7EYkPEwg+@T}#|~6`)aF z{~@;dAMw%NXuSMY6b4eoph*46J}-PC3oYNiGx46l+0X^Ny)(hf5PH`V(NJETFwqyM z@!ZaZv<0`!Pn(zw61O*ye)tAfyX;tcnX=m@pZb1hw3${Pg;<28K`Z?Xb26siGTK;I z_IIU2w6Wz*(xp?g?2q|-izClyGky|G3prxWiAFz_o6Z+tXP9)3EF7l(+BM~6h7lNPK?e^7XkHSM_|nU4%{Ie79`y=6XNLR;sZ{hs! z^InZ}(r6y6Pkk=bj= zr@A7129giX5pM?noG3PJ<+wCgc6;fr{bsW(Jb`u{S2qb(2M2BE&g5b zH##SG^Ene3Ap8c+1nB(s4$D$xuF#I4D#T$}Etvb9O27;E%Hu-%sDEH_^GxLBaxT67 zC~@skGHjjgWNe{rMO{QT>1oEAJhZgh%WmZUH4$N@<;zrGy#_otsO)wB0Lj%CouvWK z`k3^KW%tszYoXdy40nLVY0r=1F+OSWZ|saO;5feLFj!)D$iFlG;p2vAIOvG2BambE^p$&>SVC!kuG>Lt$P+(64f+M)pBvVQ8B`Bf8-TZV`GHyrgCWA{Abjs zFK}}V|CpQ0u!@^1=PPOB|7__9po5o}L4Yo28ZRyKj^#i!#JuWN><6sCRe3_`3a=sC z_%S-PSO7_1R9)jjVo#O96rD5&8-i~x8>hEUOGS#n zC~-v~xK}k-8nnLEYk@rgOXX70CYxwO;$NZJi>gOCtfj3>FLA*aONGq7ROVv}NA{&q z2pxs8#R+Vjdbz{8FYO(q-n8wQO&on$(JS*EMK5Rjyv(z^InQpFi7R`R*+SVHv#jht z7nl7w;Z3o{%Kj@V`wi+!4#KNEcc8wTJi4u&h$nQF=Oz|Bkh#QT)q=-s&Ewz&4;JJ= zgz}j6*iaR)0|KD|Hj(8(g} zAp@F}A3bRgor-*aV7{y6OTlZ;uY##{hPPrK+Y~TJp+VgmV7!|rYWY>p>ij2iyR4qm zUjh9b;*nl1IJFi8%eS7Y6u?4k20N1_>Po0@(O+rjt%S^raYbhpCyU0ud2z3}Q;eGz z--Y(U)uvV!}|(tC-Nm z^WCt3ueuS0o^ltli!+Rwe(`zmE@&39clyxJ;A1%agw`t0RhjsYh@&Utur!1un4V}k zg@I-%Vwj1HU{tfo>IQ?D>c$LO!|j z2Rz<~q30@Hda;ZVXN)>yxiiKG%q(rC<@(`rp-48z6?>Cb+$-dfYOa)rE4y{@Ca3k3 zE${8|K>8!XFM`kmF@qOBk<#;a4_FG zl2y6zcWgk7oL4^tyAF!QN;|&w!m_+t8gJ(%V#6oFMWoItII`BHoCl zW0youh&a~yG6~*<4dbyG;c@cih)tnUFQuxoJ6@g_df~AYOZ`k7%@gPiU9Q-*eMEms zkxMX)5jqFZdU{TBRuRiC*0Lzhz5t7q;d8fzyCX;7s{MS?R=$(7PA5iJx_x}LDSCJ} zMm0o$TV~^)fGYfm_s$|ryWh@AWo33L&svvz4{WN#T=7)4s-9vwHePCbfU&2$=555o0Nux z=g~>o$1@DZ;a$nn)&VbxPWRQBn9Cd*FI?Aw$QGYh9PIe4Gqsb!r$4Wu^oFO`Gq+S? z#)0T$ayNG}PSXo{5|+Ke0O{7Z5HK;X5M9!*IARTjo)}(VtmlEE6FChC)hiL(nyf8; zpJ`H3$-%sE3s9p#`8?k^R_pPvxr)v=I!R0hZM$`yB512`;zv$yUQb`e>&F{1Pin#}Wk3pFU&dcn>z~~gnZ=SB8@xL3$I_4<}Z->0XQwi+N zD!*gyoig<1M5ieR*Aj^FH;YjTy&ZCgrxRjY;G3r^xMZQF+@9?%$QbVNz}3F&vh2L} z4qpQ=5&X-l?sd8NBdz$4Y0(ywwVC+qXP9d{b~)d@!*x&;b9%aHP)rQU$HGIFpY~UP zU-}s{@wvRk5zFb`q9WUkYy<^jPQ;`YMVbp@0j-?1Doe}B9zn=88Ebi}pT2H1+1uOu zcw6&?nY5M1Ld$ckZp@IITyO-lO|5*+!)0eG;rZB_7w~EM-o`FL^9gvYyF;)$WDVbl zryk%EVDmyjH!k9fPU{Jf$rY30)-~ydmR}=F4IN@cjylTV9(eihNi>E5Xk)_%2|I_wkl(OD{xD9 z!&;XeKRnz(jrV^e>?PKAo&?48L)XCK%di^bo0nr_jrnAZbuR#@PId5m@3 zCu#*ERV)zkta*b#8aLWk_Kr%Xx}`cMRZLICtQ})@Oo@4!=0C~U@y~n*xyr@dyz<~H zlte=TJ>Cu(9gI^f@K`lNF}{-O-gAbxLl!5D&B7M?0k@$2IiQJa8d$J^sr;p zzLct&kzzD(N%uKGx!SkjoerOiug13lXoH`>`a_$aBHa(4r|{NbdyZG*Rk4LfIqH+@ zSan`}v7+-Q0Pga)^bp|sL)+y=s{pUA_nmpDb34}q2pj9JTjzIPbTA>&edGcK`E7eoWgs2hi)Y5ZisLk6 zS2MB9+e7aCCaw8it~zA6*}iV0=&tlS6kJ=hgC93t{Y9salpwyRUq~#ex_Q(lQvqW6 znZH_N7ZVjGGMsHUXXRuJGn2`-OgsK+dlI-^K)c#;>NuITUn9dYGHHZ9&@@1|ZvAKS z@Cxz}-o+_ZuKqRgBJD+A$E;kOj_$$KbYlBI?BYcY#Uv%lLS*%P3jTd$$ctwCd zJs16n&#Fo_ooy&Z!+>2xIBbK=M|7Vc$}z;m_lBZxfWP*dAi7=Bt$N~hE%{}>_bj4y zY?z`QuC-zMOoh1fa;|kGUTJMu;j~1>ir?5|yms5A7S;0AyiQme`lgMfbze}WG>`o< zIlCnaxajT- z^?i)PLRMi(AQC&+*z))rbEynjRhlv5oTpa8y!aNds;;a70XjC$+coKr>*GA&+!_&@kK>B^SYdYh20nn zdsZhbgp|S_1sP4+FM5q=k~)lDylcf-uBKiU@4ZNkTfGl&UiR$3P>eCSbsFo1#W<{9 zCQWARwZ>P`mJ1r+#qif;gT{k$S5Vw*KC25sV~;`9zQ?7I6rD5OQ_#2{zhu}?>Qyu& zH@=B8-XP#S`X>rZg#*gT*D4dN)C|4_?stOw20hT_*S_7x56wDHlupN+J7}ySOPfs9 zzYX@Ls7Bv&&@vM=Id<$|ViSJ@Px%-iMjQ$Vf; zQh8hqDWA%SAT9ru*KjG>w80E2TN(8@F^k6X$q7rlH1p)9Xdpy!c;{kCJ7{Y=NC_); zF#XYtMbitO)a(@*i)CKLsZ1s;fT|K?!XZrVfb%TNh=3H|0UZj^a12y*Kwaf*4K?Q} z$DmBspr^Ckv9zq0Wf5%*nby8!x_V%_q-2HOKmyOA(2*!lT$DD02pYo{;u#-_r}!3u zc(OloJZ4{s*IAibdM-JnBNn2k0~bBLKuOwBlD1s;q#Y$(;u(mEq8}4&RNBmCj?Ho6 zX&Y}B(llBfsYEyie6K@KT~qC*>>3QxNB66Kb2GI>W{l6t#IwM2i|}lJ9TR%y3MBx7#&?KU z9|5c<$Ta0B`&JnV^y^FT?@s&1En^IJ%c?%uEsy%>x>nlN6hCPo)0t%2RTNBt&_mZp zMUJ*>VsoiXdQ^3h_2qJm*4Hs$UI(qM{j6J|xyW#*cG``iO(by~zmb>v9ZyZ1uPZ)N zLv?kw^W(y?An>HVg-L<&CO71EvmcOOs`)KPQp3!X#ja4@fetB*3yddbYO636eoxSw zc+xGj=zddOnu)UfQWi!Vne|^eNBCntkN7IlA7fgbh}+UL;G1iMieDXP`7KLRaIxJwNkh+I zZRj}PH#2$|C=(TQ&Y$9>&bi30W?8(rWrsf#Qb)4cOUNkbj*dw59f=F$t^KI5^{2iB7&e*C}Sl`QMUp@+*@llqhqQOVm9Uo;AABA0fl-a>YbGG@7Yj@_u|ws1t#YGHuT0_}F&tybJ!c0W@)I@sZUb*Da*eAes0D z^$?Y7nsar9!w9_~poQE{53Y|e-(naZLv0S~97g`kfSRNHNl zdMoE~w*c<~Iu6n%hT~%%KonC?6eFy*5N3IL)(}d!5ATd16m%f4Sf)uKyC{V(XH0IW zc54tF1WeXkCIrkIVQ2--WTSV$rAo?#gKl^}bts4?fXtZePS(D>grgfi%D47*ZzJE~ zDqzsN%D3C)++_u|AR&I0>*E|H^~BcWNTK>Pz04w!CiIF#hX7L}A81!8W0i7o%dT|N z#MwQpmEClP?KpAGy~0%i9yNA)Yo)Z+GF|~ux@3r2jQzCB_WEmCJ*1;5QCxmd%_!+7 zmroAglHuP5sYibE?-<-%MmP$K_V+4Y$N{$I=pB9%-0s4cIuBTU#^(v_fx3^uYLCaq za}z_&Kg*cd8zk|qr}(UxhjaA+n}sz5P@bGi;}K=}lsCDRM;80Md|3}ftHmZR=liiu zYTUx@)WJGxHR8FMlY7pwr^_WR)GTVlOdI@}%5YeMYh}MbQ4GIGK(t1Yz;JCFgAP@u z@NKVjrUkP2G{X8t-RpXz>U%>F+}{ch!{lizmK=}4=0|J!#!{JwW34^hK4aIKX%}&| ztW|97BPn)wWeIo`yEltu?m8^Ic&I$1k*F&)EPELHbS85=IP~W=MDFnPW9USLYv;RY zt#e0Uv*VaaEPI3XeCtQbZ(boGoqEM((_-s5CeGpmomh@ij9O{coWpXouxv0a3JISH z7Q1=M949;mpYmkAhA}U2`Pn(ma#vPm9(Wp^+huFkx!Ywh<+vj@?~Kj6T=1J>=bL4c zN6n26#>CE<*6plIqmS^Jt)f|#L%$DFl+~VKHii1>@cB46EW6QbyoK1cVki7s;G@Tj zI49GrbD=Z$!Flo`oN)bQ;HzGm9$5&h{`iwXFPhNd)}~20rO_xqOu$4pb1vn^OPPw; z*(ZT^EP6IzO`%DJjN8^;QgqtkcI1GY#)J*tP|0)_`r+HP{$`&%nRuA>-0jpCpT`fw zEuyE_H?&UY#=z`6*k^yp$LT5^Obj(YK`K;5roolwC!PI6APkvnR+>C~N}%mXH9v;k zi~fi*rRV_wy4M{`YUKNSIH;I=i_6&(vR$CwtUZ;pegy#8@EwG&AI3U&3mCG|nb4)x zS#%bb;+nJ7m7R?>I#Hi<%yT0YeSmn2!b;KO1aT4{&P5XWz(@jeF}>^F0=MUGT}X@f ztXx_fbbBeE+Bdn5HHpD>e$|?`Q1tc7`R&udav}s^|3u$TqZUiMXB$OnGiHoMySi;8_f{Muis4+ z>Xyz?BxZRTzq8=*hxqkj*PrGts<%beTgiE@&v)*lr z;{QbaCmNUVEhHP4%1EIekC!{KR*%l7P!?&{DZN`T#Z%zuF?o89U0+GJ09{DR4Rdi)8Kla;kxd$3AdImRU? zaUOsC0_Pc*K@6c=I|hq5IQ-eCRO0BbHu;%kf-^zMYBA2J!i}lE__K^;Egl@p^hX6k zaeNU2VS?&(pFex(0>pSQ-jtVKr*;L8S{2)wjoIUulCGh=&(ib~Zzjz*QTH5X<{mET zK}H4@x!xE2Fbzr4bm5oqU@PE}!l-dyAhbG^8K0c)_gc;rPHu5N3NF+ok*>;w?JrAs z=_3KBv-QiU4)x3VaPE^zyd9eLH@l8(x)wdJfnfG|3vPAR){8H1Ju|Km8x{JqKLlvk z#K`R5%v>@%RFr#kmMI_R*enlRVJ@BJ;VaB#vp32N8;o7^nnHw^(nGi3E`QrXpe7b` zpW?GO_$pbdKLv8bZG7f!P655@KXtX_&Ej|CV}N?rg-2H?dmknelQMa`^BPSjkn9O; zJY^1`&N_&$6cUI+i@}%c!zwM>c}b6+)p2!SKRQqG`o34w+zi2 z24LPLSOnpkvVh~AavSY_;+2?hG1}#;eqbZSuuu#?2JL=ytVnA)HsN52`dAF@bkLKY z>^0(eneaHgCmP4|?QNXEmp5>1u+}o7JtVV$u->9OpUO`0pm09922AQeIZkeoa0;=f z?kp*P?-8xq#4w98@or_JXf;_wRmx9jtOtE`|+pG`3?N zQwqk*lN)GuN8S!A@R_`B-7n2{!DEJl@$-*-mviWa(S*Hg5{x${pF*QNl9r!X_X$36 z6GkCY2PLalIENcf$IH{4I~cVit}j{wTSdHyo?CWC_VXFt&u45upJn^`EZxs%JiDLQ zLN`}p`bs$(UyUMTj*Xwmwl46_aHg1Xf9meKsTkDat0}*DW_!dsv!wGEVfAB#8W(Sb zU3XI^rJT(cx+^@jsBXJAs2-3VuTAs1mY5QsP8(b3tK**cfNXdgRik>)BLHO`411l9 zmN%zul8N^7r_w5_{TX{W!RGTdE?5q+xcCYQ&8u}&(cI#~wP#(CVx&f%@D3m>K4(nH z1y^`FRB+hDCeA&A_&Oismv2|i-ljUo)7bdxZ0cc5ogDoXbEf`wJxX<>?w((VuEFSD zJmqM#9QB8hA#-~?%b~+?5&llSkf3ygQJC<17k*nEuAdSqyg$bEvz9{&$|SEeT>maX z?74)RlJC^iaj~P7f3>eqt9_v_LVR)jI21Zi0!sfTPfj4F#%OYai@pZF)$A(C5%WQ^ z1DfNfrGH5gIzUS^rs7M!9B!Jy>Ib^CI@qaLDhkbX*)-Z$c#mhKo1YcFWb<<}Qq9j} z#PxI~ZT%gh5lMlCw+>=1JDseDE{UDRseWwYxC>aM65e?gH+-2)x8T>TYLypTK|f|` z6FwFNr?mmoBp<$y)mHsfH1u6pl%T8d#u3*Hw~Dqi9tRBT7p1@2lsze4xDmWuKV7q= z1gaPd#ty>LTTL19;+Tat74L6T(V{hmtp7;t^iaQQ7Wz~%5!H8Q>RuU2W3*oL8e*%} zX!X2u=s;CW_QHPyi7p^(ovQJ!pgE0Us3P(ujHV$M5egT`soJXmYOnmMz2>d?Ll%CTE*_fpGVLgdzx0(yW4@C*-H&n}_&pZAj&3J> zJ)a5Bq_?A6WDoCBzHgP)5C4HZ7rg;TQ2({dL3NDUZk|GYr(oVC&#v&@ z@_Zeq>F>ePydO%WT=lz{wGnTJOfUR9nCkB(d?;jqt1#7&f8%}lSepr?mn-pZ_%BW8 zywM)ZHE~J?T=ah65RuZh4HCb~a&!O;vbUmR$|qvV3jymZNB##%)V6@C8SQ|703@wE z+{>tiv!_@{uX~sp;5Eds0#6UI9q~az3K>03rs2)K1$D%Sfx_p__*DA?q`4J8GZXy_ zMhs~KA#b<2c(yHm1I>?RG8*tpGlg85$K{@e4-b0q7uG&3 zH*djBg#U^SRjb9yK==`P^2#|%@;@OOmXeIhQ#>HfM-|L^GH=<;_m#HtbXy;9J%5aV zsW-Ddy|s|eGyQ7i(`w5xNw%lGhH5p+*`tpGyZ#{>g4a;>jXoiygI+^5H2S0*h451{ zhKjtUT<}7BJiRzrv`46;PZRVgrE_YlbV`nK#Wm~mr64~XJ&icilPz0*Fki?I&Hj?| z_Zn(_;a;+sABOnh{IH8UnQax~-NnL)6DMltDnH^%Z%GG(M;wDki-obu8SRvoEO3uE zk443y?J%Q)XO{0I@kgg4pC5y+vHaNJsN?eO`4K!u@+13jd3A4#_G8YF?4X|?j6Oq( z#Y59`PeA62_hkp8&*G6UM4yZOuXFwdTPE>3^yl#p|I_HP(#l3(z^B#&eQF_L7tH}I zUvyZ$gyG5%zb~6ZWeEPS;HWH$#XAP-OJ7L+eh=->Zj&IKG}}{RIsH6pt7ffdv8489 zmv(rSoLAW4HR8P1b$BgtUZ=Ob*yr+QFKD^IJn8_Des3o>h8HQ?T0Kax>8-a*8B5z$ zlB~6BWVcmFj)kpLSP2)jW!9@_+c$z36XDwA)4 zB59F{Y>zb&z7~)50hQP(hx`h=ByNw@?i^?jwTE99T}Us#g*{Z?^rgQa9!lfgftoBx zL8R0M@)a0C@_M#c91{ntLHx;g~!{l4e<-sh{Q`|N4$wdcLp z-h1t}B%6FYOs19cv)LUe01ChaVb;~c6Y66Ce4Kg}VcPN@RMD?@;-6Bt5Z zcL;Wmz@90v{RM{9z#W3!3mD{Jd?)!sfc=j#IIEbJuf~^7GRxXC)q`B495nJsh!qiq z1QQ_HoAcG-7gAy>+(l_#WWyjszG6#}fEb)>9;lA42~6y7G$dju+nbCv^D334DEg@2 zeU>z@x3O~{*=Q{HqZ_E>XhK&K@=4u^-1o~J*pwH8(7q-ti4R!0|$&gRlfJDX(Mg4bw__c88@-Ualb z&$si>u~197Y%CtXfdyjnTryw>NRwM++m(Dm=?Wq~PkCE+8O7&N?v*$esMLB2 z(s#Lyz*<)Y;<3W&zH4Jc z=t&#ZyZO)7iLqu6%|4|L(w^0JVV8b3SV#B95@TtdBNw~JUplbXuTt~ZsrgW9KAf7r zNzLD;=I>JT5t-cWmyJi1?0E3vMG@)-^Y-n__2v7*zJhZUQ8Ird9Uw9dAmRxqo9u-& z9{h|Bx^FwcfVux;0^;ZPZivNaim1$6P4BP3lo*q?<)*9x<}kxqT(g0DZkHdP|Y_{mHB<8 zZ4WS}lB`~QyF;>ko6N9a{l!)W?haTG^tHo69!Euk=B4l2vrv^`E`8$$$<*8!gsE~Q->%7*&`EFkNt{p~agSqr|Xy{k-%}ZbNV)^8``j%ml6HD;aoUo8}gVE@H zQFB71T$;#Umq*S9XDavb`XcqSJR%W@Gg0L&^;MoytMZ~{Z!|9$%ZmfIJjm)!Htcxg zsXoT9br5;_5_v)n@Xjdlt9Oqd({4_#&qRlrf*m8gqMvbE7T=6!XNme-G8&pH)@T{I zVQ>BPoZ5kZnIZp0{%gg>ql-p|II8xysf6zCYmFaOi4<+np(=jBk)iXeYz9 zGJ1xPT{D|d!1n4LK)HE1uQPD(%glMr`@sjlRxTgL?<5>0d`2g}l<=<*US)1Q8GrF` zJOF5S?MUX_2eHAI2k+Lq2(yRAKf|jrzYngbZ4Zf9{yFa2vI_457WYXb;oSgY`~;)9 zGgT7*0sv6`Qt>`+`OD;>1J5DNmodHnII#>1>hYiq?0#vsJH(R=1IKw z`%lUM2j~cW1R*hzx{B=smjU=+YKPkZD2MrEEkV3~*;7U?*$YEl8ny1|^?Z9!qV_!i zo4+P!z0pIKRX=(zUiOauZh7Qu&u2&V6It0+6nG2rZiN^7i*=q7amw&8K{Qk`z6$^N zV|;3>!46CJ5oU@XQ2{C7feGbkRx(#K)OqnH;wLI>(&v-6l7kKs^Vh2Fu`CH+_W zER>l6KU#y~M|<-%`eu7xoAhqD#KT=SEFa)0`w_EG(=lsXkr zH;k1Qbo-=BNb75~3qpRH%t>B# z7jp>a*V}n^?;KUA*>{eXXM5+U{-}43Dwg$1?CONban1C3(2f@~|4eG8ckD^e`0DxerqSUVO{9ScrZI6E#ZB*52plqrlryyx;r} z@x*(>fr6n37~gsZ^JIIuOqBDPPO)1MM=J)x^pzW*i?coLP$4;@5Z5ha&#VC2)~oX<;HZI`W4Zp z(p2LGYPi%D#0yiGicyIN!Vy6peVOt(7ldkS)f`{B zD39ccoJM&f#;eP6^aR7Oc^E?z1$l>Sgzjf|MuoT!GZAhck|}zp7@p}BBSgaaaQGYV?CQ!{4Jl? z?2bw(A6ZiIE6C$`<9V4;R`Ovh>}VESaZe=f zw}n44;MHtjzSYAEtF;F?OJlt_mv14_Mi^N(#V38Mm6<}_&rwT*<@qeJ9xUjpgwaYW z$0g&y!7rYT=U~2@0Zz?+fn2Es&tuci3jlmxf)B=vFydE%np681VTAGN_yp0nDC+pF zf8fEpd1sJNk>vt+spPlDSW6@^IMP>t*Wv&%L*$#Pq)*sywKy&IOC%mHLC|0Jzu7TXkyp z#7^yvSda(_2Q9*>Q#+->shy!DsRM-?^B|d5Wv7Mj1{23cl_ec`1PLAk6i?d0&V5LV zKu#etH-|9@*s;SHncMUUu5Mei!x+jT`i`P`-(Vd0Eg=c)>kjA!9X>`zV2Gnpjf9M@ zSUx9S8+4|^MCOj$+>s6kb_2P5wHn<|<+D_>zw66YQYSc6um6dupR0ksuzsq}Mvpu_ zs{m~~UpVWELN=w1`O$|N8P1=LWqB+6f)O>q`EAHt)Z-wLND(@JgQNlvRR!jg!(FN?^dp7o2Jc3{WpP^u6g@zx8o@vf(#3G49zN(Q&1Z7R zC-O)*f;i?FP>m!^(&dcx2w8R5WfnY+%skA3$1^hzvpkq>F`|b^mxpx+?!=z+SF-1# z-^lPeu432OJcNm-c_^Rc8N$HOkr{8qM+wG%0GM;iqQ~{9_Z^#We~nkfk`y-f47ezm z&-k*PZni&#Aq@z+!%XEax|H2NUlsqA;biy5e)O;q9Nb3G|6~M$;COYW^4T3AuzdXq z2($b}7V@U^bVTLb&#ADmYy`0~vzFCCID=T%k2l1m@BPA@6bm71k#}~1nx@q1PIVdw1cByGB0}dnc(_w>K8uT z_@hvJ-L+aF{umamh+cJhq-TlTl0i$yK7^Mh}DT2|MF_#^!PBLa=v&oG*t4t7GP9|k;miu78 zB^Va2-pJ0-u+|iq?@sO$~(EWVFtN52!c2X+ERwB0kEaWQ?k+z6*Txgy5%_Zt3>3^T5(b zw26Ycqrc|e)Gk7eB-2f_Q*oJBC}N7%T8()dIQ)1%85s^LKd6YeH~uXs3l~$kE+nE< z3ekOmgc>}AZ!vndQQ68v!PepLwc`i5$pd&cUO}Tw{0CsC`>8NCb?N|x<~ZNZIvX0A zt+SyeUZ3hrIGLNg+uJx1iv&|jZMdhNFJAJ}M!s@?cdb;cyhVAtzdH;D3ehx~qp5Gy z2?qRumU1xAbIN@? z8n4We#QZ+_4A47nYSRM~b{3tbds7`)NDZ^k1gh~F+E+|64r}Pft4-(3bV#v#J48wt+m3!Y$Rg=l z`WdbT@+aTQ1OnbWqwFll8~m1XZyH|F6`#6>73A!C&pit^s!=+_}>h9f)(}lr}I*C+TDD26nhZtIQb4a-I8N zr4hO_bo1hnYj@BiY>;nsBTX%0RC~tb=szDZ8n#^qo-)mhtq75&JpRGwz+GyY*Af3f zEpL>IYwq#8{!O4GaYm=P!hI!_95ngk90a;c78IJQ<)c?AV4$gO_73uOw%s2xE%m>@%xwQ^PMRq+Gb1C(!oyi&(7v4D(W?F?-> z@3`lE4%wm09*3bmBPUXI7FDaZ$XA+a>R@>=7_^!RX<+ zvbuU@8!0umY*jUWoUG{W2a>GTAfta(8z1gPXkX%uX#5&5pco#0Ipeh6Ttn4t)mcd; z2sXuk0}IJX_SN;|?+5frHXz3YlP6Id)#!QT)QL%V0=w(IPL#Kmxh|bS&dnYsdN#1U z4P`N|9y2gn?MY)C+YzI2m~-@w-^@LkO_^tr#fABjm9js-dbd&q%0T(<&pC+&b!4jK zEzb*RPSqUArns>cip?KGv$0rdtrD*l)_zKtAK2WN^Eb1w{>fcNtO}!ZRHF#uLY1FM zFxZ?Aqm8Pg>HNq*dD_cuLN`TjQv`=@xS6FszsYt}csdI^A+!UMhLc-5=$du_{45_I_JKTAJUUp1m9Ip9P9Qg@S2U!*s}3eQE@ zr|}(0qpi8N6RZ%wpY+0*jfC`Q6iknX`d1L0OwAjc6GYun*!$=^bgfNMk(z9b&8=*| zqq4(}%I>2(_2u)M4fpAkJBH32;0(>MOQR)MSHfPX_Z0@B@ zmbb^z^Qt{`RTu3@g>M+;3&@6Y#&W)X$b8(qXEi(E66MghFK@GhL^-a%nfmbi!(4Pc z6>d3pJfnr$QE-o+qHJ=ZJAOZDFNt1^6W+w)_@8E-Wdw7?ISN+WX>P?8wAUZXMi|I! z+xk&BO$%_E7TnQtU%37va=>soQR4>I#>UFIXgXWDKi|=fYR4jgsTBQSu!-= z^3STKUfsNw3S#kMLM(T$doN(F3VVv<#YM=?(Hnu7dagf%RJDNC=hGHlTsLj5EDZ0} znHORs(%0WZ{rSOFy@bzDGYX%cAm5v7hvW6n%ycI zHnU3A3JiAjIM*VkOrY~DA-{=Ha9E>EWP}ux@@NpUSoUXU3`@OhZ*^x3izD`pj4bti zx`uZbb&^&=5O1WM-5qI#RO@h02Gs!XiaY)4_K-vWFCv~D1?Qf%!B3m5URc2 zHOeHqsT!T2M(WGuH@P)`b6=POgmA9rH*MC@S#*UON_4UAIDSh0ZM}9vs-4tny~9|= zQ;Q2Ies5{nE@Sgc%T8I#b1?`IUh9Ol1zNkrtL&DJ^eKkc$2B*n0;j>PG@6)Yx-#z= zBvquG%N^}sV>-_Aa{f%gJ_Za+r9_3eRo;AXRX)I!K)Rkq*%|z)}5=4veP- z#D{{wO~cGr-8H|$X-ls8Mjj>`{tF#`9?c8?t7YU8-bD-lB!&UK%>ljM0lm%vz0m=^ zDFb?s1A2=CdYc1!hXZ<-fHV*8K|b$QUvh6Lc0=OCpV-1d8XKFS>CyMjr4+xVWH?jiPcpP}}6L8aQe!sY2bE>D-c zJY6Y++mx#?NB3vb;>f<}OT;n#JkKDnsL1LMDrY{&j}F!V;!t22v-SAFB(@}e2klkQ zFPo2KUVoex%DnugWiNm!qK85}2Z|YW6XdX(YgL~mj%{CVfeRvVEufPc7s*W)tDnxrgytAGVQfH7 zPN#c6Az@9+r@rZyuU(8?E|32V$;^3i9I9FH?9dge zi-u3|Z@gF*xAi zttP^0JXsF8AgU+uHbWMZdtymAx5HxgXJ}!>; z(lR?fE>+1aAD3mxba84@6(5&o)kKBCuBkOqxs8A8JPoz%yx}v!vR#mevk@l^K6@)V-FFZ~~X_U1*LnZN&|N-IfTD zS%*`~w$r4Kys)Fy&jfke>Srk(?VH78Av}Idp&SqWb1cU)Q}(1s=`~~tWmJv^==Tt? zSpeK||wHNsI8x9i9CD^>bz zzp{EU{y;5>>Q|~lTNtrxVN6tK*tI$)su=8AA`{h#^|Ln+v!j8x;GZ_|E3r}>I~$p8 zV*zZ}#&3S=HeSm1=>aQ);!$)hsvSDU&ISL&{L|Kd#-OGw1Fcs9W|UlSX;SlI98+6^ zW9Rrq8n}f=#cw5oc`<3bK5;%ywUrRmYG|0jbUQDppGnSBaMePq<$Ix5ybL%6wT8W! z+ZZs?u!>$gF-^^NC-!{mPD-~J9Ris9K6Q6mEUEmK@KBoY^n$dAuFt$lHK#r!ekJu8 z{RXKs{o6pnt^VU`MR`*Hv7%-DNBBGXk2%}@=fQT}yZ)m#o$Wt{)%uS}9`zqJPofWY z5k83;0{evQs(0)nff7}M^`Ey8v!nk^;h*-O*I>>1k7%5-%@G2i|45IWW(nj6ZKuWV zU8)l%({-$i6qAl647Kz8mfUW#vEKLw1-CBb8=V0T7w66LM7f>C ziTsw_9i8z41y?PUDdva_GKI6Ah;lpC1U=Dkxl|RhVJl}|u6_tqW?Wx-JJ3(+OL{-9 z|IWT-HDUPFm#j3_m&UU~x@;)WvYmA_WxAuInN#bZ=Bb}qKNDux&(!v_{mfFdekQ6} z{Y=f2=!0FfbE0;^E&@7HjbaxSov2=|pZzB>JNnr+{L_AR3D&Hi&CXK-*lwP>LN&Cb zwJ7wirVKx~GAJG;7s*aP>Mm5rPNx%TJ)#p?syv>4E1`bt?R=|#>zx=K^U$RVqq_)} zE3=l|?e0>EPA3z|#e%6CNVdcnY6ooX|1CdKeraMMa83MP6`;MR)_n2a_qwLl95IVQ zO=rnwO{es-rh{Qc&TY4Gs|3yF+V2Phs$u5C@C8o{o; zO`>|i{w~>7Io5tx5woNH{saHC{r(f{liN=K+qK_^RQw&aU%`W)Hk}6)kK${4lgfJ&{mGCTpx=6*q8~<4-ArN$ z8K^t?%isHY^+o4%3iAPvU&0aaO>^i~pNE?I*-YzHyFq)uACynIV!85noD$V`r)ye) zST^5HRGca%J++w?dEL`A3AF^(ILhU@x^{q)s4iWC@k=N}ZI2zK9&{W}Jt=iRQZu{$ zezh9h`ujn9QfPiUH+m-j@Tzdg#e%~0maUt&(!l!foaU6M;_h}QNSm?1xl%rmTo~VkHJ3w^A!Dc3jYGom2! z9A~{wLv{(r_iu*`)`kqXlYAi&F-j?r%o%L9+4(p*QyqOGHLp$0Ps+Tl&D$g}Ed>B)fJWZ4f z<2hb{OU&l$@4`dOPs)?szQ&tG5Pbbf-cQGSq(2|Tp9NAE6kKx%XMA1ijz5Vdj6Tn| zjwTCpmN7qtN37~Yg2%DEBD4A{7La?R%34s0|EUs;;8rzqZ(tZk+W^i#o&kze;w)O~ z`!9UKX*K-;C&Xj6rYXJ$Q=5^=d-|$Y~t*ejP<^1}{u4i55>{>Gi@Oy}M<{`Eu zVuaE4s?V5H4&C(y9;ZUy!-Vr5-5QI#<+S_g4ZIq?T&pnx)Z(sz(fPhOC|c9HcMaF` zY`X#HSuE6ms&*Q;GC7E^SNuo%xdEdYaBu!s^FP9Wm47nk)%Iov85-;LtK4iZ8q52O zji~^y5?*p97w*wzn17@GZNc_lFa8|)8=c%2 z{(ZQ4^>Ecr3r`KK^Ka&aoU4yb(#Z5>0lK~ae8$Od!BgSB@&>$zT@Re?f8FTe>$2|G zqoZ@{eVhcUnXN&)TsQiudt@=&jqbgHa`*BEG+!UqGtfTPnvB&xfKk3=j9wk9oso7L zbX(wc>1qryQevhed-E~geMWXyxOcApynOwX9ibdQ2&h^9!VcWEdak}QUmw{~EYf)e zouUJJn%Z%EUyHq!hh(BWeDB!fywz9nwoPq%>>Ir|a`xDTz=3a3ZSYQgivG(S{AmoU zTXg7A1CSe>t9%Aey-u&?qm{7!Odmua6ny+dKjc~(@~EE!)Y|h3 z@dC`{%e}(X+GEm?jnqZ75O3c5&Q$gTtzEc}AFd;87kLv?uss5?TWRKcE01PC`31s3HUOG5a6rqOwWVlLOD(5Z(Y$-ebZmOEwAx<`$<%;o*r+T>R9%7 zzuTLqGU`3+uDBmn`O->!n+Y;iCWaPO;=?#dM)k6)+}84<2l4GaX6?|fb42chah^&y z_V27;x{}xv5UY8|`K<~^u0#9{azETCQl|KuSldT?EYH`Gm{WFkD#9 z)NK`DpA{J9=Va1zIG~lv4|&sb%va@GLw@N({Q-peEy5T5H{Wd!Fk=1TnZj*2Y=fLW z)iqWc$D5k5GVjfFrH4lNp4WVU*op~#ifQlP6z6z zf?5nfv|J~sI?FtRI{3ZXY|FdY9x=bo592Y|8Z~R{6}s4#7!2K5&%I1+dBT;#zxZ!Y!duPV-LkNyfydbIf> z@!=PsRd-7J$k$xx*Jb3B|58-yEwFK_e($#g!CTYs5|5@IM!Y^AHi1Gb{SIHG=;IUS z<6X#3bcw3p1Q4)~SSM|WbM)JZM);$($L87gcvyLoU|%;1oA-k#xe=tkvwj1sq(Kyd zROCcUfkFHLa3gaA1eyi#a>->dh#pZ2Di?E!_a~cwgd%QNgba9vNPsnQ^`Vb|E ze?~x0ZID&==h%8fuBLy1PG@na8)%-@ipd z%z@v=m={EE!FL0r&cnVGnlW0&r;OvR1a#Lyd|anJj~xyNcT^3{o;%L5NG#(wTSm1P0Z-(=FA{nTqNLkIv@#@Wx7ZP^o_vx*Yf zcOd$$W|j&ANq5bgQk8O!)yHS%)X)Yey8R z?VZzFP_MpJV^dZYEL!Q)h}(dt7QZJWpWKc?b$wUH8b4klwm`{Pqwg2IW7B%D;8+sY zf_Ma!5S@$D$Hsn3_~M<22f687LA=zQ$XZq^R}CZaS?RdQS4BIMQN4^Pb23zo)&on@ z4v(HKv>kdoK;9%v)SYGNobGYWYw0_M6KoYU)&z?l+Si`fX{}Y_p?#ef^R==O+Sfh8 zt58n2_cr-&_Ar8l8al^4kAT4?&DmX1=M0HiI|jg9-H546W3FWHmdL(0{!I2C z5s8M;YChv9;jGS;eQS-O^>!ujaIir~e4lhXWT|{KFj*?{h1vBRjO{1MQrSM9$x`_@ z@kFccM0$U>`i;lb%+vF`{X(=FtMP!tlJ0m7RSr0b=4&6bi$7p}f)NyzmjZxCq)vh* z=PY*Ls}ltGW@?q8?#WPdFblBJuEJX?c|F3b{0!kfUUXCt@3Esu*}jpySR5GY>_v*` z1-)m}{z|`K%a_0iV;+>M>ddB$0>Hmz_dgwsXcy{mmA%1b9Egdg(aRn8Mq{kG7pYI( zLCm(FL|n9T2SJGkRGt zdADT|t~I4N6YfXi&D{YVo>GXGDmdeGcCrK9D~0>K@r&qHL3K@uL>^$Djx60v)$Mp& z&4ZEg_bSvqs(C6rmPeIMnHGU;lLC4xvr5U#qy5$|$Q6*Pj`$x)7jDBGfgn)A5HkCu zprhw?jen4A_^n^5OruK0*1LnP#b~o#pZLh{?>Op=O$V%DS`pAVazf4tv?O&!HNmIe zx8vOg?g-9uc!}TowdG=%Rte(0?7KJLb2%Yi(k$wwj@qi^-A~$2&{lfGzGS#fD{X;}_8WjB!k+D)gN_lhMK4kr$lz05&0Mdd|#G?)>eLd9^wk@OB9lnT=$$X<1 zY6=HOVEfw{)tNn@>MpbeV3t9?fd9q(*OrfejU>vomE*UWxnev*=6AWa$mG_eDb_{r zkd8Ti7l1UERu-3B)}CX{XH(p%hiFrJTI=D|{7q{9HZ^}Ib1Q_009f!8&Vr|45%CsG z)-=zo!~7Rzh`v0)DR9}0=quPO#v&;Rt;>JTk*K-KJcu3t+|sUdB4*R_oH;Ryygq2F zuKoSV$4EwdhEvEY=Ky)*>4G7Hw?H#ptT2QAw(K(y(qj*=v54ENz9uQD@0KF7OsC_JYMce}!w%8`|6JmR&UK>4b8L#haBo^*-+? zzj9_JZZg-6u)X*btIl%oO3z!hmrq-tO5$}L9RG&7p|J~=hq2Tbr4~O9alVwIkeRzQ z;koB#(VeoBj@D0|6#GhV%eORASU+jF|01)a{uXGdE<|_~5d-!-)kP4kqCYghM(70y z0Y|2paO6DZd@ry(TY|_|<@|mwD0&VqrsQ3$9LS2PqE;xJ>FNo1D=-UK3k$Qji=&rR zs?D#H)RZb4{^FC!LbE~THplo(sg?AyzOKbRNPaITUFwgi`KQ$Uv&^@*kGT{~hmtQH zNN1q>$`i8`QVeMjhI$vqZ!vPw?;O^%+E}lU z=Bo`SWU;psw?paXz~JN-Y=+SUVD#)%}W{1TMO~k1oTdyHv8ltdNpWuo*%{uHeQ!h zo9|ktRRCtJ_@|68Jxse4p9~34Y4SX!$-5^DoXek2yk2~B_`3Vzdw42gXT?4*B6dAR ztW30(H{~t9%+xesf4O(ar<`47zJ_p=I!gwUD$$kcz}YgvW^ZK*0Z?;bSe-lY`2CbB zw6b+ipC&1WE^k)09v+DqQY&9EEnaVF$C!@dSZcalsv}{1Uy$BYw9<7?my31Yub7vZ zu-(1GBCmF6R<<*}o!^+*kM%ZQ=IkolZzx-6?Rl^Iohjpr4?&VtdAc-Wt;;lPS?x|6 zb3a;8jZyGpML}Z7G=`1_%hl$g#DqatI(IK8Bc=FZ!luvb$lv04(%Q7pZp!|=!(5Y!EI2i*pSOAoKallwd8w?|Vbx^!S$PG~=j3$jUxR#{$vhR92J>=lUKrm_O^QOl9;gxbzP0gC zr(8awruWqaZ^+bP#a%E{c^>~2nAc4s9Sf(62#|IN47ZG^w;Q)&`%IH zKgwW1PK5fQU<>Mp8SFr{5}iyediU&@aqlF2*54jh7NU5}`hQDj|G&$eJwKK=ONIFY z^^X+l37M0A^mMgd&`h)-UBvB7A^_kmd=1Yx2#?>RYa3f5uOuzeYc61XIZ~(MZG@)o zG2G0t?}tvCrQ+gu%mN%d7r+s8od72}fUBMo!D`~(L z1UNq{&Ybvfn2mqKYHbShOgxXO1 z0plGrCVSD_F9)WiJ{oQ2Tm)H3_Kds=?8nJk{b-~$V2;`?X=AZJz7m$5aSnr>{7N2l zn5H(&Au?`JmQ4PWUT2>|^I9UupVS9R3;Hekl&~E<{u64h`DyG^0%q`w#^4y$ety84 z#5bxhH~)(aCo}5BuJa;^ChMLY#ho*rL*klMl?xyLXfK|}Zs&QL+;3^ej60B=si2NN ze?LS`ZhM4%97ttNlBRPm@$#K;+wkbiEsDRXva0P;zUOb# zli%@9HEj@GEW_(RmTz^KI$Z>NM>1aYfzED|yn@ic&w+Oknbvp?+<1O+g4dE@ zHp<_kTCt88MsJ>5D_UzcPyW7(b1jX1>q7CDDSl=D`|wPQe7*8-gTn!Q6@d6VD*U>) z14T;ztqNe^--6lWV&VD>uFgRvy(dLG@v#gQ@(dkA*WL%nuayBT=&*-#I~ zSZX^uKt(q@V2&-UV?PWqL~zHD5(jb$d4e{y(m)Do zmH|HwL z>74s*ihxWs>x_4hhp>|Z`rpp7^%Q|-+0LP(jl7$6)2dLVqN#}qy536TJf?#0czG)? zV>uk)W3`o&w93V~=(RM7lZVthK0@F!SmIW4^#+GuHrpSJcd?_2I~J@ROz7`XS9tP- zt~uua>U@4WUB>9I)3Bh~fR;(;bA|l>Za!z^|NHs;RJB|Ob+Y66y<;kP@>H)oU!8^N zmv$jrkfSTw!*_g&WX9QVc8;khHF!rVvtv4E`ZZ>8k8e*;eRjJNh`vI74z1DAxr}N< zht77sHxd^`I`Z9~{1Ub0f_6-Cr7K1U)%Cu1aXU+<(d70F3z_tKY%SE#j=x3MsqD`# zdd^yCgREr$Hv}tr*|97y!YbJS~!iFu7w?BiYfp4-zrT)ZDY2f_S>`%?1)LfjJOHy;^)LbfajX$vr zGkPmW!AfyO8n{bp?wXprrDiQP>oVQ?D>+|%8iNs%70SsdAqNGWeDZ zt&#cWJB17ZpL#Qu`IaYP*AzlRj zbF$fzk*ER4pz5CjsPHPl5@qT?z{afzdR@xN?gY%sMI7{&dE6A?n%)P!FPO+vs5bWm zCfX|loa3=lD5D$Hu7`kir2QUkz&qr4yP~6SF7UocU!AYKj#yrU1lCFQHF}IJ_JoRXm?B*EKSuaH5iGIVUKZ`?inf&z{O{9wRMC`K>UnoXc@HV|J}HjG z8&9sW>|d50 z9XNvduIyK0PZMd7NHJ_#Mb3ngGKuyXLam}+!8IzZ;r+QnKK1z`@omfmcE;0hW9C{s zS$_hSBGjAkipSmni3U55ez^dc2!>yjs>UsXyK9HBR!v}Itx}PSTq$G3ds9-WwE7@H z+#(P04C!jD@p7iBdYKjC8eGVh!~a9r8ux+bd|5u_UOJ$6FWqs35e&$%7NqC8z232> zyXjG9Q@T%D*v^w5eU!ALN0^B83h5)@>#pqz=8s}S&qchEka#tc_mR<!}ki_3hrP* zXX9IW9_+vyrFgsNbrqtIlfZEGd2mqo4C&ijtOq3|?egxio!0lBoK~jaOKI)3uS@G_ z&S5@DMp68uT2Y=ykIqSs%{=s7C?TcO1+P)g_GuO6$zTQJ;&R%TGf-uwt3E$Hfzh?= zoxf0D)A}Gy;N`VL;5~iHj*Ei86uZ^8&^~sF8ILcV!U@zRJzDe3D*;`niEh zKKhpGVJ0jH3LRhN{Bj-sM(Eut$Lv{aiRQcM5x*s~vGe~l6{dX=S(Yc;LnP)xR|i8K zb#RXr$xq<=rmR5%=egAZoa31J+7);>P$DDBS#Gk4_oYn2e6t*V%E>-jx*tbT3fULmIu1Uc@Y*eRmRaRnid!j1zRt6R$mSBeTDc- zW#oSr{pN=?1%Cra^S_86--vB9>KGA-+m}a_U8U4q4f5{czT&0=|IN<>ANG~vFM$_# zE~xU2zfZLI%V@g|n|D#mJpzv(!4qA|@lBQm8Z7qPs9h z?sbVD;vRN~x#;`AvS|KX2QOi~iyq>Pb1ilfeYe4Ta-$CY0C)##V>Ix-4!&jTcT8SI zOfs6_80e`qUv8XAh~g`oFd?vp(q)~j}{L?vKR^h$S&Q4v?J=Yrnptt590$w|+W z9_uPJDg)Rz=+Cjap_Y4u*jQJ3t3WJB>-a40&WtBGh|k6v#IN8RiOiD-J2W0rW%WtAi$Y=1 z>ZW1fjrebpsjPkxr-bsa=we9Bd~)RDqjMReN;SS8M^9~ip~yASVn=)p!E!*O4$?%6 zWXS^N zbxS0AitfsqlJ}~tDZ3IEeSDL{@*jZI{g|MQT3q)%;ARQNPZ3bG_#3V#z>hxN_E3NL zMB9a~rD7yfdHp2@_asUa`Y0nd^R;KO7Kqqf7)s-XSVYso`zo4oK_UJF-1j4B*LZSR zG5$Sab(D}Uq@ynx%U7ws66lOZ{V>Hs4_fF5;EaY%3D*t7nqK>)nr4;=1lUzW7~e*Q zviq2-_u$_gjYh+3H->^(ZFXgqDI!GMYMXJkl4-p$lmkVjaydG39d*4Mbsc?A4dF+> zqrY!k4&TEhPq91qstXt(&D#M&XP>6DE9u}7O1R41Qs-6fS$7+iT8w{yy|)nm5Tg|T zh%f8&>2#PoW#w&sTmjEOv@f&H!Xi)Je=Pq(Z7-g!-z6*3c$d9kb#HCAf>h*|yfAz%D5+oqI`9nB?VtXCW4<5cd&fcuFDB`&Edm z_#hX#6r&nSN+r;xRE{6yQ#7O-cDE(3gT*HP8G&K^bH3@Cf3kP>cd|AAAn*PaU1ci6 z=ydIOhE>160J`kI;!SvO(`WLRc-UD0dXvgCA$o+$P1GroHHAbUAXic+#O7mZAx5c^ zSh?cgViuzh64v}3*7y-VsVv!_bh6=u@uP&$#%}NMG;j2U*?R1ouC)>6$@XAOJ&ys~ z%?R&`evhs72R=$H+tvILH;>xV-lsX&(W$$GBcs)M{bg(7Kg|r188dUqzs$@hFuW7a z+TUfC!Gu?1cucr>5!X9fEal4RRF?*#rIg0uWFaY8R6pr4Ge~;PDE{n3+pfo0(6>%p?t-6HrHkNzKd&7f<@el!jb$)2O*L z{-nCv$D;Vj1~Y?Xy_vb>X=dh=ea$3|b!Hh%_BM0E#S=HZ(vU0qOJ`lxJJLA7qWH-{ zW(LWDX6BNE&CDl599 z%^EBd=BDlMXw%rBHZ_!`LTQ54H5nh6Axb-)_3v;c%%gA#->!{#Ez!ETP=c9iR zuxd{?4=zA0xV)n$@I<2hWFCxS297Uaeq@LrHV44CUs#`T5hOvra^e;Ppc z!XDnJ=08{3ced>jAS`TE%qR_qT_!it?r3}qO`$3sBDdsp=CC(bI`Kc)5KYiZOV z?jhJw{p#gIxZ?ZMt`6_6+_q7M!F*Y|L9XUel)?6Gc6U4sra2>{r^*I#p+-htEt{(y z3WXM89c~rmk#7}cK+~if#NE7g|;^e&)&Aa~J+GCRb}RZg;O zVd_E2tZxg`u&qqJt+I-cqj{~*u1HIeE7{mR-{l{5=Ebm-4qZR8CF}+U7^m9oG_3%I zg?YDqPYaNz`P22X*L(4~t_*iJW5yDat&e1yLbCNUW#p5iWH7TGEz?h)g)tMJqfw_r z;L$squW+$8DLj{KmXS|*%VM#3JyGJQZ>{9lCj{ zz$9qXR2{;15Nsnw~UoM~o| zyv)p8a+aC-#GHH#KE1IuH$kN!WBaNm-@sllP2FbZ*A_dmW zeDX>&N#j*!8BE5_oN)1?Yh4<0&8Be}<=NY%fx5kNGGS5tBr!8cCe6$x=bJg0w9K4v zV9_TXO1Y$7kG`XP3+Fx#=YVj&(c<{Yg=PlHo6O857nwPjyur)~2Nr$G;glKPt3ggC4-eT}U@>a~wGwkcNvbE%kBE2e6VLpv!J@wS6pRprJDP>7%*LXY%yz5iE zZ%gsMeLK9@8D9B$2Jd<`Kuq;k-V{mcq@E3+mwF}O?%X{vNmwTdzBLSXJ6|vx*EcR( zgF$>MD;k{W0^sDy@}n)JwTtG94X#}tVe}^NwDS7NyV7$1hna{+G&7%EYUW__4l^el zc=T!4K5|8mfo60gavCOcBq)+>y(TB#Ts<%Jd~I~q9}Xs6j<3kKj_}=M`KZdBFGujY z&2&EQ>d~LjLH@ABo0J>=$f$Jd*^AYkF-I@yyjGi1ns_`!-8GjIJSDDU@4U);f*4?Wr+!Lq=l9k0abLF%3#jbiKNF-x=;NiN96HQbF#bRE^ju0HiA7j^v6bQ45- zDr-FcP?*_oz}{>S9FOrC0p}{=_&@|VO|9E>|A}yh_=;8&u%HOJx<9lr2Rvv4(s8Dy z{51qM->G?Et$^~;o{+2*Eup${a}(Zf)_gRv(zJ} zhXt~7jedJ6Fde0n)G4x*=FvsL(H)HmxXa($=%d@j11U0QuX zkwdf3(IP$2rSZN%ju2x%Or09zLNFwNvuhC2DB^1i7WAyT-0D*%o(N9jBVzi6{!RYIPLCBTw)~C~{mxD-) zIo#In_t^aAC+{^gNG>-M(WhqSllPg)x(d4!gcB?d?>Ea}a+#SE4ncH1g=P_#%Pp{^ zqxnzi9o&%~2b!SqlaHGjBp)_2moO^v&nF)-lk}i?TzVff%U}X?3LX;!kP&4^{iPv+KdY z)>-Fr?JnxiJY$}Em~62_i0xDWABv4rUE6&XW9~TIVYrqs8sX`LHtv?r#lY_P_cDH3 z%~A0ynVI6{43?m!^*6o>&j|ei_A+IZn^3m9Eiv%8@QztfN~X%fjx@_MB0R>lHXP?i z9|QxJ$qk$^)2xy&hp=WU{UOT9`*F%C2o2>E7n4dDEz!c}?iBtfm^0GI@kvDWV>(ON z98h$0yBk*LI&Si0!VR%`Oj#BePqGuW7s01;dqhrGJ7-HKn@Sp;$1syy#a4uRuW-u1 zDZ*O8VeTmt!E|DKl79PBM!HfZq|h0!BxN^1RIx@2K@+V|22b^)Wtga^Ta@0F zGbphmrB{(IfnzmqVKX7-pb-chZ`N><>Xw{N%4@2FahyqaB_pEeqwWS!Q%Q!(aazznaPp3 znS)7a=7a-_{_Jqd)t-}G-+NXE&UqHcPx{RalKE!l5@a-x|9rC0%)zA3%n1h`{l(#y zs{^;{V3WiB?jrTdIhWPJA~S=^QdSZU6R?5>ojCb>u~ZF>DEmNqB0*ErgAzX)qNq(-WX zS4R~{SOKc>Q@2mcd+Rwnd3GmG7_8bjbMbdL#^FFzs!Zc8tZyS}G7IzTZlH#sNZoxV z)OnTUq77uF-iND#YyGn4*J} zub`qJTgctT>4tr|h6}co*#GI_Red!~h}7pk052?a?z@VnTUg@6rxfjhH5Y#ss@~$4 zqSbgbe#!1w`z`G_Je@hhlZQ4AD2a;Gl|0^eJlxQx>@-*Hp2pX{dt0AC?hiTRDEJ(?HzF^}xq%p$&xXt=eubRmtIPOgj-`Fwau83F z>-c;=D8mZlDJeELf^y_iBx(vN@N#{7y z$<@zFSx3}I!0_B$3`e_T0PC(jjaP?of3ZmVX|JJ^>YBVUFJIIXD@b{xxEGX`jP=2O zr2f&+&G~dCT}!{xdA~_d&82&&rQTufyUoCO5RWH6&BlSsMv!b?3Q^M9pY;`<+c7+w zyRCp;xC(*cI$#{Z(R%$(PzCB60lQAmJHguEAfjwQl!n*b9T?6&gd>iy_tXw9#w)Ri zH+2PO#KI0+toFL2IMG5Vm8vs?&nlqjHXqmUL-2rYK9ycv=i@Gy8`pOVmk1}HO>XT{ z_!ulR;cDf#0rc>cLZT0l>*#~Zx<8@(p{n?5T%32vr8aSWb7$}9m(BKtmH3~iGR6H! z2s!s$$gAP_V6wcdG**~An3(7yI0S=BZQkHZkaBa3L=%-b6%-ci(c@hK9{rXbR2^Ef zY~9Wk{g%yZF4+xoQD_WTya=bW^|fvD+P3*^TR*nyX%2Eh+m}w9#vW+f2HUnu+g5Gc zhOoIjs0@&*PP7@~AVjJ{=^iHUJKD}eRjOR_bQ$?%qYP++!_CYm&oDDgj=-cs#e-(& z;kI|^V}h>3!aFm#jqU;!Jur}KLg$2|NKap|y{PK(0}!+&u~rcjZY_ErHv?Chxauaf zn2mWSPxmCXP4sRui{9}gEnPplTs&HwBBF3Jf&xKe9f~&@p|1ceVrmEtNr#N4c^=hN z*-RJEzE_d~P6qD+e`atIEL4-v1aEH%X3J9iW;m^)ZG7rTc$b44u!}KJM0^QGPwh}Y zvXb`r-C0>{OMI!Wj$XB#8p!$OTDORYR3r^LADV9=X7Bk*r4&6*wny+B2-4cooBC8v z6!{8VS(&{%%j`FhNI8B4Pf2FQ!vivr6;)hqIthGnzv@nOAZ&*k@64BKQmv|-ceLN~pbG2b}08gfICmwS5M!qqyqmae-ZJi2|T8nVeO{h{5K>VEbm3Wc-|KNCO!D zcK}MCHu2y$OWU}?*6l1Bap<|mA+7mYDu7v#n4XvIu_j+!wtjV`xa@S&}gKm<`DeE#D{K}dlnhAV&wCJ2WWzPLgje)cp>}18Qm<|I6G?W4D z5XF)#^zXju8}TWO{w4K77oY>FyEZhAEI=e+e8RrFj>x{=zUFh;+~_%?W&c7~Lm#Dd zDO60)LdBFXoK2DP{<7t(=ljc6tdS<(EH70y-bc}f?ZH0Qd<`;crc%Gw(F&WL0L*z_ zy1hiUar6$VEr|7vD@$0+Dr}*HEeJzGkC@thjRT3R3d|-H`mpbbOH#ieXV+5oz|PA9 zd!LPaf(+|aO$ikQnel8)udiNa-klsrUucwdAs(&X#9ESgkLmo@tTOywSl zWnWF#a~Vvn3xwYJio{E;A``V_jr`OEH%?u z^K#iYbvCD@Gm?9IymgEVXdNq)8<1yXnmE6<rtJr@+2z5lSrBz`m&n z+sf#v!IlYn6*?V)t7VBktUOgXM=>~u!J(e144}8dsx*4GD(+{j?4uVs!0~Qmoy>vL zGgMRXpt-Qi7JJFh(R_{cC?4EgA5>O#kKeeQQySjam$&BRytVD5#LsaRaU90zR)g*c z9(2J$V!_m|pjFG}MqXqPU8l0F$!wZ;-axy35?|hZ@Lf9}r{w4$YK5;|c~BwBo>hn} z4oL-)BaJ9X>oe|raCiD}+2&4Rq|chr&+!NQs1C!Ld9~}p_x2#pLR%M0G;=JmM}ep@>|Et$8D{;;u9H74J2L9dRF4i_@xmYT>LpAr-Dj5L0J!myW{KI zf#cBtQa8HBe@lNiz1Y#`3A3sJp_1TcMhSi~MIRdGlon}`=TnRp`7)Kzyn(1`HsUW} z@2;(2^nVdsPskh!FMb*0%NWhC@QJ@FkFMyyFdBC{Ce{Pnk66RWlSti2+Y_qX!{Ygz2P5A!HiE1?^^v0TB2iKI)w&&_& zXj+N>;Nnw;c>kn3;hO@KfR#2N5^XQhuAUZrF8=XtK#Pvn9=?HTeb0i_hTkL9wV{Av z=hxfp_;!4qwR)oBY9FDxe6H1{K$>udt1c~xJFvUD`~fzr%O7H)E`Nm4ypvD-V|jE% zcVT38d1OajK9AI`E>FcW6W*#M?gn;vN+I!2ugLbqhAwTU!OW2!ZF->m~XlD8@}v`1T-_a znVJe?Q{vOh#`8(tB=G_-lLS8kMc=WI87f)-1fe3m3f=a=jjW@ z65srn$opxkv)Rg8uRYsS)t9Ry-!dH(;un(b!lLG5$}Epbl#Gdh?A)PFpEQyWTG}H8 zMr3bCuRC(x)E`xPr}uzKs}q>*@hj+2bAh_0`1%fN>7ME+f+M?FtE45oZ?n3dev!A= zbG`b7tQBT|lQ*pLie~)Or`%m}MxY&merR&$x74AcAAqynoexGKwlY1mXpwjxE#P>h zJ&H*D7H(FjW#;1O=|}<6NWN#FZU-5bLO7!Pgnw}+s&9tr@PQt95lIK2w~urM{yu}la4bu z>Eo^Ie6OZsNX@;f4>~}<4Cv#<=p%JoCBgG04shXa@K*(*1q{;#6Jg z`B+)mh12)G51unLK3alcI-bJl4xb+2um1Ej{@=ns$Et&gAt^+E;0#OL7r)mCya4#x zuKt8fg_L{!QZk8yckzPf2~HZ(f&3AW#_bM%X7D(sB{uMQZijKW1EW2zb~uNg8s}}D zI86zqa?zon)0`@^&N`ppF0<3msY;pE&uIlU{hSZeF4E7bYDx65Ve*)IL^i}&CSOB9 z47b@F&)3TH1-TAS2IK4SM0+vcXbXpeZ6pjbqSLzcaB#PeV< zF*JO+$4>r2$Lj#&oTCv+US*k^BaUMLTmu}0e&6npyC(M1db4~T-{JYBL;h&{58;Qx zn5j0TOS+TYq6L)>n*~!C>RLbYe^`4D0J*BN|9|%0nLA}?XLq*DmXryBT`s$`fh3d= zdY6a@p(P*&=>*7y9b#daWkChSfbVNTrKus#s7#K)NCVM(n-o`(g|K&-XcZ z%5K7|zu)h_$=vgt{+#DLr$6U8f_aloW^^l`NhEoMzaQPkcd%=77<+yM>uhlfKl~_e z(Z~2yUhn!hyURU4aoA}NckM^70=F}S+y6p?$xgJjvS6N9LXep^IfOvOlsI>p90%u; zs7a&U_HE@e_QLt7z%Q5v=RP#WL}IngxJBm8P2xf3!MaGQ+GXyp$&jDs2x_e%jdDfDguw;%!(v8 z`7CqKkGkPL7=2n_1{rr>HJd=6f|biltWNCkN;ltx!4){VlMh9)e&ayQ zvs4ya5SY~1XYsC#)4%-}fEL9!VNT{_Z5V&&NJ+;x@5V9whb%$(dEl5f?;^dko3z^b)ArI4=t$=K&mN65)eugU~IXVfh3U%d-BpW*rfh`11$ z=u5a|qA&B+L9!_KI*j2v{kmH@EX{N#My3@S?TY_)!t?nzg8TkaI@IH*_em*YMY38Ku z5t!rVst?L-Mm{W$Ig?t{x`5AIlpLo$3j8o&UA5>{9}y@r##3FZPxXoGDF@Z}sQjN{2u}6v!QkO4m zBjf7WH;$~pOpMKy_t!W~)w?2W(+I$UlTR}_8D#*|+*JGc=Nca-BhE*eC(dtsMK6nT z40a;jvw52n{Wk1bJ#uWA=vIx6$3>uWF9wg?cU#Uh~66 z0O5r$&OyTE)F)Zum_?keN`#Ga;~pKKK5OP8ht`V4^X=C zKf1TLY-;G-{Ybv5pO)MKNDw^0r+G1@4r%Va4W*evyy zk`i(|UfLzp-d+6~*DT(w#xm~J{sVJ}+1+Aqs4kcZ`=9}FgBGoxC6DveF5ID3*AlJF zqLXYk6CI2($+k-ntp?Im?jLjIvT+_wVCd+O|>VJ0D98!l|@QL%~C|rp~ zFH@$uA}2uUVy2k8xyZHfz6@Y?*<+jzoPjsw@S-Io4>>5GAni;t?|nD)=3%FZ2QA%_ zHTtoR@iYz}0Bz2`Q_R4Mel$j`R1wj=Jq4z{&8Jb zh{uGk1h;>3SmEW4#A3`1N`E67Mf3(J$L3dzl9AnoSIY>m67Eihp(9Ztd}MXSYm2s> z92iDDbjE2QyW(y)%M)P+`{d7bpWIJK2g8Kvk1o;5w6BBmZ;4UE+cDHRnqF7Q@}$Gv zhIdY2bAptBrrC=^zx#yHZ zASccuPN{#rlYYC9uHS>HZ6nzS*Xb?j*fO+E47<|#lozclFKYRXtkbK~alnP^7PbZK zSy%4CI*u?o6{VVGWU)*}s%J8;@?Pc(8+2{=tI=UT5S!nO%?D*J_M(R{*9&+UU;}G~ z7fvnq)53Q8D|w1JGJUrh;dhnT$n;m8<4>LOq>KYSgc;4-tG)*5T~MiBEK?rSk1L2* z{j40;%i%tA7+fAqf7f~4-t@Y^>GhQJ`b5*~fu`5f&g;&m*EgG9&p5BoG`${ddVSA% zeX;5FP}6I(^ZJs!HVDIqo!5F${J!)1TGQ{5mfy3^@9WJZA9a32`+@Vizv=Z@)9Z)M z>j8P~>v8OBq?|TNUhAC~<`HfJhi_Rh+Str~r1vAUomc&qV%_A;4zxWDguman0?rNh zZHwL>?#B*`N0i=XUS_0A8-Cm5m^a-;_TkIu{lM%A3p9N)wuaMBT)fK_k36-`T!?vu z*6TWeIGDa72+yRiC;oR_;5WFy3foOsBs0;g{ok+?iaEkRiLIfRCl$iY1E(-HpI!DYdQr+3SC zf`97VuNC|=2fst`&)dTP!oe2)mkwqa>ewu<|K=|w+(cz)e0Y3heBSu{@de`x$IIFA za&ElbIbP0>m%GNxh4FItc)2)U?j0}pAcr7)FC(7*yrH#+u!1l=#p%LPoG$$2-p@~5 zuUc8aZxKKGio_25cI2mXFttyeV@xdFcFsNH<$>`sTS#Ch9Qq8I?Z(UfHe_3yT-o8; zs~3HpO3Veu9%&L4QdxeiXcF7;Q$~C8JA~iS{7&X~4!@23RH&=@Y4Ljtzx()og5O>I zRy@F`pC;}`vG9?8H9Q;1!iOEK(JXw_!5Y!R#~iFtEqvU;8rZ^bIrtI5-*)h$f}i-` z!#}1l-*sW`6a0{apAh^V2Y*}elMa4d@KX-{7Vsw6zXP1_1;!Ae+PH8DRawsNW>XNJ zB9(9WSB12`^Hxf){;)w`s$EnStBP`?v8j$tc2QWS>_NG(mTLvnFF$#x#l2Ye6CEu} zTNrmEQO`l5mxDy1(t7h&A;mZev#FTzC=t7;ux?B^olzj3%Xx|8h%pCmH5)anf9EH( z^=pJ}z!OHM`@LaD26;EUUdVJ&8kGGf=#Gzgj=Gz$+Jk2f5#1b&3;Lj8wa^d&~)%9FBR`IXUPlf&fu6jfcO+oI^)7 z@m_xFe$>&bYBiXh!tY{!SMt*qn||_FOFWd{`TSOBg!8>fY#g1T3d5q=VRU9}(G)Sd znGR1r;*IDI9(R&OO)EMewumjFv*I{n9D9XJ!PL^C%b0-6B7TX^j)RG-qH|)48eX(s z7Dtt~7NL6|JAo%OfbV;d1kFudjkFL7o0x?}InHJfylyq4bCt>}FMN(9b+5C3+`Zzm z-uFxp$8N1!cn<0a19eedDKF2wkZ&OmD%uZw0d%5oecJ#yw9#HNF&aEwnzZ=})tq-ltH1-rDIeI2DtFYaW$^c6z_HNNkt5IC-MajXguQrVtyV zlxjCpD&=tbZvJTW9o9Ds*RL^;Mp#Fh7#SBmb`mnYQc5=55KJ$7uUDN%J#>}&f)#f_ z8CJRd~4@E-cO zhKt3DJ)A*NHQ9cSlhyUe!5&Zam@>&TrO;d z^P8RIfq9KG5o|Ahzx)f0-e0oD;x`OCZJo-9&JHr_PIaIjh!pj8ad-LJt08_W_*tl$wE#^D5T{bb&@cTm3 zFI~*%z{n0iT*cdqu*vlHJ(SutzAj$aQm{QzQPKo5eX0~ynRD^ znzQN9p0kB5_nx?6O<%WH?6wke9ie>$h|Ag618_41?kfUlWSUGBi^J4^J5mf6%G}Z^ zW{W)=pnzju*KCRf2vaC>4e6S5_B)0i12s~q>Mjx@cW({z=_1iJC^^@ z!GCN@6L76c=QQ`rNY%OB!tP(P{!KGeb+mnA59$w@nXW&Ksg1jaDRuGo#p&Y$Ke zw$YfpaM$wG?ldkJf8qMIn{0#P!?d6{dUkR!t_?!3-Qb4g6+Z`~>W(xqv`f?<2i4JR z{V@y;z(KeZ9`#4CHZ6~0*+#F1zoAn9mJ4i^TK{&t<%!s0Q;hGlTb?vaF;!E>)}HI% z1!A+kCX?r@%)I8D=rxdNY@6BFgk|j+K9fC!H`~+L%Ecw7iuPh+I@-AQu;1r+k3&zs z+B{vm8XKvP>I4NQTuoJxw(fX&fdRxOPfBiLsT&>YvQ&>izimF6OaN1S4-YZNW|_i)dIE`}^Kgh*dLY)w)sX&9E@-cUHsK6Tlk+*-ZyHYR4v69a&I)VXg=VZ3D zGl?*tO;?tr(`_*prsEhq@SqszX>(Chbk~aGbFyOPFl-IG?aaCpYyH8cp>GGPwAQJd;g~(y|@AaMFNz&Seojbz*0<$ja3$ ztdLErTSPJ;W&z<|%1=ie#wUw0sVC+lipKF?xGOEvrP#2A?DPfWS2#z`FqHrD9v1_v zBCy3HqPJtJS7X-OEHm z{RMO`HGMgJJ!V})Y~MLW_bj4M+n&CghrJ(F9a;#sm~t1lhd6_y(1>RmbJHm$H#s;q zodnntoJl6t6Yvd-+Z4ALfQlj3O z&<5rhMG2BuR}?rzF{qbc%3y5!m6@sfugyfQkeTWF@6629e`990{(CcX^*@-|S^uM% z`TC#C?5h9S%tHMyW_H*A+svN&|Cm{nSsb>i;zN;rbRcN9xbZL~c##g)fB~b+&PdF|XcX=KQ*6=7PG9sdIz{iM7EAd{ZJ~gE9I+E|I>e_@m^hq`*hiCh?m9FkA2p&9%v zfGH$7v_7{p2 zP@TPN3w)aVke>|?S9PC5#LkI{bhI8I@6&;v3s5_s>&MFnu$?E{1=zZ>!LlUlo`xQg z2ixyHi;OWH3yD1radbSsRmoO?GwMCm8wBD#%yevKVlx|?Ihm4s@oc-Er0IIQ{h=kD zQ}5lQ(YvK^8OG()O&7nkH0cj7?VQrHj_!gHBaSkoKT%%vC(6o0tC6x$zhYTl<#FoX zKf(1oT}EcL3e3GYV47W(SGw()_v10W@C5rF$2Z(pH_PnyM6^)Tp#_}V*P$^dWor$xoCc`m7D=-_P+?6qxXQj`X_y`3HClMQ2B=KD`r4MT~ zs3+^4luiUTb7bna{n`Cn9go56Hl9J8dR}2{?aX{BajAIldN>CW(i<>3Cr(aBHv(u# z6~2SZj{sT=R5?g1QbXcQtQ)^hfw{#yDOW2()76wB44`)x1rXsH!dA0;f%;7(8(*Nm zel8Qaw%C<8=ar6!?)0M5i0DUuU8zmh1x!^>#qL~}n^2AH&VRfa`fvXtwES)3^(-Pw zu0flyXUDMG<%^)n3^d_UfM^5m_LhO6k~CB<`UCaJQSd^)rlAE1;pp8It5Qg%!<%WN zm;H(MfEwH_0|K19i1wBdjV)H+Lr8UdeSwr9yw}Kav%YjvX*N3E2fXY@)~4p|(v?`n zp6%trrKUPVFF_)DKOyY02ihEZb%9>!u*$p;ROQ~^)!&!w?@RUf1#Frj@6+Fx<<^P% zMC(C1{hCIsVrOqx#9?x7&#S<#*j0OwhTfM4co+bKV|cU%pf2<^B#ix0?3E(`cx7Au zkIUaj%JpLBFXui6qVNMG%8r-|(bwJE9ez+QnduKZS8#Rck^K)q1O=CU`B4yB?LA>GAlyF$|6*Z;lGGl%KT z7kg@4ZcLWKI-BNLp2yNR&^r*K;vzRW7`tF_Qq-a$uji;1qK#nG*IVqZ>_vzzL=7K9 zlD4np6?=;%Q4|d)Rl@X^LSEyAlriCYBklzSec2UBkVr*8B}io~xo82lXaLEk$;0T~ zQqxCwgUn#>V0Z%atMJu?>K{)Cbkl?+yW z-_ub~TMg{cH&h(jcp`#xlLG*#@K;p~{XbMiu^6JAIv4({y4cM5n%cj_)Pfq~8R!yz znr~4G`PkM$(|Ng`yAnlH2{p=IA>!8$S8-GN^C zJFrXgFIBsq@EA8>M4!Y}hal>Z;|!NQk_?VcrH?k;{6rPpUZ=k4Qv}UT&!m_$mN`rl zN<4R;2|tayW+AVG+b27aOYx(5yR+&)g8S>i-H$$yXCV=6 zd=|04&h(x-cu7Y~CRi7yyV!%WjWQ zG0{&Q?!=m5q3lO9M2MeXGdgr-H;QC7lyje4WS~A9bfNqk|4s^4*A4Gfv_2-Awm~v& zWjnFFrF!*Vwx}M~D%h{j)6#?dHMf61=9S_>^rbTwj^`nl%$|oRr@^(&`%%LG1mT|< z>Y6AGcTMy%)zExp(<_=3jb|$=f|D)HE-w|6rgJ7bOERuZn|T_?Y0C*;OJwHO*=PnV z+%#q7YuKZmJyU7SQ{MDWH&0PL><%7p5FZ-VnH*%PNZxJGMFjV(1Bx@cm!vcEme_en zCwD0=7anq&xZmy5=s^9As!PK(7tCLhmP(wyiN)SUle&w)JtDT~-|tJ0d#(hhQvzNl z_cG&N^i$+lr5Cif5q)S$Dk$e{o}{*t(>=VzRZ2ejrTX?{Y&#M_dEYz$$udBzfb%@4SB}@4?vn0eN#) zM&{)~=g-j=3f<)2n^@?a_T7tqg=eFZUiFXi<*_LFmdBm<0rH*~r}#~!co;7D_d5TB z=6bo|7?<}NIW96sulg5yBNEBE@Nbsa zcCpuU&TGPX{fE33$4SLS|2`q=+sDEG?t;&A!T(dicZh?Ri_Y;aavYVT>;C^F;*4RJ z_PLi(P%k>dzAv`#k$jC)Y+vUb#!$wP_H}(X@|J%gjbPBL361DWWDxzGk>I9)i$r3H z=)dug{)f*^!3YmC$muyb{nec2^E88;{wAltn-hx~RbBKCIsMa|$~j(BmfL5P{!^BI znaQ$>5`9%}TU@waucms7o>yGu*Gh1fbX;d*v?^#3E}`xwgT9e zVvEB{{o!|8p0>}}VyoGnw)xoNB|M)ZX4WdYkQ|D7sF%2)+Lc>FB@}VeV`Z+b$DZ1q z!?V;LL7Q{!5nPAl$b8WSjFHhPdr2dDoP<_|!C-&*Gzhpwm|J{BFQUR3sNJ~Nmst4{ zcQ;YvwnQj5*_hQU2I8?t^avT`ji;)8Kn&*n7@ZUI($N5bDVX3!qRzs(iXH))vXf*|J1M3-1~< z;tUbTwgMuiI*1k_E|;79VEYvo&3ha@i;0srIK1|a>p}aph?i&+MXxF6>T4!C+ue+?6UG$#LBV}Bbtc9cKJT2~v&(m2Cp z=(RJ+oYPd7*n!9##+T9s+&Aq=F-ZwF0MpxD%2WlJ_ zN#=j7e&_N#ik~fUPHr&s1Vv=OZ!KdX8<(rIdM8x3xLFlM-xSEWBlh4H_d#TY zt2N#qY~B%_qO2I*s|k(NDx@~iH6FCBb7C(x1=XU)=o75txDsB7zNQR70kZ<_Ekjr8BB^cfYUbasem zDH;C|bRrEk{bDZso~4m>X?&kFvZRrnoyK)aL%m>M=Zf2)9PgW{E9}dYjQFFN4>yy{ zo)YNwu$%-DZO4zqb4Ue^_jV~j4oMoDsUc3YzY0>*G`pBDc8A|5dbEV15|WjAZt}rm zKKcm#Xldy_KyL+#exMY3sF0rMhXScztB|6rke)_`unR{KdR!4eRn%E|xK?ZVVkbVG zvkP~F3U{v(?4<&Fqi+ag*{bPYy0^bs0cLMhfO?f;pHQU&dRrCHOZvSo{qR&0$~UUv z4a(&qB|R{4YH=WXSYWAGs-4VUOw00n@ex6Au!7nR5Rur)y+~u8TElPzNWrKP!=k z3xID=9Poz*+|x0-TSx5v?T+oAYrw~Le6iPy-Isa?Of}$lAlBlWyX4MwYv--a_MF_* z$22!?)bXlcH%vM$S62P3QlsS{$0e0yv@3w=Yh=`{uBHt1;X3nDC-63<8F7aJ4bjY^ z(Jc~0JpjD@Zo5X|XXZ(VzY+2$?Sr%z?Wagj6E@HDuzK`bDpp#N;!{N;wN4eGk z9t5;WQaz0_>b7wlCd?7ggaaqV$(f0l^GNOzfxL_xy$nv)_Uq)%bc{FB{`xvSEj)-* z%!Utvs~$;={feDyqut3K@k>sHin-`6f@M7RX&I6zdb9_gq`nKOPrl2mJx|$*dW;YX zJo>vAksdpV(HOW+WF&FK?q5f*??iF5E<>T=o&%ZqsV(`!x7ZC3v8p?1?8)S9@RIpuKE9G*R$ z#C67(HhJEULh9u5ST~-hqy2HvvA_YC%v{u7-FTL1P3dhWKio#HAic)sS;o~O=zGA4K<d@g>c68GlXt{3fpm5|p=1Mq{S0w& z+7|MSWyTQ%vpt099tPdG+j@9*%W33SOzd{(w(?Ww|F82?sB~ocX~iDh_kWO|`XXqQ zc&GGjv^E8q^}PiAO**5dBMGfi&!ti--Kn8hfC*1qmzxb+B+nj zBezQDyhb{g(oLD%#MbF(&mhJ}Ta2Xh(yh`tzmd+G7fwfe3~@Tzi6k8pC(&KOX1Pob zMdd2KaJg=3rK1f?(m84?e4++Eobt{t*F7-`+R7yA(aoqvC}#5Qu13*D4DD}j9fLW3 zyX&kN+VmvG>e+d)5@>g|7$^{-d6_mh9Tbo69`22VG&*;VBCvMIV$;c}Ys`21Fl>B5 z(|rhwe*H^iR`=!8AAXFL!66lwopUjR*~svB_hGpGf=;UEG}TK1b3VPND)R zB+6uG_(8UyoPxrwCH_tE7LOA(6lU>$QLK$?`zAEn@~*VN?VA3}n$W5yw7($f!aA_& zba2DzPytly=_)?kNvC0kdrQu4gBLF3u39DU%WU9*Oe|+WXU4pr@$s(FCg4eshfPg z?#-P7ef8%MqgI5c(@+(9mskmucy~t&UQUMF5sJVvmgtPWq{u1pW`pkjIyfV5vnRe&73OYLB#d3 zd2Vc;7n|qHycU{0=4hsH5J$m~I8-RHv4tXU;h=N*_Zkipu9z|$O%CA7fOC`K+$Onr zfCU_(h@kK+K9v%>xth*`%o)m4BSOV$L_oL;o~jXz#|Jm_Rt8?Etefd?DgBV}cAvVL zc$=Fe<$jXx)W^nmB$cf!{r1v|qT9>G22^(@@tJc(AKhiy;3yKwelxmzF@5{GCQH4_ z%eQZTc)RM=3iEiQFapBeTwyfsRmgjz+O9=`K3htA^L&cK-%@s`5vew{WeYujoixy* z3Nu`xq)=AY07e?XLI<>m-KP=OfZaV*cnz){bXp>|`4&g>r4Cr<-6}HXdt{ynt2|9f zporYz5p#aX3lAa>s#u1r`2~o+VA&+?GI%s$^L1@Z{4@+5Zib)yjY_xD?cX9(x_S;3 z)}`@NT{8RSzM|%uT{ix1SPtDgj zCxP|~G8s%or|^h~3rJ0jUZ_EU!>`0V4up8kbxTRGjaSyy@83mmJ>~E|M}zmvNY&Z? zGfK%-`N~akcS zvbym)&Dl<-dI|-Oj>FN`Rz8QXcSEYrsAFTpLRfrIxw^9;(f0kyuO>guqE1li^hrVO zLoOKY$~VOyTZgN32el6q3gJ|Hmu;LwNTyrYdY34R@J|D@ z^%nA{`j5t^5(2CS$RU|w@#{)omOqnN_V}s$eKOC3I^U9Wf{wQeWz5@Ts!_@T z7Bu@6Q-g1jR)<%J=Xkk_n`Ng8oR8R;yT9c6FVRH(m%mZXT>K_e{HBhn#g|J6_W`Rb zrD*L_smA?_l13ZrmXeZhYoUm}DLCbnp?g*eiB(2pATMbS!R}^Guh6JHGpL`%#U@lb zyoNhiOcc&0^vqXWaYGlpq~KC7iN2g!kw|E@H~m!tFA1iMGp9aMB9-H-Fl;b$Hy#dB zkZ}aml^$!?ogjJrYjQ(1xpQ;Y0{VdpsO53=+6_7Y^1d5-<_N7`X>bC1glnlu#+(Xb zA42_38E zSSe0jrmJaY33Y{Z+?BJ1_dO~`0qsWm!69aM_>X`;3lqjnhk?9={YhZCH4^gmBh$I_ zG6H}^E0cR&CcR{`oiZ`Ijfu+R2=ym%9`aEhr*E^M^7SL>@-fY2v-0?c@*r(9nI*{# z|0kY9h1XD_#s_zN?YWdb1T+CF191VyvY8B zs{bjLxsObT9e6+Bhyx!0oaexA0?v2fgMbSh_z>Vi2R;l~&N}!J!8r#%D!9|Zj|t8@ z_;KJWHwc26ZwY#jpl=JhS&RU`&re^ zV3^*!IrXEuc~7%$xE>J9e3vp0R}GZX!Vw2P4LHw%&j8MM;P(I*IB+xILI-{ykh-xX zo)w&P@DBucI{1fz3l9E~;BE*17+4a{!OTzO+T~n-3M`ryLnS)?FKKhKnqEws1DU~y ztv&y-`p=ZkzTR-`;OsO8b6@PtvtaFJo8t_q+2#~TZSLjGcFpFF>s&Ykldo@jzN{km z^+p<*{9KtH=*^4mXV=Z)P&7Erb^#Cb0S}pvGWUvs7Cs+p>t_^5_^jI|KJxWVBT|gd z{02V15I*~Q3uf8L+}s;x8x3gVO&TbS^3*Nh&^p+58pzi-?VNF*3mbX-Qh6Tem9w)P z$jm$%W~-bZZY!sPD9=;2Sx))-k#sd#p5&2hvsu^ei?Q__a_VCo|hr#8#y=&*?J7A|Ho{+wqX+zlld2bT%HVP)b5*L*0YTcsS;h#-LXDN)RbIXpQjN2hd-ljgc zCRFHbkqr;n%T-2*E11n+bXW3sTTDTfzlfqI92i6gA#70YIW>q51~{eR$`hi__0X1U zx)Cv}PGU9~{swG^PHf)qM;VyiPyZ>-(XDK4bWZG$j&1|U2S%ry-ue?V z7|r4~FQ$L1U4U2u9q!z>kl1Bk>!oa-a9B*^^5UuaaAo*g@>(;scMCkW1)kRgy_y)+ z1upNphCB4XBVMq^omH=*^ZqDx(N0+}PK;j^E2y{BIkcZR3?BTL^^fvrBSt+b?}_D!i&tV7eiDq`#P1G%&+_9&VPbE7 z>-lkaH}PeDf8)n_#6Vriq-z=u&_pox5Q@5-t@;mCNY%UWWj9rU?4dCiTBC+SKWm|7 zYYROzH?+nUg?`RL%hncpcy?%SYA6&2>ipY6jm!>}u4#Nyn!8wN+1f(Sn;TlAm_o0z z(6Y6Ko9gH`VAIZwzkj<=Z4m}S=rH>y46C<))u;)ogLhp zy4!+j>}wB}n;k4&)9BkDzJZRrQlVBXlH6<`u03Yw?3nh7o2t0+iW?)ctebXVk6Y&~ z?kzV2))|jg_3kY~$mb4MxjvKk}rS}F(rn792dmYa1FWT}v zESPk5@(L1Y$VxD8V7(3^c`8+mc+=_nsepTlPP>A^ch^st)?W(VprTlBSELzbxsAC zl)>8k?8shWf%UD)eGz<2q$b>W`^HdeH)B(G-}RR zms1Z((>2e%wW1fRMB_|Rlo&o-v>=)6p66?zS4IE;7zJbW1=ezMgW!zrWwq)!XYC&RxLm{>>Yvi38M}fpF z7k^v9{H=ne6znR`$o{Bj)q$Z}#n24<(JFT}gYm0Kp8J|;O9{C(BZHfoGPsQyxVl@0 zyamtGhHrs&kw!fRuDy&nQoeFLsu!gt6WD)jA=ws(BEuUX_#?qtYCq`*tF zuz07~v*4wx?*bUjh1X#ODIKqgx*4a3t5oHR6)K=DHKoNMp5Ow`zm*mWf6???NEb5g zskk-3+ewEzJd)R7ct&7&KtdWqu7O$>36u_QgmW^~IdPJ%65Rk6m&u7&xe2Z7oIyTW z8>Yw-(G&$Idosz|5Dp>tMT5$s!SRNjE1*F|z6!3pqNei3jt+z9Mp9mOLo-7isFer? zJqIzy?=;$T%>;{Y-{=i=Rvh`&(uE8Mr3ZZ5_35ntz)cW|*dno(l(DX|gX{rZ;3D0htS2lVtK3O^n9LL&U zh!kJBHOKtK%H!RdUln3*^J;dRT#s?zL`}D_`nD$~=B!R^$qLla7X5p6ClUpBM9-^##2t$CFa- zw0Si`t)J7*+vZ%h5@g(av}}aD3DG`g6k%^V`~V$kA9pM=#w&eUwBkhb#4Me-aYe&8 zkZ>O)+~mXkI4-YP=zLH=$bS+?XrbEwD>BS^EL0y2H+(U!gX_=|!&MePJVJrFFde=`f%Cn&Ed#89 z<`ucR$0R5^64&q;1V*^if()<}2UStr9rSf>9&Rnj0%nhHX*QQnAb_dC5ymQwuEpgk2mSqeW2MNo*rZOfqgG2rOqa`1H(lxeXa z-i{SMk}TsQ(&7Fj^8rOdXMlp=!6)RdD=%)Q#`<%ci6x%X-|%pPm-G@H$O?=pHSP1g z%z4q9B2AiFL4R^pyz@1s?@^^nX659j3;92X9#QW-k%gi?8dXPvu`>A zHR?J%iurEzS3Xi*mPMu5X9+ynmC@a`fP3!$g>`fH7?<4K9n8;Re`Nu(r1S9tMvQK*sVrTpb&5kRJmkgmu9E|LgDy%QbrScKucFJ(zY#y z>zgFon!jD=K&OE_`iG zH5h$SMfnn++(c&(eHp+a#4_Z+*|rS%U}A8Iqj@JZrzf#LFZv46D`~G3-3_qWr-8x# z){iPcvFPeg^`t$Foa*V4-Na-6q|Gs~h%=+F61Vm>K6J6B09ds%>Plw&BP)q}H{}TX zC@iaqsY4f0Grz%Nyhl3XTUV>4p!#)^>Wt&3tM_1IQXg{B(3Y<12FIW9lO`8X@!6?H z4|FufJd_J+nvK3n*Top3=9`ngwh(0!G-Z#Py1>rgi3aU2fx{(L?#Kl*yMqZZmzIK= zJp_}rW%)|Kb}y(POv?FWZt4-WT9mctjN7#8SgFvfm<1P-p~r(z%#O_IcxgQL<>2c& zPT*W6|DiPp^rnxId+k6HfR8yiKn4sQRN=6mmAcBS?TH7Xsh7w^&W^DCA#Fn9)N+zY zZ9<@hF7ac65+f52=m^PC~b*sS#5lzc(-o?}_RmuqM@VzD7Ma)zR@U`T4 z7~RDZ>B;UO8pO{AJ#?HLt_8BWY>beJ)I$K39{Tgck#2EKW{tI`hak_W3m82tcWUWF}9NXa-rKK z=Kjd0fwid4spqIXr{vnRmga}AR#QX1%oTkX5_9pZ+~$F=5S)%wYJW*H%+jsG94P(S zx#LLMy;W>wOeOw68M&&jwn3ECWHLFtJe{f>fU(ci4g?>G^#D%YG%s<1bpJKfM^0UW z@6Dsb$xY8t#GAvVNLyH-s_6%p%Io~t)HTZSY)X7_{ZQyb4Id^WRezC;g54PiFQ$C; z!_6TzDS5(y8<6r$Pvi@!@Gcr)^-;K3-QHuElj)GLd19h~{c-G@zR{7Gm(SE!S$ve2 z1Y_aniBx~FIi%$`S3t; zw6?*T)|6BCOE%gpsM@GfpJ!NkHyHHTgQ< z;_L8(5P~IC5Pry5%g_rPlJh{j!Y+#n6WDk9rGTdH{YZc#kK^$L4(Y&9=c<6A9N3pWqh#-Zwc5=?jz}(J7uF@|QVBJzglv(bLtYT-^Cl## zkV!B;+MhVT)u>q7i88KHEp4Q2Txl5KZ>(e`bX0S+b+zqjA1h;b`Ewdm;+D7E5BH=2 z(Xhn>szl@Gf05K5y=bvD+->0TLMiwSJeE|?hu$+HJ=N<*PaZ;tf|R;()`~(1=BsBC zW^}T|BOP0UFR7ByuEoAjUG4!Y&}yd&X$HMl;_04}egK85(Ncn`yuJ4FC>kY-g)V83 zPF0uT!<1gS+Z!7_4Xy1#Luq@pN@^hE6CY6p`|~EZo9-Bnxdy3sxMtyQAas36TqB>J zL_b>m`}_TAZ+5t{!oAhP$!FT1?Y&6eH<-74rjxV1x0Cmc<}Dxc&|k8JqnCJh14pAJ zW708Dg&ylz8L9elG8pRCnwhGfXl77&(p7PcbuBe}$Qybg127OO1;i5tKXtvZtD-;*G@6`WomY!$A=!ZlQtNqdr)GIvLqVmUKr*RZ_s zRWu0hei6V0tF9x{JZd@=YC1C;p-~~UmmwsdbTkPIWU71P;?k?0zl;$3U=Lpka$vA8 z@X9I9K2_KqF`@BSQf2D(E?`)QGTg#IxIX8;SSN*2}C z$#4ho8|>U%A|QKP_^`L7jhFBsJXpTQduv`|w>{iCavuBcTSy;0JJe(N5u)U#J7;4Y z3gbfzWBGW=>Y-RTO6eO10?=mTRPcsJ5n#`^5V$}ntI$1Phb^w`Y;V>&rQXb}I!FKRP2HZNyYpV|5i9w6*SIsag2FyHU5PxNei-F@#^ao2y%In{|73;^~7r3Seyg zEXqt0j~TuDkB-|u8}Nx}FPgu*y>%=pb{2x5b{xRbUYeReN-Z#aJ=7k*ycsFln2^ zlFMKFkX0$axj+aLcX3S{mTK;sAHLf0)S0PDCdH=35?G{xYP2uW39EL`u~-6)XAQiz z=BDo1byR6_lYF-3rsJU!-1L6R4L6-2o49GnxM`a#qfKS?4{%s}x3F!N>6wkrWQ%3w zqb#Y#eqL4kwZH=!|^mjTfrtPE}uqTdKODIdC7Rrk$i|^RyT|+tzKLOvsfd zQBOhCPik9t-tNrk<%!P?wd(4qW?ePM%{xW21+J=s@J-m7L+1)|WawNZic_)4Xb}z^ zvhx_moGNp9d5HrLZq!#gv5fk9g8E_t^eW23JG67^ji+VWsw^3PoV+`y`({&WmsV}b zr%_w2{`%!sK`U-ibtS`fvVm%&FTSQ#UG&+my3k*2)55e>S2k{CZc_h#tF*X7?w^gy zQlWAR8H~=zhi1G;l@?TAftyPuRlT5Db;r-Cx>m1zD&beYl&VWNs&3nT^UD(VZr`Z8 zl-&cEGv~3on`dN!mn zl5AAZ>9YMlRL`yL)l-^{%5tG{1{sXb$cO4#?5gKX+_tWs6JD@-&LaH(UOjO?xL@Ml zxF6J9dInZQw`H-A=D1CbYGbc^Xw8^S9b?=vJg!0@s6=C$K3n+e^}cfewgl_>R?n5& zjC>H(<{MPc=j%$4tX|k;ur(?{nx>hyzQK2+KI@RIy$yo8=q4_E3OR>PRHAEi4Zv^; zBXEr|yQ2-W!P(T^Rn*;Jn90YF{s-bR32DP@s)^a!ZDXb}wkvTJsGyL#SiOL_xuB4# zUkJbeQJ=zODo~Tjb96~PNXMk$zeLQv8Z(L5I~{C6fCXw@q{uZTQOKt4t*vx81!)Ui z;fbKZoM2&Fiuv#^QhR}U0{YLV8*QK~aUpo3x4KyUE=4yyUqQk9nf%PfZCL|1iQjGT3Qq`e!l0#`EPUHp9iTSH1aoiaVd~%5&`H93cs?&Uh{X5Nt>5*+RTx5@= zkczlS-|SDrSCW0szMbK#fb*G+ceAMO%51z6qc7Rb3#6~cebd*lZoCy4q{;O3XHZJO z7I1pgS8=@M@FW3KOx<4w(qn~A5jS1v3|~XE%8o&yGZGYjoh82ulELX>Io*R(R0EpG z1S#j|6|y!cgD02UgX(;in+$3nqc-~3nq}gN{>K$>q~AfFfMYduIu<&MIn$r#M&9$~ z=NvZPqcU_BJNJAml@x5eSJr&>5_05)XcxxXSFuYxUZ9V6`vA78t}9rLeIvmQc$6CEYZZq;h zQSP_Z{q^d(C6sVpiCY8bwxz?%!MM;_>8Dz4ei3J2YeOnRC%!As<%QtQ6Ybi4i7`^> z48nU=&u<{*LT4uAP+%f@BbH~Tuj1Q=+MBS(t7ZAXt!}xTu|-#3IumWedC%LSQMPh? zHe3f%eSMq+q@%0xxM(s3+4{X=f3Xinx8s1Kn`;$exygL*z?Omc6Q(#|{CN#=Hp#xR zAM%H%klMrv9P=N;9PVA>w^A$V7m3FQz2ac8>GzEBu~Md z)2lUHJjK-kO*~k1!Noj-WW(57NXRPutpHnsxACpMU2Ze-$wY6X_sdqV1&#+|c7dC% z=2WP(;)eGgwx~)}M{%tKI91s>viw%u;C`&a7hsHaxR^KJJ8TkNE z7Jx0m2l!S$D7P8;g!icnKb_(S(TA`%_F}pcC!O6Ie~_h0plq8xH#MJ>&K_VP8=Qx1 z0CXpJ0RuybX6Fgk2*WNUs@!QRbCwM880RJS+^dy`&McnQ7?*9V6;f`9>+!?~vle-= zy^yxCBxOTMZu-M2l}dUmz?R@PzH!$hA1^g)qpme>$4j?DCOp%~uxq?AP9ft%&VdGaH^o(th-GQT4uaI(iBq&$yULg`a>vmHB|- zCxN`o*74$cy|2Aq8}&4q*ek9l%|l-d4Sxte-3SNx(MKpX)$~z}N(JC!0G$)VOshT) zl=m_|({cJI+I4s~_~CIo9+R63nTp&lr!4M1n)vreq#J$$fB5$fO9}q{q!P+R&oSH> z|9%R)-t_;+abWOO%8us*M3X5II39od#+&hbx!yBQ9AAO$bV&}wUI;!>?CuiW~ zJH*K&g-j;=)Lc%sSTP?zuq{5GNbGsKqn-Fz`%374hL6dKH4ByXMe4)2_)7qei@yxi z;9`xl>F~|u3m1O{54boD7pKFkjEl9$>Eup-O1h0l&E~B=q?4>Pd?xt?@lSTaG8=Hi zKEd@gJx0ganlc?WKO;Tqx}lADDAQwZUde}dpk95|Nlyg?_rSeY#yz z*LF(7^>Fd#ftK*C>!Qp#PIwiB_ykGYNy1Kun(1gkS^CpoC0*&Oi$1m^qRvB`Tx_==%>c7`&$fp;J0+<2 zUdZj9M)hex;mugl+^o~Zw4aG~=9tJttz!8*#>hlsuSCy_6aJAj8HUKj;4XeFCaXGOF+>ogfF^A;xO{{qXB>3Fyss7`U9cR>*T zh+1{ZwOk+Ck?2V*Jt5&A08WyfS%di-a0|Z+@p9o)s-8xjcyX5VCX0p*D*y^Jv;Un}UPUz`K0f`%WkjRYPJYCM8BGL<%S>KHlA4yRiEAR1WD=Z)lvCokPb_dJQA88w z%}ta76Xmr;U7#dG5UyI1L1{a~bQ93hIH#D7cAR1+7B^+={e)hj6^Q6v&$~g5NttX zwiAeGi8B<4=ma3_MEEwCUh)-w;^a7PbvrnFlx?B^)XvPTcdEiSLxxw5yn10dYsm$`*DNgfAcFnel(3MFZnVURHP}^_LJP)q=FV=$)+T2 zLy7w+Y}Z8JQsX5ceWvP4=Lq_MjMs^7iM|&VuUFEiJS9B%%Am2bkH8IUj#|L_DjtjhhSZp}F8L z1RI@^PxM`-FaGrt`;g-A!66y_8P%4^cZLCrjoid`3reO4iBz(v7U5zkJ+^PM`6F@IRtO#&t6fdDN29;JpL^aaUn;>Bw8WoCvp3<@ zZ^M^+iGO7W!jD3A+v?@}!#jD~UF_eRa6M=JBLsBf_B^{=ldYf2<@X8?Zq%lu^PujY z4}gJJQ&G}J?o#wMUTw(_b~$TrYRkZl^xK?N97!8XM;8*QG#Ie}W+4?{@8+%dW~g0h zJlsVJ!Xc(5T*q3)iPo?{T{-$86@b)^xR}Yd zFearDQkwiIsc(VmutFEygUpq^;j^;JX%z$$y+$e3pT!U110C2o<$ThWiqT_;S0(r=) zN1*=j70{n%pb#}bj&^<=O=cYJZQG8f5H6bTAYKCge=&YuuN2O&-Vd^R*35X$zEMEd zLHGz5J7;r^B$^o*IJWnAERar2}0#f^7~vf*CCsjdvN#q;jH6Wg8a z=H1hNGzzJ`@IJC!(%rD#kInk*hHUA78}I)&RSiL(5J3a52u~wvT^@P}7n^(RPZ|G* zu;J8gbxG6STm<+yP6hd2^r(rl~}xUV_oJa7LvBLL9g~k z_@4ePM^LWbJG&QkDyG_&d-Fs%^E9u+`8#uPMnE8ZR9I`D(oejJw4Wn<$}rANoF6!h zI~>L@r#}hr7VgJp2ABAm$zr2yWXFYBYM#+jngy z#R*|Lx|c|}81Mfio?N}DeR9>vz1U0w<`;{&WwEkDcjtkiU!F2E*HN z)O`G59`4?#g-KnN;9FIw|8`J$WyFRmr)vXCc+AQ?gD6kExX|9zc9o6`%KiP(PKa*T z)fM~R)aR~CwA@5i+$P(@Z8EpIx=@=3xcj`IpK#YQyU1YF`twp$5Il9vy2J&8F?;|? z4aM+rz{4?o7Vt<6UkE%ehA#!4Z}5yp45QT!h14JvnJQt_2_?Qa?Smn@3OM%Opk}U+R!#M zT|lTfPecW;;H5}VUr_&tz7`HtIfDYCb1TJGR?FCoFP ze^}m%$Dmoo$fqlr^x%>sOS#RjLS>HSmkD{TIf$MDrTRsL@yh=+j|pV`Wsg=fyY0%_ z9KO6|$%vP&U#MV%7HTlJd9o2B4sXkduR7$seoK@5!1ifjtM({-wITAxH#&SbG;pyD zx$f&S-kXw3o>`cT8x-C?jL#S&KPW6Q) zZmKT?X)=Dr)XzcHvurjg4TqP3PIdT_>hD$ROC8qk#=%0r+SN~@4JsT-&pSf^uXY*V zFp%E{FI>-Tf`VTmA3s&Sg;Lb7bm`RO*x>(e>iBwl2S>izEO@t8bkL{~+RWUDT@o1< znf@*^sczvSiyJE??sr!_LeDbr?HgW^hI}X~jZ^mx2tTAeOde3_Ow7e$OX-ppNrml} z(iiDo+pce2{>X?>xs6S!=}ig{WEL_W{)841_Gd`k)OLh)gA?KN!dG|BPa_}wdDWj0Kd>d)1>l_U=lXAzMiJr8JZ5IwR zgKP4cVA-#cX{Qg$xv;sC&4CZ1tbO!LaENk<(j*J4OrzgYFJ4W!UULqUhv;Y6(f!ej zzZ}!oSqP`HW7#iN9^cj~&r=?M;|J*=G<^?uX0wa^IHQCm97OEb(Q&fk(bS%`rR6c{ zrN?=kRxsDIb#)B})Eq%_7KxP7RE5&@p5YJ-EH$@BvD#%2ST@TKcBKidOs<-ix|9P; zfBI@Nv4xUjjI0>r7tn5WMn2&Yy02us=QI8`_DEu~EY%2M`53dsgmbP!9t}XxUmCtd z_ny?WTOWF;G#Sk(&t}`Ctunwc1|f8ca6?YlFArqzs}f9Kqi|leQ{IeBVn|r&%`SG$ zOyePqPaQ^|`HntZYLjnZ-|)9=pHY}q&T(|oA1jR;=F-M~pjCn8F=P3Wz4Z%z{Xa+o z4*pN&cO;xC=@H)+`(aTi;TE0+;D^ikw%k5oZkNt-yH;_-SMhCzixygX<)&NC?uS}- zbS=u=>fcXHQa*G}Fm}puk`8FgfEvH9>KT$XMbfPhEtb*|Vow^Lj356`<06<8jNcRA zE{%JuMSh%(GDH2kW#`$~`Ywp8Tcr!t+svofp9q1G(xb)77l-DGQ%b;j`N3 zF$wc^VHj9S+%WU&*Ajs$eus=y{arHXo!*H_=eT8H5h)N#-lC`WB2K~7-@JHF)4NcC zHt7>eV{VkA-Li!|b!bjEQHOYU2MpLWed%e53nsXOEo=15sJ6+6<3J+_H!1ble&~MR@M&T4Z-dl8U~ITXTD0cKB#;jPMXf<&$Y8U^GF z=l-0WD6{(O-7xPGFS>I5f9$w!eKD?fpovo6!D!Z~|d*vc~*k&wYV@xwWF#&92 zK(Yaw4hB3hYf~&%tRWDJfzU!Alth6LN+6H`p?3(qYwYNtbeSF`p88UAl@xqu*Fj+%liAe9zP}uZNTvT=Z=|APS!iojfNoufAkyjb6#8WI z$?B%&J@b_?_OmS8|AwsV*DLEr#^A_W3~;FllCi0cbnOVpl7LimA$e`co{ENk3k!r) zDjIe);fz@%r{Z1Y@|`M#31|U5e}{QyA>HbFFh?YdYkJrk^~;wl5{W%V)lXMa2PCPw z1bu|5N%}hw{&d8}4LH$^MLzn26{mnd+G;A`sLjhL3q?JXhxLXx0ea0^Cq!dFR;#Cd z4beg@hLaCq>Tl4Zv4|U_l=X40zBQzWwZYm0Kd2ILvhZ7r@WY;E4I^Up)5TIE0M`X} z^!$73^E1}V_rd#G+;Psm0M?q*HbC2f0)TN2DHcps=IybFwO2O$(Dw8~6M%K|-wN;k zk>PDv3y%~P-nc+`=uRwVVBXhbPuJXXAsDb$!C01H1f zPqitW^&~45OiJk1QXq3Ot0Kf%)mpsF1`vAYr?;eX*ezAPS(SruG9&p=(lo`)k93`w z6|$I$=|ci42+sCIpc3bm1NyRLAb3BbWIe!mQJ-dL(pTo+paE^EjeYy)Q@t|U^)LDD z8_E3d%f6oMv%S#l8|a*?62T^}HD__qr`j4#Y_=FuM>y<5ZEQeA;@Hn#N-o)%_IPb8!3w0}TuUFIUP}MqC&!GjiC|k*|%n#?(+O zC!;f(+o7NCVhdK%$?5iwmrCx+80@w>u^fbXVi6QQ**_$^n%RAo#M?xoj95-q60zyv z2Z>_GZ3R~@ZM3LpH3y;v9!8&oIVu=mYbBJDLlHX`U)FN?r_R%B)jYxoZ3r#1e{<6S zuaZ|H9fv*PP5G$rCI>a^7!V7MxPiS2z-rccSeaFwRXVr5D^SC;5h9X{D~ttw2m)8` zdEH+3_LS6mpvn4y5m1G!xGsvjJLsL!2TsMyZP>Br+9Uhq7iw|FHEhNJorF|8H$3LD zsGggpB7sBF2<9=8HrmCMQYbDpHm&!06@AM7je3Jn#<*vnMDy#mOiGxdQAPL-5;b{SdLg>Vx?Q0$kw(s5pgvC?fBb}D`~>a=er zxAe2MG3Uvy?t)`ZrQ_Gut7G;t^^wL&E~R7k%5tuP^MYC!r~EI&V4qbV22NM4CyXsd zmftqNET}PoH58EKRwv!Mo1M<(LOGI+gbX20rCW6KH8R=ruV3ap>yvppWnNvE>oNeZ z%f@?{I4-WRd}G-pSSJJJ`w)qozGi%0A&borIRfeaph!1&AHkr2BTrLQs2 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⩔ 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%0DO+uDo@?(b*%DcLawVq`$15uZ9`Uf#nk0E&t1Tr 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�G-nq$;jqjni} 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�Xr_sl-_VdJi_-8RcG8Zt{;j?{i z`Gt819qwoH=kZ*JL%gn~d2QaBkH*+v!1{089K%;Ln^)Gqu>9~Z;yOpLj$MSDUuzv( zzBFH$FU?1H?i);u>KZDW3HJ~v;Q4__Vob6EGQGI!?cFJmY9tLP=H=Vxv1V7+EH zmQVjW9=m{b?9#l3wf`IQ^fInFH!onVQ^C5HwdLoq_U-s@qEG%d9(xM2vwPkwKl!`Z zpZ@)ReRhsu_W8P)TV4e3UN6=;g*E5NKg4sL!phgMettzW-~DVM^ttB7a+-b4v$cHj zk8#bVx%!v5KgGYs{Y+jHJvGnGg}E}XVC`*V`Py>&Wq2*~cey+3(0Yvzmeb0&u+~pr z8|R$B+#mj|V`}*fR-e{+=hi9AOY2vbuVC$eWBJ$4v zU31G9u&#^Nc?;`Q=9Tpu%RBQ1)(nH?+mLgH_CbzN)oCU|#U{}tCM%$2z@cjm#og|#RAW<;}1VC7TGXO_<` zUszsPzJzrxmE|kT8_U-r=QVbg55at|Nd7y{IW;ffmxb490qZ@yhB*VjUt7VtuGYLZ z_rW~ZXx_qHXZLrg|7X7rJCk5O1DWM>nET1k_dMiuYwpb>teMmQjh?|gFTc0yVBI5H zUzhgQr**x9^+)TZuaE0zu==!Sn8R1|TV9%LnET0nSO@bO2Uy1@$-S;Tfwlir%Qu#9 zVa=1K`~Gfk%`;e?$-VA%^>@Z+F!R@7uNJ`vc$UgwejY7@`8?E?x551PLwf6s=56p_ zVV(3~e=a_&Suod}!@Bky*7cUwse}15!`AXOtiS)>hnzqE8G|2(p9^iRpHB8Ourq;q zuH9aRob%)%=Y8oz{!FYhz`ED;3&Lw>3>_Yuyg}?tVO>`SUtJf>J3OnofA?G@y zIeEjlP73Qj*1`OD6&+1{Fw>5Xxr`7L6hx?qp(f(LIOS!o;S1{+~{57omGQUrpe=zs=jWdtt^o`^G zXXe~onrm}wPT$1VG3VE;Jt-}(uUYrKwVYPoTRxi8H?gcPVXP{ z?3%UbIdZqwS%jR=VQI(Gy4Q8+@O^{Uv8}nkW*s|*WBJ}f>)7|DTFCwZ&=>y$I(uqW@fUj=i9wYh`&Uct`hf$_R7V6MZ@h)c_l-a2-UgSlq%HgTO2*37l}GMMK| z-!@+R1m^qaM?N)84q-h@nRSj}&68VxZ2i*m+I$*1Ja23HdB{2c2Il(w{n#z6_j8*0 z-y)yA-QN66Sp@Uzu@=6%*XGf@4SgP)J}CAxb8arpwfPj*{`&0F*09b;!bjqYKsKgssy zJw1dq&n)D8ot_8t{%*~acZ%yA!aSDuo&H*w|JL-8c?s*hC+3y;)cO~eZ_St1Il2+o zT$(4dm>i=jIO9*FV#DiLdv8JVQ%@-`j_t-k3E04eV_OG0@isC|4-b*0@lo@?;h7b zhts(kqz!eSO&S0&Ro6FCNof=lBHTRz# zJ0q-4`Z>`ptn2D6AKEo*sWrMeF@Gg|+_Fa#}yv%3#elw+^jNZk@t9 zmANr@<`L!$yVuk+;%rm%++4uA_Tib)Bg{GZ-%w6JH(pm}&dmj^bxO-?nCtMfySIG$ zd9k0t+P555zpzdja?Udb?>_fGKkjD+U#(*<&9(Jgb8nq7Yjqa=zaCV9q&Oo}TWHWhV>Xea#lk z-+dim?eiG&Pk+_DlH_Y*p2C_rgEB!KA3+$sQ$V*Pan*62KZ_QSm#Q= ze!qvj-Z`v4Q_Ep>3d<|=2Udb8{cedo;khU&(W#Q~2uIgSodw= zcU{>y5WETi%*`^LWkNA6`rHEpfIK)_F5?ZZ51}!n&6FnzjE;=<{5ybvny?%LmJg zZ;i86uQSfey{ill}R z?ia1RHTTzi)qj3GS8MKJcKG+O((jC&3}*gpTno)>eBMLw9&Vl1+?z*p|6Tia`1cd1 z-yQGo++4tVzoqpIlrU#_C(KsCy51VrzP0Aw`lIFb_gEj+I=y*>wO47g@9(~rgO%r& zmzLMToU;ubzW=9fJl7QF&jm)C**9&}xec)>$gEjx$^4#+B znt3kX-xj%Er=1@82$ zF;8KwnFaG}p1E~$>y*~1tW#U3HTUMxoPMueBdi$;Snq+Qb!u~K?#=1<*_!4#toxf= zUYZ-2&(iyTExxa@yo0ay(DK3Z(em_#afT_ZW9R1FI)&w><(1{N<&EX76X!T2TZEj%gRcm?q z;&^NYt5aLvntStL{n7IDN8_5AIX9QrtZS)}yLDZy^?UR1WAPp(KOQ}Wb?n?+m@9K* z?#zQZ`-!+_4(qfQ<^-IfX?SE}~18bhv^8T9jni?%ne>ToJg>_#t%X4!PI=g+dyo5DdWu4kO zt+_Xk=Je;{Jej$KHGge+17BUc<-PT3-HXwj{(Q_cb8aroC46;XEU(OU=x~1;%Ug4A z9${Sus9fFYw>8o?0gh9e&MEYtFej zH<$3$9$H?TTXSz7&1oOcMQi@d^4wgSYjXqh`QdwG3u_%(*V0+1w|p><*Q|Atm&bKd zSl3Q#{i!)K&&|2HFqh`aTwk;1X)JHeop~_lcjBA{toMh~a$4(G)~T&S>)Kn(X&u{J zKAO`_oMCFtV6Ms68m;}Dn{!y})9RGw+T5CZ^Jq?gF|J8#&CHye3;1f^EU&NmYJV(m zVO?Wqd2b%fqdEDdI9qC-nzL)xUd=7f&4sx%SLWK>m|OVj8ZGb4edzF>(%Rd>JereV zj-AvzHD~6zIX4&P(p;HqSo71GtueRe&fH(K))_1x&B?FC&ox@-O0QY#Of9GNnV4Bl zv(LSqTb`Q>b7`*3wYf33u;!sPb7$_aS@R5*kLKheu9KRl=FB`d=jOs(nk#b+Ykpeu zH|EydU9n+urx$tdPJ7MTlg|3I`n`EDC%+au zQ&=<8I(BY3t-P?DR$g7R)@&?q&7HY759ZOF{CYfBYMz=iSbIWiwz)aK=Bww>^3q(H zYjb06VV#%Oc{_7&9?YXT`HgsNYMz=i^W2=93v+3%%(b~Ox8}~=n+Nk~PJYwoH&4wO ztk)N z++3JTb7ij0jkz^<=H5KOoPnRYqvf>rE&1)(Nnz!*u4QVS%<{SAx#fkqG*{*t*12e% ztARChYaLph-f~*`0PEP%^5l17J~tQU%G{W{Yv!MW{L44tzawe+2qMG_2Wr zSkHX&`}azI_qj>(%ioNDs}0tgHOvk_D;vu@a}R6HDV|ZCD}%NE-16M=!t&no1lOi{ za#-_}<|VBCso<9!;6Ii0O8i-~b=uJ3{JnW&9?jVw#p^ADxo*|DmT%4JpTzTK zux6fFo?BkPdIm~Z&jzhym$0s-4julRz_dE8<+SoOtYdrY(CUmK=kH6<%F|ax^Y6DS zpTS&{d!Acfz`A#(0j7+VI7-UK7)0=x#b0{erfp8qfpuN2<(=id-0o#nmdqdEPXc)e3t=gnZw&p-E>g$}PV5Bcu* zyUexqSJrP}t+}>*4CX$ke;a3*1n=HgVI7;poacXWPYcV-kaM0Te6>H8H!#0n`15ba z`}yDP{pjc7yfFKmAv4cI=jG@W!4G^M{_X~>J*h(eHOT9bbA}eyn!V*i=)WHQ^zUOQ zGtc3x>$SYFd>L}?Pi>t6*7LcwPVx`&`-l|QGdZ<9gEez*F050+JeGeSp|ZRVIj_C3 zd=2Yfbe0e1^dIASGxIEX_q@THxeVUT0CTT)?^o7uEFa)A%*^laMp*lk{8P*)u;$EQ zp6gBV^+;|mtY5-fr?R}Zys^A9_tx3KI`3ee(K^XL$2n72=bc)fS)RjJ_tEkazS={} zm!Z#nu3+s|ZJoyQ&ODe$>nHyb*GXZ`OlyXzb>`;I+`~F{uzU+^o#bEbT(I(~<(cJk z%X7;M%S+2E%WKP9b8jB3KU$vro6QMd&1rdN`P}l{^1|}c^2+ks^2YMk@-@uoWcQhF z`DjjFV>827Gh04`wa(n~9M-)nEH6W!ui47-+VTeG>zcE*mapNLA?Itkw|q3GuZ_=t z7R+^M&6Ar8Sns!`3_tTGxH4AKIE1c@YR}@*YMS~n0xbJ{p>&Y^Y4DY8ot`Mkn?@Mu)GdA zzlUmr`L)*Mzv7%3e6^0bg*Dq6)-%?dH|Ej$$?M|vrm)tT1ar@))|pv8hc(Xv=6N}D zVL8qHbjxjxri1@E5EV0Jp|_m&TqC;uJSOkvGDg*8tJYaiNRJ{!IDNAosx9`nce z-u!>!nv-D8JcspcHpe!VXn`4GRt#wXS z+`-x(TAd!&9uAgoVcpa8^|6zgXR!7m59aqf3(HsL7S_3X^Cooo{0y*W8?BQk2Uo`~ zV9i!qzO;O0ZiD%=(seNRYJjiK6>`o$N%!lslfjyKX89b}e$rZJX`LF@v8{P+oetKq zy>&+O*81ta_OtPMo&|Hx8ooN0d2OBE^3lAtPIeHleFk$)KL2I#?zL>4+VYj<4b1D} zv1`ja%Qu#9&FLgw%LLXlmRUZtJhyyd`O;j$x?d~H8_RoGd$_UAX!$ned{$}wTi@v$ z#A7G0o=;kx%sMmc(CW-#?c35imF11Og*9_;PTnxClfvp`u=aBn%xlT5v#?HWd29JP zn8$W7XXdl9vCd%m2y2F|b&`9>W2fc}R(}R-Kj+rTty5TDTE2vJy_I!p>ok_P)?Wwn z8aL(<)@)nrCvOz5C56?Qz?y$*oy&&f_TW1kEe7zUeDXp`#P8B-*ELd6IT7Mn# z-8GuG)}I{4J)FY2*E7p=^CFm^UnQ)4SXy3Nz6v>Kp!Hf<2XlV<*#}ATuCLr%``IDa zJR6wj;(HFwb$ILu>lsMz6X(gy3s{|H$hl4(a(*qhvQ7i*{iF?jKL2a$bk^yuGr)R{ z(^_X6Iy`T3--wuzusUO4d%XOZx+|dVLhJ(tmmN)Iqz3vd29X7@*dV~qdC3b zetkYySupp14(p!gu#PQY%|NSDTBnBftgeE&W@G&}(&~v-Os5ET^^3Xq|27aLx2B(^9t58Hin%4=1lt5`~L2GLzvJ1?maf-{BQh~!F;_`@H6p`0=)Yfz9+T3 zHFu%&3+VKgkLL7k_UGNr0P9*Z^9+o zrM0}boYtBH%=c1${V-adJ}91R3Uhzn_xtekG0SH#_me-*pNGy*pp#pt2>HWbh(CX^ zybAe?kk^(sA%EBJ$IoPfUkH!ZN#8!smYGX)_6~7Bb8`XnTD}}V>s!Iv&nD#e`azsG z_^aR{_-$T%#o+y~yTh2>?)`T4T6ytaI0`2cgaNBj`3*Yb24&y~U2 z^E{Z(Olf&-c?)aKwYh`!4D^<7%mb`vgI0gE4$armi=T|oO3RZh9!u-k6xKX6kLABl zIkiq^Ij#QOI=OXdbqed0q4VIUV1KMrS*H#i&OmFO#yYgV-e^OgYtrg>Fz?-?e;CgX ztn2MVpX<}=5262u=+o+tq0jYc^|!FzPm*`qpX-Z$1e*uz*c4WuzS>*sWFhDJwEA=F z$H}yE$=PgSiUt+ z-q~gg=JggZpU*e>QT*9W@HfCUtZS!vU3@=jLg(!;Y-^o$=>0jpD5UYpmU!)LOCd0u{f zwFx=*bMmhHb=aB0?C`UD7INOZg}DsoXHXUTTyqt2{{CJI>ov6wIoIher}cUqV9mA- zeXf(fTilZg%pX zi}$X9b+0!tXS@H`<7b|sv->_Sn0u1GN1SsC^Vr?@aj>pEhq(?vn`q^w<+So8%>C!N zR-sd323q%JfOW3vdmdcHF^c zd=HtzSF?qje>R;5@4lylHFIrl&3))Ui~C@C`tW${1m>Lleap=9+`I@KUSnx_1#8aQ z^47eDxjw%y=t7_G5509Z))_5N-!IOY!Mg7`ti3Hmhp+3}+z0a>jpoVw?_X=Lehxk_ z%sI?8pTzHrgP+0gXM;I^1M9xGmiNKDM`Q5rd3Z#ea{}{z?cRTaIor(g-0}tdGCX7a zU6IoA+T5B4ShJ0mr;oHfG|z%LPY!E87nYZnFJaA7hYsg&t<%AJ9{P~;^*dTW{Q#Q> zzB+HnIZtVwrRBBdD_F<2miOiXzS2G;tmb=KDDtkYY*F%Q-mVa>Uw zxzF6s!8)UL(tBb*Gw0?7tQiVeYnIkoTBov3Yn|RY8}rtj-n4nlxw$mgux9HmAI<5) z)-=yx9?Q>&JeaS+Md<9_)2v^cSE0{iTUhsT9XdR=w|szKet>_!2tV^5E#JbLfBGTu zbul+DV9mLNd4G5B{~sE!YXNJW((FY&OC+=*GV3|KX&&S2W!m?)-{%v zFN1k6YRel~GxRWzeH7kXXnw!;sN49NcIfli^keK?<^t9_C9E0xV9q>RKl|9&DT6-< zou%bHtm{fYE;@s?er_&c&cOXIt-lN%{yeR=d}Vn9>)6&h8~7P`zvVuUu+E!)yv+kE zFN1l#wRKk3X<&Rr@4ohHE$=KJ%%gRZPl(5+u=Zzad1m?C@*LKjh2>?)IdcVTA85_F z3LU=BwANo+-ou(_G;ggl{lxwH+|LZ=JUs6V=CORn7Ut4A6|85h4jta>CgfbRwR|1S zHG5dsK3G5fq&UMQnAbRiIS<#&gLluBxiR`^`lIFB;NA22X>s35^D>y7+VU0rY`hlU9rv!ad;@bHexI8> zAwC-!toxFiOPGDmybSs7T-I4x-dlgPPFlqEC&7HiGRt%G(mEB)*ERoLik0Q9^?UPZ z-daB|;|wLNXO-qP@)=$Q@4hbx=5xD-bx-?X-n)(UN6WXt+^gh?ai3FI`#gbpUY=`e zoye`{EKLTgXjVD3W)^F4~k_OQ;o31&W8 zo-Jc%0Y4k}@p;(i(()G845Q`SU_K}5lj1rVto|(I>@3U`toMBS1(=yX^Ql9J_pY&= zR=>B-2qi*PoEN>hZ(HrDu;EhGUS|dX`Kqz`n7c$So61* zcb0EM&Y6=>kLyff9h` zW}cZB<`UMqR+hKswYfKM%;{&x88Y(>*7~`*G*_^m!zP%|+uAyPFn^D6gth2aQwd4g}~H0Q#+hIKDCmM=ax=1cP$);e2r`FZiW zYIAGu&7*nw`Ekt^d^L~d1I+8?KF_}(UV91ib8{&0^<;2X;&-d8vxT+h^b6y$GnhHw z59gMzL(bRQ7S{Dnz9_DMXuAcDAtQOusD7N$Yu@gnajJuvng3pH{y#*XGvxwEDey6FPh*2UySQXq~Nf(r4Ms zu-2Twx~|MRv^q2E{*1U$bx4q@G)*mfT>$qlS&aYX=mX_1Xm%+O| zu}*95&7(QR7qPmo%shwnbDP}q1*~f-;1XKkI%I=yvh-J`)e zqjk2hW=?L$>q=qGGqpUkd~SJeIjuDd>y*}^ukMlcE9=+RUsnSEw2qy^T9a0undh+HZ*y3CPOD#7r?d{O&JxyawdL(KYu|dy$7|LM=~u+{ zY2}&a`8BIkSYDc!ux6+%udi91#_|@{`n0Zn4XfW--kV43&^k8#%IFEKbu!EIkn??j z*0H6zHn-;9Jet$5it9{ay(eUr&n?d_U%;G`@7slSO6ydX*Rb}D*8Ht`4eQ!FSo8GO z87vW**Pfon8EDOrU9;Alg+4#WbL*7m+T5CZ^8o8TWQ4U3v}V{^o_qqR`t|YHNiaJFteLm4?%m`Y;&V8InZF~xzgqd1TzykqXa3DG&tdKP0@k?(>uh12cls^y*bLUOGg!wK)>&D; zg|$xct#O^fJo&cRSq1a!@CMek%)Wi!;qO2;u<|zK+}qwdBdpmb&yDM6=9#&GwPtDg z(!4Tn%<1#uY&5^WyLkS+k}0e;7ooHJd5C#q9;`q44x1U)wahFpV69(B;?=Sy-%f|9`$X|?~-*%R7V7>PamTyDwei^8ybj*IR|oT2mM@6& z)WJM&1M8l)u+|?e--bTd%+BI@=dfN=i;%Okgt-o%u{xNq0%=Z@l`)@So;qOZ{u-=o`A?IuZe041^jQh~QSAF>Eo?2(|{V}g# zt+Rr4-r4!yd{0h)U~m3zd;zOphWv5(`^c5$b;vnq`Gfm&?VcH!>whPHue-IpH;?8m ztoMZUMRA?XoSR#i>+^HDgEePw`C$17>$Q{pP&~Fax8@G!n!J`x$a#&~565*D!F)Dq zSo5rc*>7OYmj1}T!+Zkke&v=gLeBHHFWx^VFFnH^!d#!vZTh3O4y<)1uzq$ovrcYa zm{;c3yf$ym%a_FSR{<8S_Qka*p zW~gD!ys~_4?%*?=m!F9n>kpPEKN~v}SZhu#pPLu3W>}h6=Cyfa-oh`#z2H3Q&&72n zu=ZyP>lvF_rwcjvaQgFc-)698UYHB(tU}Iba`FqYKZkX$MabDHEMJG5=N)0)>$Hnr zz?y#<%=fDb*7_^UlRnNrH8;ULc5x@pS;1PTF>hf$+pCx2_n=_j7klVV=QyPFBAX_h%i<&$!<5jpeh8eV?D*b6ES3!&-9@I(&avn#W+i7j3OS`PKcJ z{F*rn=CL`fJy`_vc_=MUUJ++VVfJ^g3(E_0Wp1sX{@Q*9o_7lCx-!dKSnK!Z!TY}+ zJF{Tk(}j6y?qHp(hk1{7-;0F~uOjmH z)%*4NI-S8vgE@mjX-zuo7&kF&qqugU(xybR`RIr)e9Y|mjm z4~4n0PG=teF)-1ruK5gW?0&Z6{ny0vZeJVkMe^@4r#0skzIkiE&J5ObIJZt= zURtNJd@wKnBktkayfIJzb3YHCrR2Y&=fQk73iA@?`#k%T*TwZ`FlXk^4OagXJB$B~ z`3BZ!}=j} z-{H^Mwy@@z+&lJXFt3HLk>wl3V=Gwqt1)-x*AaTfxu3YoE_H&GYiTZVhYw?tzotGs)+C^VV^; z#oNTr(!4S^u%73&lSu+r?{{ zz?xxZUYM8W&4c3J&fh*>%L3M(7nU#IA?90H=bFA_ycctG70mnC1n<5soyM8hu-4g_ z7g@~L=E)7q-#L0~p1n)V7qG5nY56Lc-$P9wJlTES^_6dg_ssW*{h4`V9$-B`llP4M zCCqE#_tCS5?al8Ex8})v?fZOgXE6Kxx_x2!_Pyhp&BNntTUf8b_50a6?;pJk=ALiO z>qo?6mye8I{olQJ-xqw)WcM?Hhy5OYzdiUq@HY4Z9=f;g*YbnoYqo;5Ck=cX*Tv7= z!JN!vXKvoWx<^CExj$Q&=i)s|@_6h7X3pPNoLXL(D|2J+g1PpeWVXTLskTKNLz zx%i&Hgf-_XD(9);=uZtA6P0K2PDR{Rw^EuVfKtn8NDJ%~j~IKUki8$o^R7 z)8O4R25bH~tTh*w7nUzW&N&;H*TOZ|u&!kjI=nC2VBU-QhsJ(ku7Y=a`(d%Ogf&|g z^4kf*0F=- zTg#J=h{sM~UCY$+IjlWgSf{XjX?bONW1c)}zy53S=e$!`YtBNxdk%wn?Mw5@yf$xO zUE}N{<7e)|yoPyQ{F-g{QPC^&+C2N{xaI=Zu`A2hmM<7_in>nvb(wwBL6A?7Ps{f*^| zPmK8r);b-m=XPtI*(b$L1M9tO4Qu@le#t?Sd=Fkbv^pDD>kpRC9utpU!0hb)>>Jj- zm^?Oi=CEcfVE+03t6z(M`!wXdceLJrwyU&2}^ zd3-!}3G2F6=D|9XPl?ACu+Ccr^L=mfsd1fIFn{l88T=r=7X|ZmH~+N#Iy|-r-o1Ch zny0ePCgePJ8~hNgIe9|7#wn~lpTlRk7yN8pgbw?K<&AkAI^5gN^1+-Gam}fD0c&s9 zFz4sFW@Vgh4s$kM?-Evj6FTfKo*4TTtY?7Mo;TO5&KkMa>_Ug<8q8Z*vn_7LbFE<= zy9xQT_&&DWcjyAv-d5(pJb6-FX9@FMJhp)~XJ;PFlPAYxr?C2S^AgsYmF3A(Vt;C$ z!Md)w<%M|(U#)3*1z+v?HEXuc`jbzO=jvc}<|pxcXIgn-IjubTjCkHDtbA@>z`U;A zYsd1++?fY+@|khXsd;WL%xjqYvwLrW^$gFR8uJQPz6v?N4qONGHM=nP+B&8O!(oIA?GO*^|V`$i8LEPcbxv zvhVxI*s1Kh1|x}zM2Rvnlr6GL7z~Omr7UF`JoYGMFZ{22=D9!j^*_JY@A{l~m+QHo z`+4S>`Fy_LbI$jWpA(m0=~(~-J>5VciaZl_HwfYfQ&ut8rI>TOpwSEWI&phrh8=HYO(~|EFw>m9Y*U}tebGaj} z=bX3>Ebs5xQDc4Kg192C!Mb)~{p{TzJ^DkPW9{q82CO}2#~D||$+zrTlo1!iuC#gG z@wUd8I3>=BOX3Qwe-5E0zX9u>x8(Q49;{>C3Dg5|0@h4QeokCarX;^6Zi#zhcOuP8 zoPc%Sia0sR_S_Sf-?nR46Su@Yu{+uF5m@&sCO;+4i3_myR+8V4--7jAMc=Xd1z5*6 z#O@T!mx1Lzs)>7I_uVl+-0y+q*;0Y!ejMHxz!%_tl+R`z`JOmA)$$o}0oJh<`3-SL z8Bcz6n$;|RVE1f%x_!=1zr#;hp?up%xY;T42 zc_OT9jL8?)YnPHQtofY$l6+yUUlX^}vDWFycW2pHVa>$kr{oLkTsd*{W813=tozdu zM?Wz?Bd&-$;^-X86Ia9?ar9Hl6Ia9?ada-_i7VocI69B=#0|0kne9XLbK`_KBQA(5 z;`n^K*F0GFv#5MaZB72yUT5COx#~#&t75u%#dGY_gx!!c)tC{GRf7{8(813GxBrt z3-U|yE3iH%Yw}y-9<0xS?3&2^bZYpX4_N)0xCd)L?pouRI3>=BYp|XHVcnCK{GK?! z&N3BPpN%#7EwQ`7diG$+%h!y;=i)u$nV0Zq%WoX_c6i?b>l&k*BKNhh_7Z#tc)cg4 zIQLu2)W0)MZyBG@AIyfY@murV?W14JKE^d78fpsl0`7LpE zm%SI)U|nNFeoKB&oZfBMC{7u0F6_ zqv9odwq!5c^Qr*LdyUNNUa>mvRon9fye=}sXIilK--9Rn@DJmZI45q2>(?#cfu;WN zy%+NHe~y{q>qoHm8UM@1wr?1x{~lS^QWE!prB3=Et62w@{psJNI&T@5#QEFiyLXIJ z;*z)}cJEr=y+5+_858G$rJwx2md`)1d`TRCXnswce`J0G)_v;&5BIE_aq^sri4(AX z_Q=UEi7U#~|5&FNtg7hVm`>J#jR}Y8J#DaWd61IatoKoRf0gL0_z%M@^j*XG9~#naZB7$z9&DK$>yqvJ#jX(WlFHV@6^N% zW!yB&MBvF<$WMuL;)3!e`89D%+)+NB#pX@GI&VsTPFxaKl&{HeiF;yC`E*vBHv{Xu zIr$}VP25nvCBG+jAG7)qcv7GIg8Y*Fnz$wIDBqLsX0y3s;smVomgHCD*W|avJ+Y^} zo89J0!TKJNfpxBiIGV%!9IT%i3i3wOcK2!2@;*z+cd`-S5KU>6VHpDKr zXI%u=d1LYm@@w*2;*K&s`EF6G9}_2FovR{l!Fum_^0Uuaz6MK1K7TgkyTxp51lIZm zaYvjamZ^w6akjW+8sg})<`={rak7MEQn2=1k?)D!l9q{y)4=k%Hv{Xs8scav^9$k< ztn+r{CrewtBKE}DGL~tGqh-xc!Fs(4@;l;WIm(0e&+4RLy%$R2it-*TUt0}-4`}%r zhwsl^^6wd337)JAEPEp7!4oGd%;-+Q_nJ1spV>&kny^ak8TM8Cb_w z#5Gv=p(8(9$$E>ynyJ8A$AjhjPO`4_bG9craRJsfmgHCD*W@=~t>2RGDPOE?nGUQy z#H);b%GVJYSm!N>OYn)<^WpnEAus2%3K`*=GA*%Nb$nl&bz%J36|l~mf@ObX-kP`p zYY#10Kj(Mk_vFW`StbGNHBHISiA&-Nyb;cftg9x!0c#IkU|D0gy7@lvaG!pj=KX@L zt0eYc9QS`uoX==2tCN7`+8r!^)+n%iZy^Wko)_eoCU6Yyk>frmAMwSG?df-)uf6k@-CBdlYSkdZw}DU$_X_NNFeJ(pk|E37puu=ZAy-+*Q9vY$Qq z!dl0NjMR7QTFnS7W5rL&7uK;^$jBP2z&}9GO<)=8iK8!#HRaF$#9-||CC)--s2TXv z__Mn{u&gD^?7Ru6H~F*TMPS*_8mv9E#2r}I8*O0gs=<<%XN4!< zZD`MbVa>$k3#*@!pA&arJ$pUnqm9NMhWkCR^q&PD{wyf@Rp4Py$oF8WKYS1HD`P*x z8Cdp5&Qbx^wU?CXiLv(W^WGwC+5ej>2+Bbfxe!_@KF zE-b!$PdEc>pE+3Om9<2hj+x%m&nZD!XrCQgY9u=ZI69_9)x z``?4Lezf^me|V1u%UH?eV9nHlhx;OAkh{KCtv0ZAJYDmOcyeE3oc=Lw*-{ z=#6~0we4F3mi?4I6XGne{7kAMu$-$Z@Nm7rGOz4a57ukpwlR*tQeVzhOnw!7nYRfn zb9I5Gz9){iwP#vNT!8f~m0<0m3BLU7jxMnL-7XK-y^6Q9d`g^y^?DUx`OJ3B%<}I> zjdQ(>>C9%q5@4daypj-44bPSkHeFSmw=$ zi@?M6qI|RCI9Bo%0Z|W$@)bt%5(?gS(D-@e{DrANGy7Ag+j`obq7lN9xpI{hCf# z`jPjzmi%ZpJ8v0r3D$fS{GlfK9s6IiyxV$v{=cz%LqpXJ|yD)+XYYvPu;C-z|7XSa`yjfoSm z)R*_Ql>ChRhPY$i*Xnos8CUz;y0Wj^dMo1O8|HiB=$qyz#2Il8)_Yu7@9_$(`&ona zY;<5ftNDR;jY_bNt%)13?psTKPn;iQV@u+CI@a?L9c;bDV4XLej;Y!;^@e+A6a7p*0~De8mx61@;l<5GVZ7u z-KA5V`vIQq4OnY-#64JR#zz~s#2r}g3r}1fJN7(0$G}o&c&{Y(AtSy!&N6vrbCusQ zj(=#J66eGvaeSs-)08+TE{SX6mbjmebx+)ntbRsaB*xdrR9 z!kuM)Oq>$u#3gY}+!FW1?rf@0oD%26C2>6+>sng!dt&!vn=1lO?m_ZX;+(i7u8CXX zp4k1w=8B0^;+(i7u8AA4UW=Cep4gp3a}lS+IdMr`6Su@YvHL02pN@6UQ}T1-lGvR) zo;SH?d*b*!JBMxH;hz1O`7v=$+=K7HbLIg&XX>Ai{4BTyYj5TG)_)Dw=ZUbM`Ifk! zjy3OU%a>rOKYT6%--{mJ#JuS*ERz%0V9Cslf784LOV2BT`@n01-36n+6*vaV^K%by z9{A9}lX-)G3j7+ZeoNdFy9+HdFzTO;u_^iabbKN{M-AWKhOhfjg4M6d7goQWj&*Dg zU;A{8aRb)(i2S0_mov~3_r&gE$^@48zWNgT?A;Rg#O~7Zd+%?rfqe$+XZ4ggCoYL= z;+D84c9&Vrm^dZQiA&;|xFzn1Jy`duxZJn~%ihX9WLMbptpuxIfpu&{+!6Pb_vA;v zwy_CuMqGgPdzd9y&qGCi4c0Tz29|5xQKkp$SWmvY()NH?|-*ng6T2k<&K5dd>q6*N8GD`8{!b z6V(Ch8BWR1$rskOl*Bc0OWYHCu--fFw^kb&V*uQ?u*_S6b>2GUhxdB&TjCC^ z{q*F!TdhtE*1b)@noom2>@(#{;x=TYhx9huuMhV5PRb2PRl368CcIl!Q73${Qglz+y$0CJ@Z{wC%W6X3oQBQ9^20h zJeil+6Gy+dj1Mezl0R6T0<3i^;^dX0w$xq17$uEgpu$)_&wz2(0tw zu0V1mbeGY z{zx5R-P`y%n>PXL*+_#g`JA{V?gPtpNxjv~iA&-dtUU;84-Hu7ZOQM*ch6g&ao}N3 zh-+f^g4K_SQ{tSs0Lz(|&+{eu75O#!EwK+7d49SVsn5XDX9CvyHzmIyzb3yUKY7W< z7Q`i3&wNeXP$qiW#^zw%|APFM{EmE2>|U|CBCxI{2J3Z9$WJMsk)H=&?#+t)hPWf{ zLtf69C%=Bx=54^*PY;$gN_|hhu-;SdA2wE4_ar7x!1`IDB)y*SbaSPV5ec)ja!IORam(_`h zbFhxBz?$zV^d)x9kcv2_u@P0w;-m!cH);clyS@2~)bFkEudCS03Q&{_~$@gHb>E0d3 zN*JzG~CSo%r9I<}@v_P))PgLO|Tu-u#S9??*y2WuTqzWc9@ z71m5loDyeXt)GK+-ZHTCT!D2TYOvO9$oF8a-2l1aciR}G%jqb&doI87_6Bz@X#}5TF%U1V@t5Ew+<|86xO*~^5ZFE ze%ODo?oURXhm7n=L4HfVn`%7^>s&E$N}N-^0PDPE@P{)-enaeuU1ak{V6Br7=V0xp zAipB6!Mbk^`EBrJe|ln1nP^6umpBDW&EbrZUxKxtiu^j{WuF`J+u+Nd^k5z9Lq_Vm znaoeYdVYHHuwKVJu;hg`Uy|Pw#~-sE(!j%5u#T;RKdgl^EoFN0)7i$FQl|xL9XGr6 z83&e(ux3*7YvKkh=UnoA@a4J)>sU93ttAdDJttrtn}Ri;6W1XxHRF#{2CREq29_R# zwN6dGo72{w2bP+`nlHfGPf3|N@UYL6@4)(f31J=EQzo9v)}DbilapT(*MViOhVsIb zxxgn(b#8O~-dr^ISaaAPu%7=4toa_SYxE&6d*$XaKPJw>lf4Z*>@8(#@;k7u%gt;1 zoPu@UoVX-zLtfU~lP@ei41LaLoD(--owo<;TyB2j2&|a|ET0qP&vK_=U1LUm9(%2wqWq(@AcfpsQ-KWO9^bmu!rm*gR0+t>mpORmZUz6XE-v(dy zp(l=p7iNJba#9&=l2G+F{fn|S6u^mi_m{ zZegn*fwj*VtTmJ14|^DV+4GF@IavEFf-iGbfn{t%`4+78JIZ*i2nJXo(iTl7((}T56w778$*11yR60Fy*4lHxE#PMfsT?JU{H^ePi>-WTN3G)-M zj!nTjZys3YEhtlx-xIqf$FZ{B6s+@>!Iyoj0}pE9qgFl=lu+}Nb zufXyQk!M0jnVvGyN@He6e9o)_&yRc!)^#;ty~kVfyO94b&T~(`r@Z@|)rrBnpJ`y( zpPVu+W%8BBysWVYYd>xk;}ksEpTLqYiF@LFRU2Cp*Tg+oYr55}hnTn|Zi(~NsXlQ{ z+!FU--4hSi>*YRgJ!D|Lz6Dq_Wyr`q*b?{P$zH8t_2a;@=Qa86|12L9Ct&^hA_Hp= zIav3n3@m$I6T3CXjQBBl@@Gnkd&(4F9M>hE-)gYdZ@@CItg#1A*0t9E&$@>(`NHB$ z4=MS=>K9fiNKnPgD?A8kY5qI%=V!rPS&$JIav3wBEKW{ zU_Ecq`ZhKJt6vZ|fronmtmmWyOaJl=?8*1RmwzkGecAHm2DbJ(@Nl*_w4PhA*6)dn zjjXrkE5`j-ZL9}NKf|BV+Sqzah_k?w$-%l;9r@8FR=*%F!J6;E+NaypI0EY)#$d_I zzNN(RW|mKhGq9eAocsc;HB0g<%GcyKlyAxJDDNp#Z*Kjx#2r}ovnSteVfmOi0c-y$ z`5E~+`33nU`4#y!`3?Ck`8~0xjN8)sjKJDkOnyq7Q6?w9AipHPBEKfTA-^TRBflr# zlkc{&o@3&aI0Nfia`FrEh4oofQl=tbSnJf3X(%JCnU*pg`NBF^PZ>`cw>7PcI00+@ zl>ChRocxlwqD)PGOWYH?ZKwz01U%`1{G7NXuEBa=d$5ib)_sV!HD6f$g8YiOp^UKB z?8p~ZKi}TgQh?R3h+E3^#GW#42dfi-wN6ZaN}Lmy#5HjP);b+=&zT*^j68?C!16xg ziKCq;L+k@fKH7QA2*+T3Ca1(%$PCYX@{8ch*pmE;{F?kG_)@1OzbEz~BQ@PF)=vbM zJsJ8WKPAqIOX8ZiCGLsct~OUpoD%26Em+TRnU5@=Nm{V(VLu(~dtbZTOzvQO=#00( zzI|=v8^Cqob+*LXcOQKZjsqXG6}~4^jQb#;_dId5hrP#TU_C#cxZ2bFhB(>F{EWCD zF2TC4iu{`VhWwWNj{Kf{Pkyww^&qVGdq#diToE^v7uL16VC}gh-|ahIFZt}$?{C~3 zFz%sz-tffn*X{ZyVEHUDd?o>F{hYXy+q6Bppg^(DUo>shMFZ;5+icMQ!-oPf1{N`6LuPJRj2 z>msbrhnoBbtTkK8^u!*l{kvnWPE4E~G5B`(04 z5!SIKWh$_qhmP{eN#j^qV@BM8HQ$4EA3Rvs=)P@!3D*9Fb!<((u=)*H>I|RvP9E#X zIVr)DJt0oNV}1#iek9+4rH=f(IQQMrm$R3Ebx&&Y8}JEJo%%!-W!}?s>_gyncAMf_%DeB`*a)m+Q}RpV zmihZO*8RXZCCSU&ew z#L*d6Ge6U6R$$$ehPXb<*4uzJ(-HTSiO;rt2G)E|enEasehb!np#$sBaun7&J!O&~ zn=h>S6s&vYeq!IRj)^m{*6fIrbIfmuJFs3~_fzXLCQgYnu-4DXFTwgusLA(~cjr=l z;v75~OWc5UuIN1D9IX3UkY9rJXQS0%-78O->}OV|A$C8vd;->aGvb^wWng($2x~tz zaRb&mE#>>^SjW2atxg2iu`yWpry@V8Et7%uIu^vyFD#RQHPf+wfn_RUccJxDfVH2r zvAxQPOX8ZiCGLscMOG&!PKk5klDGnEKQ;L+aZl_i?=Gf!iBsYXto3v9OX8Zip?phz z`%9b4{mM8c&WWo_#?LcruYl(pSgzOY^4=79`28KQp6&Qjlto|dt&!%%j96KUlX^)>6Ml#!15WdUJ=iKu)!U{yX!0y6DMHJSH$rRv=-u? z*xhKEk~q1^YL;N#^ER;b>~1!{CT@v)V*fjPhPYd7Y#dmghY46dQw{%q0r?gAJ^Aj| zvCc5|HtRVBYtI$=E%_d-*P?2TTd)hf2bQr7SnA7j!~Mb5m4LNQ2G&eYnUc7oOig}6eoKB&?C!OBW8#!JCoYL=;ufs; zm%Go_n}8?%lkdTLO@(#6@gJ=pcfWmRC?7Dc!8%t1*7_ZB57sm0$&Vhid<@o1LVgu^ zBV3mTtY)^rsz!}kHey7mUF z*S!bpHFb{|M_{QbUw6dhr^E$VuTcfonjKiiUW=c}CM9TUP?sys+jo zu-2?7Bdi%8e0lF{9=Ck-x3Q*N--I|L&cX7v>NktKg?0v-FW8YbJv)`!JlzkohGt1^H$0mpTg1(!iI2 z`@q@JIR9YXH}}NY&qMGdu=;WE_dW*uLw*|k58)SJ?WYd@Z;r*<$!~+d`f=zX@GW5X zPVo$h?P)dwQ&Y<4LF=c&7M1BdDGjKor8Z77Jpi}U?3j7YZ3we3I#n0HiEUfo$N?d{E9+79J zd)D$1SoTEfB*Z!RLiqAtUyxsu-xEjA*}7t|j?IZ{;s&h!^yDYr`pJlMu-2@Jdtx8* za=r5BEnk53y4U3Q#L)}ZPYl+%a^ecCdsUO)kl&LZzi4$5u=bFXUyxrB*OcjrqnD^p z@T5=T3aouL#4T9P(q~S^8GhNureJ+9D8SlhNq$TDjxy0JmQTT2M_A@s^)%dHVC}O4 z>veC*mm5Jd5m@_Ah*Qdx#8t=)_bK@vyl!}Yx_?;x1gw5aeg>Ybo&1XYn*5fy18Yt9 zn#~mxCtzKBN`6jU5;tJohnD<~eD}J|6@fLM5J&$szXNLz*}u%s!TO9U$gj!w!Iynb z-WbOUH(;&VgHH_44fk*31gyQKV3|vvIT`sCaZ8z=*!{=G#>5F&>(}JB#64Jh^I+}S zy=i_5#<3lqdpU6d*7_B32R>oy`1kvgw`@-`u%3s4xC$(vX=||Vc|*Pj%Ur`gzinI) zmtY-R6E~D;$@kPk!<)jU{e~J#q3L<%t_&Pn^6@dE$oH6DR+r zJaI$piIe|Pp12|Q#K{MgCvJ#6aq=PMi5p^1oP1>Y6s&t*klzq{;>687IVS~iL+pu@ z87!ZI@pyEL{Scq8$Zv=}aWcim7Q_v)Cr+kPp12|Q#Bnt98O%?s9f3*r(i*F~OJ4f&opnaRfHV13RMLLzOMXx6DdT3Le!yBY0Z;k~ zzU)asenZ@bj9fcUempDH1W#&$_1fjc1!YR|YvP77o;dy(%>~xEa`FrE%iznp8uDAP z_9m=*(vvT&z6a}EZZ;b$EScdfO~+b4fv;oJkdZyir(?|*lrO>R*OYH4(*|F9@Z=}6 z)4X6^OF@1O*7^oP1&Jv!F~#eofp^rUh$nec<8RQ6`#e=E?W8bFk(M zu=Z1v-;m#u-v=J*Qzn_)>g3=_eexUP7Od;-Deoy0&tr9jHJ^aB=ae$Sn#qX^%9rHV zVC}P^OdEVzV^4V>GIFlmyf#+~);cx$4OlbUvMPr#GC0!yDVZ$^F|d>JdOHB0h4u&$*iKmLTRJqUwXoKyC{t6W4J_;JDepdIV5rHKy zb>iR;_Z@Lb`I@)^Yi~W}-6B>$4lFeju=bXMb&VPMIpr(z>);RPjTj#^Cwm?TmP`iL z-g2gu8jOV_%c^Teoy&0v9SqQdq~0BLp~kr zTqXH6aRb)gTCnDYwPr_|o-%H6+MmF(KNVPOy3bmj2t4T-taIgohqZ%sY(w0E^_kFz zyv!9XVSYheg0=s8I+l6mJa_PAF5w<5zVzUh99jIBI00)9CHWOt*VTh{UbmES1lDyW z#3@+k&A?he55DwJkYAEtk>8W=!Md(!Y2y^Ez2(F;SbJ!|x|TNh!~PH_%h*~{uS8nCXb5BXuAm$k7maRSzS2G+HdlxZl_24BvDTh8WfK8gLU4X z*n@TLZbi$)fn}}~ti5Gmowoq%yu#uSf2Ihmb9Esz{JzpkRwpLTz|w>4VGfqDGH*eC z8GJco!rD&-)_!WrG~{>0p4feEoJ(p(V6Br7r(m5cBR>aApE6chGX+@pvn0PJ?!Y=% z57za%m91t>oPhOQmE<>I-M1F3J#^&vvx%k#%mCi%3>`YE=yya(&N(Kf~jSm!Os_vB~WTAdE8bv&`#&YsmVaRQe7 z&<}AZ@4;HX*wOroxFJqKhgPrlp5{1mL`Gbb*IE3nQR?P~KT#6@7)|AsipZEOS9J#4`;ujD)O zJ#n&|f-h1E%jGvbOk+r#Q~U|p9dj`p;9 z8?ers>}C0kI0x&s=z>4=zqi#X!J4VSS~J?mY9_=@V5!rCb-kYaVqdG{!Mc`cKjQ>E zxqpePkdgYH{A_=#*@3mDCr%C+eHojAr8l{E3i4a>Jy_RUeBEkR#5Gvg7=6PsIe4;f ztddyWpYwZveZDu1`QxC86D;)5)c5@%rTAt%2eza+mV z?m|ZPIX>9#{Q|7>da%}y4l&M%Jy`R_p_ZwLJ#lrI<)gzbpAc7prMHeaJHp0xVC~Hl zM@QP3Oo%h$3M^xX^GSYo6x9b$>JukN+t`BGgD3lNjE${`qhoDs1J-7^3h3_ufUpbh`Yc;{@XUTAdXI^ zI^ani;ts6O8Bd&i$7*I^%@o8HWjt|q3gwAAuwIw!yVg%Z+y$0(6{lL>gSG$YG~+C= z)3|4_`dnk4=4|w?ePB%Xx&cISfdTYqnZ}@iNDWP5jVtLVEOqo(G4~>2`pnX;)1vY>*tdy_)@0{EPo%$ z6Gt~%{fxK@EOYt5Qm4Ji>i0K~EPELL&NvM`oIS8!(}K7nZURgFj{N8r8=DYEx0;^? zz8F6{s|fsO^jw2=9~#Pg;^H=|;{(gstQ~#fhPVf7&FFT^Bw#)NS@30_8)8o!-(h=| zfMtJVpVQ#Wz7@fj9;(2@{)de0c^7>7`Mo}{%p2Wl{iI;&dAJtjS75y^b;wA~mhv6t zJ>}ERYUacRcv6%6mbkdfGU?q^hqwT1os#^TxFzn1<9n>8uzoF^lAjZo#2xqo?3H{U zJHFTIBw+0)CBGoQ4gT=GGRj2v*|kW(S|=mU!Fr8q;)XIEaZj1(k7Lbea86>d*2#iD zoI~P{IK6+&OV4d!IVU}_d%$XzVEz782iCPD4;mN56|pCd9F} zrqiFTw+O7g#pE|&y-$Vp=T;?uF<)5yihN=9n@21!tbYEe^-vPm#N}hQpV8wsR# z|7Mx|@5a#+Btw>eDtK%DTqt3o}Uh^HT&Sp^C5X^94mWXfi)vM zssFTPGO+qh@TGrG-1JsQSo6^{<_oKzO~=}UCtq0o?pfo+kG;u#k%D!-1^FfUHE~0k z`gt4M6ML}qDfg6n!7>q8{e(CpE{Oe$W1sSG0c0=DJo%Z8#miQw1nd1+f%VMS8C*Qh>mL);O2;^=i6 zOPmoG#3fkHlH4N|`3-SL?1`g)j&m*a6z(tLjJN>H`5Ed5e|WYNcf_99ywNx zGb3L|q~zzsC2>Xhn*5fyCwBj)d5IISzRza=vGd#!7jKQd$!D7?usm}*^0T)s1^FFV_CdzxGfbP@M+I2xM^mOvo`DHi{VcH5tcY8%-j5!v_0y@NFLM=O-T#WX zA?}Dhv5Uq!a!pg>oVWn%`RTygLpkHL$r)(DdNw++=6zuKH(BDDERzS8=Rg6L{P2AM zu-;P*aZCAlW?Op&*1QL6Z*JO{k@_idOWYHevsk`np4HaafwjH|YtPZgjD28vre(9) zb%|!Tu?blBCnIi%J7OPL_NSi1*4}|9J$!s*d7n)J%burTy%#d_bMi~#nz$wIz%tj8 zc((WCd$8`mo73is!1BGOsRh1{1MAqBGD+}dT?JU{ROB~-Wj{O0M01Vx6Vy+^y2c8u zbz1T}@`ZK(qq&U}u#OehObXWe8Tone<=!dC7uGsm@R!83@PUuRTB3Qz`onu=;Ni>= z=U|<;AioU0%v+J)5O>6$IGWeiRf4s?2kSE=ozMIXtbR#;1(yAhXJ!+4HJpu(d>?py z_-_8Ort};WCt$6UlAn>ElV6Zul3$Tu2Vd^}hWw7$6T44XZxLAgiGwe767n>J=X_c&PnvCF(da*5_mX2#07Cf+y$1gp8RN`v8L2X z0uP_t$uHRd^q7~=Cq-cS*-#a6v&eX#UbQFAM&M__o;ZrfjQCmLCH6v1@*DCy@}ot^ zv64>$OPzxJiu{gzPk!JWF7@r#Z3#qj=>jQb$Z+XgK6i};>6`|PyI_iPLB zBmTqEI|@hp|^=XlCwOPXJRCpE!(X0oM>8{%kb^NVF@ELi(VmNma2 zPL{K=9z4k}Z}|+YJqznv3d%$)SSA5$|JjOGvjVFhtz?{mrKX(KhI!>NBcF@1Rjkj3 zI9iqbHLZsZtaD{wupTy#v-YMqji{16IEyzgWxW?T9`2TwGr{Z^_!$f0x=C zqjiiEu;h2zA8QPJ9=HlD_d>O<^&qVK-+*;3(U;8kVD*#C=E?%g`;-SuMxNo(dX`Cu zJLdJR2M^Zz)t7B-v4QywSg&bETx@9bR$$$$hPd0v#(LuJE9Pe#+dUp_X7g6W+2)q7 zh&^$#1!V%u_q09xTT*5#o2%Hy_M`&qdOdNpt@+V*#zkOx-Ztb%+f#Qv-6|KN=f&I1j|0GSU9l zTNZfejo4GBI>7SD*NrRUF0j;zzCoG5ga6IZ7cK%1dv&1YJL2dd$_JKwa`1RBd_{g{ zAXu*Z4{+}kfmit(p1p@#O;4O0VSW=>zW>v)f23tRadMRT1#tz|XKzE?5qsk3Xv-(W z8F2yD^IVbN5O>7UF;tT{BQA(5;)b{*_QcV#RG&B_E{H4Q2CQr8h@<1IW=32PSHul* zN9>8CZ&}TRI3q5I8{&@G6GtW0B=%rkS9bi!cgpvO0?Y3~G=X=JGe*7#>vJhNaU45* zRtM{IxFPn$S!H9RZ;xY#&-Q_(P8V427Z29CvXian;ycC-u_sPWnKt>pW%S)?lb;bS zENho}JFtFl(-TLhS|$N&CJVmwRuOl^(P`FO7I;`AaRb(M32Xi2M>e)QYkXGpIo>zV z9(mE-z_n!(;)1vVYyIdKlqash@|j2eer0sQm>=E~i3_lvlP>u3ew18jenwmnS77a- zA>R{c4Q0TSxrjY+c9Hemfu;WNH4$-ivDGYy8?e@oercI1u+(XYqhHxv4Y4QAF0ncV zadfGTt-#u6LmXXZV;itui{x_4XT$|@1)i+s3d)1kZ@`n9zoravLF|c(D{ZU?YyZ(z z#z|l~4;@(N%6?;+g194&uC`1<+z=PnSWOR}^l+_l5m#i97J5=ik}bg192? zh^t#{Y;>!QO^7Svo1#UHF@McjaOjh;BU*YX8eGZnE1PwL-i`HHv+JnR)%>qLLFo-^VG zJjvW|^(*jXPl%%j%&&-}2Wc#LGL|@c$a+YKJFu=R`;(0=h`YeUx`?Yk+t}z~8=DYU zfn{t%oc+bdc3|z<6DNPQo-<+()}D(;Y-~l`1eSTTN3BlunB^Pd6Enc!Z6>;(M=nubtMBEVjf7n|5>%?!_*z9fN zj<|Ve%**d(NAHfAp--^voA}MNS%x(Z-%I@1$nv?a14~A}e$QqbeHok0Zkgue=6kT@ z=SRlRX?`-7aY5V=XLFBZhd-}N?1`g!EYpDHx(xe2@94|dVg*?Jj<}d_^oM;0>zS!O zVfkbMt5bocj^vx*Z;Sd}@MT_4oP5&i6kw?@UzcSIn%@v-pR)P|So?_7{r7fQk7sS>2V;#9h(U+}e5m@|+xT8$8f#s9H zk}m?wzlS0$U(*fOh%yajI`%i3W%7F~(O1X%@_V4w#>AT#H(=c#&;F*CNj4|m!nh)C zh`Z@nf3Mk-A8l!M65@=wAg+iT;x6#;J+ZCEn!*`zMeK=_tu0>>N86a+5PRZe+c7ho z=fE;=N1SbEnIf=c8scbso2w%3h?5;G(-3#W$&QxEh#TTAu=MQ7&vv3d0}p)?cf`rg zG#7C}+z@xf(JnT&Ag+iz;$&CLXT%k8N1WuA_q&g0dw3oe#CwdHZ{k`cV0k~f@j~oL z@MZ1Mo>nI#u82Kxw3p=*;*2=j+vXM4c{}oj)%U?4`q{_o7sM5DL);N(``Xx!INQ(s zBCwo|iu`E*F(ZBwSo$f5qXVo?MeK=_uTzG&BaXgdnTFUCN8hweMcff52U;d0t^yB# zF79B~{Ql7XVu814rj@T1N z$63vaxFJqT%Vfk2aYyWlixX^YN9>84)9tfI2iDIjo;W(g{O(N4d$8u4ADQ2Q)sN1i z=OJ+ySUzufu;!Dqjhmm0EccNI>u1aCoY9wm)2#?BnT~uydAL*EMud~Z7ogUq32(Z_2u`wD`HPvTxt7r;AaVJ*DIHu1Ec;l@WaFF z%-hWdXO`{WTzCfevF#rHXa+a?z#ku8=h{y4^9(%S@LxYM@F$1YPYk>odr3PMR7`xoSD-5qI4V70Oc-7&*u0HS@!|NA^*R=gv&sMc5dV9g$hqI+*BSA@U&gQak!tQ0{5lJMeHFjT-<|vi zetmxq=gx~z82|rs`4t7v$FB?Hzq^@da4~-Awc%Z$Re z4zIV#giikCJO1tI;q{K;_0GYcP1<&|&v^y@)WD6TXH31}f` z9cVM?YtU)XShFQLn!o1i#V~S`Jzp+7Q|lIsy6~ z^kb-jE`_d!ehanG-O%&UtI#{p2hi-#q8=1O%RwtcYd~v5>p>erTSL1+dqVp`2SKMn zXF}&g7eSXmS3=i9H$k^ScSH9>k3vsDuS4%cQ=h|}Pz-$*S_4`S+7Q|r%ArG`qo5M{ zK6F0RK$k$bLJvZZL(f64Lm%_lV`x!mWoRwvtI+n)?$8gROQ5Tu-$KtouRKuR}*cr$A>x7eY5c4?|Bu|AeOeV~U#w%>gX}Ed^}=Z2|2B?F}6P9S8jg zIu~l7OQEZv>!G`$hoHxy9(n>7V4nCL(f6~g5HMy2hIF1Tz6`m1)UC^2Q|>8PzOB<&Hu&}w>-2Zv^R7LbTjlU^eXfwG~2(i4^Ree1RVuk z5B(8(7hmL?wg>Hu)hF*a_gl2V9-TcrB(Av;?&{ojC&?(S)&;`&H&<)Tn&>x^D zpl6{Mq4%K0XPD}ihc<@}fDVR^guVq`3Ec?Y2R#B!n=;kS0eueoJd{G~LpwlwL5D&| zL*IoihOUS1f*yh%fu4q*hhB%?gx-gyPMzvzf!2h!gm#7Yh7N z9eNOY40-{26PglDb#p=sL(4+zLYqOmK>I@nK_&Ek=sf6B=o;vD=uzl-=s(a5Gfs6M zhvtJ8gI0nzg?5JagpPtvgnk9x4ZQ|^dM0F{<)D?JHK28&jiGIzJ)i@jW1y3vA3{He zE`hFvZiDWH{to>E+Gpme?x)aI&`r=?&;!sD(6i9%&^yp9)26ybpcSFjpk1K@prfJh zLO+Ergf4-84c!FY20aA*9eM_O5&9SO0W|k4Q{4j4BGB^Cs?d|rbI{AsThM=@nP$Zq zfYyRGfOdvxDQT?4%hZ7};(w=Rg)Z4EhfA1L$n%Jm>=Ga_A=LUg$yS5vYfrhhBr; zg{FQS`wA@stpjZW?F#JyeFHiM`Vn+FbT#x8^aeD;oH&Qj!cYP&4Xp^R27Liq7uo>Y z5!wyf3pxNg5;_Sw75WkM3+M`{h5iV=11&SxRJRe7L;FC7LH~sQ3(Yn+o-NSA&@#|! z&|1)!q0OOfp}n9IItBVZbT)JzbTM=}bTxD{^ceIK^g8q|^oe=!%z>7Nz5s0v<*o1L(f1jL9avaK?^KA z)vW>@4Sf$f6Z$oDE%XP-L$5$@LT(ZC55>^B&<4;Z(ALmS(0d(1M@Ed4?M3Ptc>#lhE8tU=7g1Py#Ittpt4@S_{gc zZ$i&Qb1jKyKC~8;K^sAvL3={`LkB^pLT5lfhJFTJ2wehQ30()>4BZah1N{w}e<@sF zXhmo}XdCFe(CN@Q&>x_GKp$TkS!gL}b!Z)E8)zr!>(C+4h0smVlhDi1f1vlEcp0n- zS{>R5+6?*{v=8(%=r_>spbmNpdJTFT`X4l9S?mwAJhTaP0CWg+JoF*7=yKQ(XftRJ z=)2I_&;`(C(7&ODm&d&W{U4M<>qDDDe}|rd-iMZ30iQ#l4WMnHuR(`G7eJRoS3@^K zcR>$9k3dgA|AF3vK7yvLh|hb_+|c~cg3w~nlF%AZ3at-q1?>Rs4IKa-2b~7}9J&;` z4r-wXphuwhp~Y6h-a}u6Hi5Q>c889Jj)yLWE{A>#-3R>zdKP*cn)P!yThKDlme9`7 zPoQg{TcCeI^Q?>>pBPpa-EBp*NwApgGo<>gI)FXjN!UXdURw(00(V(6^y8p`St*LYF}| zK(|2eL)-ly?&JT*-CKZLQMG^nQ)|yYyUsb(A*H*!rCUls1SBM+q`SMN8$?P#KtuuQ z6p<1TkOmPD5Rq=F|993pbKmddyPy5y^*sOIKdy6qZ$8{BXU&>5Yu3bu21B1i`=Rqt zbaC``s3=qcstvV;IzyA7PoZz1ozPk6A*7c;TR;h*x1fAbQK${n6&eOjh899=pzY8v zP;5zT15^Qe7y1b54E2I`KsTT}&=W|18|N-43se9q4poERgW5qoq5jZFXfiYx+6L{0 zeumCMze3lbKcT-MtrX@|P)?{i)E4Ru4S`ld>!I(VpP-Y_W#|TU7m6#5c7ifN*`WeZ zF{nIL7a9cRErW3j>I4me=0TrBtDv8t1Z6P}LlvQe&}}HDoT(*)QbQe~h0t1P7jzP; zS{}y@)E@c<+74ZS?m^F?w<=(s4%LMkLoJ|T&_rl4^cA!XIsl!AQdUI0q0&$#s5(>! z`T*(yt%NQ@nJb~MLIo?MPeIqAq*bu5p|Q{uXeIO`bQX%Mim?RB4Rwe5LPMZWpjpt@ z(6`VQ=m2yKIuBikZb3#h91~C$C>K-`Y6P`}`az#SGog9VVrVOL56b=y<~7i9$f%C? zgpxy$+6?W44nRLczd_!bIPXIxpvF);XdpBanhec@7DH>H-OyF&4wR%8 zjvFX5R1_)&Rf1|jO`&$s2xtPd2-*ytf%MuqzM%q8MW`m!4C(?6f@VO=p+nF~=sM(m z7yT4U31x!vK_#K8P;IC_)E$}zErm8h-$RF?-=LRJk~&BSm4zxpHKBS?bEpl}4eA4p zg2qFiLo1+N&|c^gbRD_{J%RMPxHg3nL8+kZP+q7Q)E?>yjesUYKR`DiUp*XCPS0DL8S)n{oF{nIL18M-ZfOZHG=kFCe`E+7)^W$_C|!-iE3`b)hcMaA-U< z6jWWKcz@Ce#S}5NZu|gcd^^p}o){ z=sa{AGCn|hC>AOTHHX?j3!oFwBPiGy`xmMLwS&e$8=!5_Ug!#xstLv==xt~aG#Q!$ zEr9Mpfu^V%G!U8xEr$+4m!Kz5uo;e7s221g)B_p_O@|ghhoIxodFUDB`w+(tR1zu& z4Tcs&%b`7xuQ}QSDh$0`;f_{ZUt#NEZxuIfEHRvO#2h<-L2Tg`%Li3=-&~j)s^ewan+6C=}4nfDEGtfoo zDs&UN2R(saLS`Ern@}{A7)k-9g)&1qq5M!$s1#HIss`1D>O+m87EoKL6VwCh2MvKn zLF1vR&}?Wvv;EU1auC%1YL)2K@Xs3&}&Gv#W4oOLUB+kC_R)F z$_*8SibG|fN>FvE4%7f@3blgTLtUU=&;V!{GzOXoO^4<}3!!DuDrhaV3EBbefeu1P zp;OQW=n8ZLx&u9eohf+bApb}7JXc#mFS^%wr4npUl%g`ez`eUq1LFJ&@&<9Xks6R9ZS`00RzJWGD zJD>y54d@kQbwD0aIw&VJ5LyUrgDyjVK)#MRCZL|sFlZjM650;^43+N$hVDVhI^$dh zRe;`y`aq+gSIC(L216sEPoOE#0%$#S6!LY&xdo~VwS#&? z1EI0d0%$F?71|9QfqsFWLS{FdW1+%ORj4sE68Z#M2Cav7K|eyLpv%xL=qY4&$MFg! zgEBz5p<+-4s3UY9x(v1X>E6hb}|EL$9FNUO1OPO`w_3 z&yd|4Z3xwYnnE8z1EIyxVJNN-%7 zplQ$=Xd`qDvif5l1LcG2LVckv&?6{z0M0{D4`@F01+)&@3mu29Ll2;5&}&ExM4Lfz zP*tcd)B>6gt%bHiXQ4aLYbb6I`X5vpssVifb%44-eW0PxXlMd74VnWjhL%ICp-s>Z zXg_oWIsu)7ZbMHX|6uGtCqEr6CnUqWl3jnH=Jd*}f46LbH&>})<8!fb2#Ea?Vt(Jekkz>jP+0*XeP7@+5;Vg zqDNxvf%-$Epz+W==m}J66s|v^=1?za4739}2Azj4L*{7Y4V8iFLv5grP#tf*K<%NF>o1k(NG2ep*LtjG&pcBwJ=r`yI6gLU=gK9tn zp~cXC=s8q>GWr_S0qPD7fyP6#p{3AjXdAQ}Isu)7euc~_=)X{Is3cSmY7g~>MnDsx z+0eJpX6OXuor>`lssPo38bKdHU7*jQlhCh_H4Wn?R2Lcojf18`^PvsUZs;6z19}Ce znvQ({)q}c2tD*hS73e1P1WGUi=W(bwR354d)rOitEuoL09?(!|JTwbh04;~sLOY>@ z&{60N^aAqF#9R+b1!aJ;LwTXX(A!XX=zXXi)B_p}O@!t^i=j2pLFg>>8>G*|{2Pjc zGD7*GGEgO`2Gkg83(bPoK%Uts3#tK)gH}T)ptI0bNSlLw1f_@*NN8>LRPdz5q;rNOh3>9s6cb}g%xN6W9})e2|@wdYz9 z?S)oCd#RPdGmh0Yq1Vv7dQB}#udVs@I$A)ltA+H&T8#domOyWzCDPk#N%YQIoZbab z33Sye=-sqRdJjB{*;8wz_tHA*y|rXWtG`c&tNV(qEEM0=($)1K>J zXqvHH(~XsyVSJ^T##&7n>+l4^R?TN@!&3;`wFJgaEs1eZOJ@A2B{vRfDUGArTgEvp zwegFV(YT})GA?Ux8&~jD=2fkNab2rw{H|3q{?O_fH??-gpIQgwwl>7Li*G64(?%Hg zwYkOvZK3f{TVy=e78_5rW5#psf$;)QD!kHO8Q6WMrR%29L#9`cF++N+8Lek9WAuz> zVm-4Nr)M)$=*7*HdPy^#Udl|bS2i=~Rm_ZfRWpW^TQq znMZGG=EVd!pWemHulF|J)(4uU^g(86eTZ2`A8MA>hneN{;bwV#q*+m4YF5&hnU(b~ z%&Phdvzq>uSyNwa*3-W+>+9>yM*2qc1AT|tSl?+j)pwa6>if->`T?_*e#HDpKW4Vp ze>U6dr_6TxX|uh4#_XVp^R% z9m{DT4VJT);K+-HC|6;P0~|all9!zR6U2?f#9FDhvsUZvt*`aZtu6XKYp1^7I;bDCe$;=o4(W%j z!}<~Hh_bcZJonIy%+T; zaaH$;YkEN3*F)l=9xWd0vEr4UP`uU?3C&0>bR&r{jHJReQV7dPDTI+qL>X@hpOIPw zjI<(Xq!S?{gNQaViiAdHk=V#8k{J0#oKZw1HHwOqMoE#%C?(!9%81lP6_M6>N2D{V zi;PAMk;$kpvKS3SR->WFW{elvjfoC}?~x3L7g$ z5#viy)L12o8DERy#tu=^*eTvNz87VTA4FMWpD1S>5ao>@MFr!qsBHWssv19wYQ_oi zj&V{{H%^IK#u-u9I49~G7sdO=CDFjRA(|V1h*rjJ@sV*~v@srvw#H-8&Uhx;8-Iz9 zjpw3+@j`Sol6X29Nj;s7WS;Iu3Qtd?jHkCz&eO*z@9A$;@C-1jc?KFaJVT6{o-sx( z&v>J@XNpnBGu5c?nP$B2nQk=p%rM${W*Q%RW*MD5bBu1DxkgXVr$#T&JfpYgGh?)8 zvGIv#i80l))R^x1!kFP%VSMIUX)N=sHV%8%8Yev88ozkf8^3xs7?(U7jT@d##%<4L zmkPPPdbrv+R`SZ2K*9j-A?^XQwge+iA_Mb~^Kzoxwa|=P*y&In7gcF7r1#xB1A< zZ(81hrtlUuJ>KG`*IUkv^42gz-dbjix3(GQtz#zjzGo)GQd)W}J!SAVGc$YJnOVFa zn_0ab%zcSZ*SDPEXUz=OK-&>0s4d!>=jpp~>&E_8O7W1HYt9it`!#w8Q zWuEZvHcxu@ny0)!nrFN}o9Dgf&D-8v=3Vby^O5(V8HjphCW?A&ri^-OW{vvG%og?B z%o+8<%oX+0%pLXGED)tx#iMkqWRzi*jxw$CQI=IDN?28+Ja~QDwyH;Yt#_k*R>LU2 z)hsG#wTKE?t)gP_`ep*FeN;lc`j`l>EhffmiOH-!QR%I|QJJg(QJJkFQCX}JQCY2# zQQ54;Q8}z7Q8}%pQMs)zqViZPqVnQ3pM2J;sQlLIr~=kEQAMn^QAMqFQN^rpql#Nw zqsmy@qRLu(qRLr6L{+f%MOC+cimG9qjH+p!ih9>N6II_j7xlh%KI#MOLR1s$m#Aje z#i$RhOHnPXD^cyNt5NN(>ro$DH=;UNH={aQx1u^(ccOY&52E^6Uf&?g=Nn=Le8a4e zZ@3lh8)?P*Mp+4bW2{8JiB@9YBrDE0#Y*OzX{GSZu~Pd!x6=B)w9@&uSQ&j=t<1jd zRu}UL>iffb$9L1J?)%fK;k#|s^xd&)`R-b^efO+JzK2$G-xI67@2S<<_m|bx_uT5? zdtvqRy|jA!URiy7udTj5L-hBVVzAE=Lw!Pw^m)Z-Uz8Z*^NF!OznJJtBBuD_#57+@ zF~gTe%=M)c^L-h`5?>av+?PXq>B}j;^5qg=`*MplzC2=`FRxhd%O^Jb@{1k50%EtX zpxEatEROk#h~vJZ;)Ji5IO8iWF8WG{KYVYCKYgXdZC`2ez*k1R@|6|3znrlB6-2;a zNhI=D7IFS6B8|VQ$l$LgGWy>US^U*SZhs9?$X`r}4i6;IJM00-=(bC^kwDNx_+WMP|F8&sxtG}h_;cq2+ z`CE$t{x)Kyzpa?;Zzrbu+lv|g4q~RiqnPdQBmtNgvh zYJYFB*5600^Y;}S{r$uye}A#nKR|rvA1HSF2Z_D@!D7FEh&bdQDt_`06UY3+#c}@# zal$`Robitm7yM(yMgLfF)jv*L_kSXO_m3C1{1e1&|3q=uKS@0FPZrPpQ^YI(RG|f? z3o|f7cmgwpH!w>C1G7aaFh?W^d@2$K=7}VM`64c`K%@#R6lnvCM8?2kkty)G$Q)QA zvImxmoPlK`f8YyIFtA({53CR+0xLzCz?Y(IV3nvC_)1g_tQOS*UyGW7Z$z!YT2VK! zPSg*4D;fsYi)Mih;-kPu(I&7-bO>w~9RpiL*T7cME3i!r3TzjH13Sg=z;|L)V7C|> z*dxXT_KJytePVK8znBp?AZ7&)iaCKF#r(h_u^@0*d>%L=mIQth%L7Nn%D^%4b>O&I z8~9ml3Y-v|11H7yz$vjKa9ZpRoDn|+&Waxc=fu&#d2uFiLHrW%cW(1g{G#ctiMue~9SdEs-dATcily6>kOaiPXXSB5m-I z$P|1mvId`uY{6$Dd+?>m6?`S~1z(GzLCy1a(D0NBnw~O2%Tp<6dm073o>svqPw$}L z(>ECK3=wLF>xL|V6C&6@{@xk<-3Be4W ziNTDXNx@8>DZ$L1nZc}{*}-g{Il=6nPlLHUJA%1AyMp;W-vtYJb_WZ3z7H1i>F6JlBJ5Jbwh+c^(AYdmaV5d7cD& zc>W6Z^1KT6_86f)9uey6@rC+%f}#GN*w6q^;?Q7E^3ZTkn$Sp3#?UBF=Fk{Vj?g$y zuFxl*{Gn-{BB6PnqM^?`#X{>mB|}?0r9;;}pF?}of~olvY@ zFO3njK&g_77ELdonNq2zYoPzrlcD5X6zl*;}j^p-s_l-iygN@LFo zrM2gU(%Fkb>Fp(<4EFL+M*FK!CVNdNv%Nl)#oidoYHtl?vv-8D+q*+K?7g9!_MuQN z`*U=#T6M(LL>k(Y@?8(Y@_H(f#ax(f#c)(F5&Iq6gXIqX*kt zqKDY0qlenDF~jV%F~jYmF(d3+F{A9ZF{ADFF=OnHW5(KpW5(G-W5(M{VrWXux#YRq!` zTFeUjddw>O_n5Ej8!@ZxKVsI{-q^KvAa#2&J<#vZn_#~!hB#2&Zv#GbTE#h$S%#GbV)#-6h) z#h$mT#{ObgkG*KujQ!QF6?@r!H}=rDp5Q| zJ<4m^JJOeKkrf}0sbP$z)s~@aDVOg+_5PNEeFqS#%I%lWt-*0h`;;i>YqwUli3Wih z%AB{Q(zGU$mciFj(jJhi%Tna5XiIiYYb!&KQRwmVy4FehMkceg9+G}RsA_{9b#Zq~ z`uZfb;^`)ZJ|(iTwlQ4B`w}fVT2f==H$hTzgie!`m*_*Hp+w&hJ;jTfD#cdvW%v+p zQpsF)lkX7GaiZ>D>GAOn6P=~dk>uM_mC9)7(gq5>N-1s;JtB(J-7P9eRFSA2QCp&c zL<@-45bYqkK$OyO%cw`xmS`Z+B%;Mcdx`E5B{bdqDiSp(8bUOe=pfN6qGXnvOCF*o zMD2+d5dA=On&>f+E!_N)5fvt?OVpKU0?`tp9Yn{7{v`5x+%mEd)g=0uXeiNaqRm9t zh?3cEehr9*6RjpXPxL#H?se0?MO1>Q5m67KNkl7&wiEqAbe|{`<(83!s2ouPqAoP|G9Xcy51qSr(j18&am z5RD+3PqcyP0MQkqS45$pn_p_8f<#q_S`dvOT1K>!=rqw?A}i#Uk%A~E(c44~i24(K zMzn!wAJG+}*F^qkx3siGWr*q%wIP~9w4Uf^qT59N7&qsvM5Ty6BpOe&g6JkuqF6VV z{6sZ~nh^CQnoP8qXamtvqEG@i=j=pPh*}f%A(~0FgXkR5bE0$!-JIVe8cp;i(Mh7` zMClT_X-g8dB3ewehv*WKme@_3k*G9LU7}7z6Npw49VU7RnkCP*h4AHs&m?I{+;hB- zD3&NKNX;3t5#=K)2Krp)lD)eYPdwx4{3*U@Aw$bhig!S2HdmKuBuLG8n(c9CU#lo| z4d@G*3#a82;d0>`@C<4La#QhoT&N@@>MZP1%&2+=sA8AJ<-RuHWv+DG&Y=vP_B@1UEKuyCwB zmXs8vYMLFSY7m-W#m`F1lCKs~E23^h!-yt=UdWv1g2cDZbwI_BEG`Y0 zZ~&A^`Yw|1J`t9;wHz`ujwl;ZVUVhQWss_UE0D^$52&zAJBmVQQ0PzV@ud$L`uw5L zDoa{Jp}UAqf>ix(5_yt)v>Gx+TB5R`y3$vls4J+c^bH}J0a7)M&EU?nSHY)x&Uy+R zc16=V%e05!Q?xUIrS+6P=ZI2Q4(0Imk)hIehSJ^y#fMTqEjr%PM$32)5IR8;ZXCpu zb6lzv*;c!h457-GnuyyfEBW$+RQn}A=pL6P;8R=Kk$hFiSC6PY5$_MK{b+=$cH!e~ zGJLA`T<4kashV;wiz#QW-wKKsZaczl?>fq5JJC_1hO}*!h`0@|QoP4RUH0KxL$eA;Nwe=-A<$frM>+I0q z*QL0oTt+w_ZwKec+rej?FHskD{B9uHMZ}{Shn6|1$EVnjcx_~zofSTni?b4_h(|6S zuQReI~yK+87o;b z)EVy;IW06t`kb+Nz9eo*XTL3%zSK?`l6Vg~`|Vrldmo`{5At5+eL0ot7jCujIfZ7* zS{?+2;T`xMblA~Ula8Y0R@R4Id|{U~!T2H!DB z?ch7DY5@90QcX(Xto8jSeX|3)_J^dV2)!%GnOi9On0(H8TGg~44k{v3os*F`RtUh!%nB%Fz4`G_9$m zZ{TYs={t~W=Yt@%Vtp9YUWQ%(sTw>6^^`s%n@1ZW=_+b9O47Bq_y&f_%3NUpbV%1_)Ku0;KBlG3bB{9Y{XDx|>eE z)kNEf_7R;Yx<>Sbh_4ZMe(cW7!(CsB0-AP0*2SA0SBsKTfK*NM5!D4Qj4 zRCOkwCzl(Vkm&k3O`9v@rG-z8aHS};4rrka?E+dYY0wT_O-SPLYBg%0#@$a4Ptk0U z>TAo%w}I#YXs68OXOOD%`jYOR4q)uuFGK%2sA)$eT|~SSlAeIn*lFc<)4tQth|eVv zeCK4mj1>Ag#>q?4m!EufLF%e}GeWP+(2f+E@RX+AlD?l2`asgRXEp7aqz8xaYk88= zqNZY#b1d9IJinx|$R$=1_wlKe^Kwvf8OlfA*AzMmA4^rOu>rn}GG3*2mX=-8PWbXl zx(q5TNza2hp`^5+a*~RHsz|B@swoK{@YU)`>H?p-qgam4IHTcfBtt9a#q3bhZ1_}N z(k^n(0iWQU{ILw}cEi%TN?L??y(Klq2&}ez3!bSSB7J=AoZ_B4UrU6ws!=j@eQ$hm zP!gxuT2hOji*7{Dsy7`4sS(K;fv3n6JW7Qdi_cN*ZxQimwvI;D8?c_=aL|`mBr{zHLqUs z$jWP$wU9!MiO%ZfDp{Jdda33I&g!L_GdQc4Yh|d@>o!T^)k|J&XjdPq$-+}L$^tA%L zmeiSi&XJ-*2f(N1tO@42XBX$IQL1lniZ`tlk6}Ds@yP!PN)wx%GYQu|+<4Dh^rj>K zLgeh1Id1~RO5$_MPw=U>4|ncy)*{u2#G}t?q)=l!k74!ES5z(u3b^@Y0;zb#$yb+% zb9P!%#cM|?eodokak8deDMf!!I_Vn?QoS=P&cw>+>@C$h`3yFm@=KH(=TMo}>Dg+0 zcFM>reLOz%R(^`KC1mJEklMDNKx*&*h`D!J8G08!RhO?bx;~?z>q`i#EaSZedPkDe zF7Ha>e(#L(?@Qma2kyC|5K^de%YoEtat)B0V>Skn)Ii&WHLqnyHTl^HBbQ&#vhpF6iScRA%edj2@_c2#iM~br-RL@D$25T)c z-W|k?_Z4!9ea_5dzKoX!p=#T*g47=5x}?BWrSfh33-7SWw#tKeiu&Hxv?Vf^qVTC! zD-BXPx6QA`kC@yV+(JBd@)5veBDdNttweBA!zZ zflqDG1fqpRJeyks-)5Q151>7g%FMvEkfgZtSlN+u6rrjmPlA4tzF$GAjE6+LGT|wV zaa_hr3{vySJfH{C$Fo>|LC8-Y5s@k_C;#HDv@D-5pv|q7ODXHUacO7#yrPu&p1sTfgL(34V z_R(e{UNicEd>26K?%@-n=d?QG)VYexIYANk9#BT2f}ol*v>ZrX3BLzwBz@gLss?;_ zQ^&q+D?|GsRBbu8Jzwiy?r3S9WV|tm*H_Y1BEHw_tdwKOnY`87WHUf z%6PBv^B8L+MZ>4+l7=WZQ7NorZj|wgk&lnd%J6NMp^ZVRot?JYFMUp1De6FJyAh2A zsWE#8NR4n0C^W8^TdUF_b=~+8NL@FM1Lc)t*a48bZuAs)uN%vO%E{0^Aa&jNB}iR2 z{sB57>&NpZ-XdNP<0}WA-TeP$WsK*E|H&HJKR*+PTOs9@)Hhvwaw)qIX zNzJZ#?#R6<+zgrf(EsceedOzSp6?nZ-1UfjAT_`G2&7h5BOjqNDa8?x8V~-HW7RC_ zj-AOtC*)DfcjEX?$QIm>SEUuqfL|q$@z}@I9=WKoZU7OlHah3?8>$S1-jVbk*2o@7 znhxJ{NzMpjZFSDS&Na4Lw{@N~_etM!#EX%{&&2Sm!4`z7*~4B?5*hC&P+CdnK&pN> zK3hf9|XGxxeI5Q8my}aKzv^&+FeZ$E&m&n!O!(+c_Gf<~h7Y)#3a5R*op8 z#h1(5#w!?OkwUd8=fb@t9PLAjzOq)F!s#38&bKos94JGb`>SIm&A@DA#=j+=6I!L+ z7UGHFxYVZZodZO=$ z4ijAT1iI`nopr;-V;`sB zTzK_k1+KhQX>V1)^Rconf8wY4>Pq6dK!ww|D-sz`A#OD_02&%bsX`y=Ct@MnU=5Aopp=Pq>tlqS{@0V zc%T0*Ubub9`z_o)3fDLIOt%zuR{ePsNbQ;ZL}!Vv6LDMd2x5PL-{q2P86^T*JpJn# zQQa5f{^zWzu8`Z7FRP|~E$I=;P~*lcDlHr(ujJ9z%M@8aTP1yqv)^7xcdu#MAxZfV zdR&t8e8d?^YclEDMM+fJL&+Xbi}rYb~XZXOUA7+D`hG5^V%^mcAn(RoV^EKzpN7O zU5f81^hYA+IR90qy#(JiNqj!KP4QlUp2*NpHJ6+@;Y;bO*wkIu>swUQ%pFeOeGBo_ z95X!;AD2u#n&m{iD4CW=%xUncb26vkcbvGNevK!D)IIw7NTIHOoqeuo75O%SRJ`Lv zd~W1i9#AO1H^J{4nD4mloRla(NNw-CplG=rO^7-YC4Xtfzuhn#KJ}i%c#zs}KbLZ! zP2pAh$2evZ%lu{|o~r$7Pzvb_S7$y?^U5)=i|#?%Ofv07D%W|#NIkpoCFTryW$1l` zsy;LnW31|l&*4)PRo$&K-_uM+zN|zAiJT)v9Tn}@<7Yo)8C58>J`o>ft;u&7Pj;!J zmg~p4gsThRzYKSGlkaId_qSB7I-|7skpa)=sH1T#d@9tryQF;1{VjD2HpSBzYQN$0 zGVzp?D2|Aq?HQuG@n+Gs4ZNwv=jS}(S5mf%bH*+wX({5VUgE6msJisUxK>4mu0rU$ zlDHRh89Q+9Q9W@z;x(4>xYat~nJ0DD{T`t$Wawd#+M;uyw$gVEq@HuT3sQGlpM%so zoL$51_X$Ai-rZXu^;Tn6kXo522vS$Br9d5I&hLQKb7T!c-K1}B5ux>x^bvfjE=BOf zRzK-;p8QsnhkQK{Px*dNgc*R0_eps-#nzJUlTQ68zmY_|kG6GnkGxqFx`=2w(Hf$y zM0<&j5%JUNr^&}x1pmqX(96hAjWoX#Id`Rp$SuDOpQ68rteUPbmMA$9kKXCwQ!UQd z@!8=UC37x7R30>5`s#tEN_s_iZ$5%g)vp)PSfYhQP9I+=)2@L}y{)*F=sVn9UnWC; zfKSzmpA2b3Pt{#O=(jT7QzD-8zv+`iJX1(m%Pozc97svN^hA6#^4P><1fS1m;psco z8aXL#1&}(cIb-4$S^N7_gtkjkxSShO+7F3%j`T5ndu7_*M8hcFOrlj3D)39is!g}U zcTA@JiRe7h4I;C)8!shMcA`Q=<%wz$H6?08)Qe~o(HxMP8FBq)Vsun}V->}-@f_#{ zS!Z5nCC0Vjo#sW;YM^GMc*_< zxOhBfhYRI#JX|QBKlq%&=b3OLKbOX54K9PX=s(FhT-tEwH?F~(p6SBH=kGu=q+ zX?5nD2*M{qvCnx99B#Z{7{u4sK)0{u+E3_nXD|zPYtUqUvzG;ayEt{lN*xo#n_!>4ZeCjBxO5~jB z)cvE*@Ku#5xb2p9SOf2g{iSx0&xCgnNUV*Yx=M z=ePM3>Re%{84Ay7oU__{a({e{c#8H>ifcq%?p^Y|Ad0+B6RuXg67vq;NK;o{QT5#O zuT!fJWUUgyr^q?iHkUr0hh;*jx_;vsne#Mr2N|!#OHJ!0sTk#46{N0z-v_C_(G8@| z&hyB(j_3%{Z$vLaF>>_?pRW90zVXpVmgcMqDaww}LDE+kG(r;h(^Q+>6_$z!Rii+- z@5!W1;?~r;U;Fnj%iO>!liCh`@5Jd%V`ORE_H|IkMCs$J7(Vu!AyoAZ=f1A`vIqCD zjtEuvW(R>(-{p5;_zGw=h0Xz~E&2ka>bHjIIE7vWsWon{6_;_3Qt)&2&RtM-&G~{t zd9D|3H9kRok2YOyIiCagSvBXWI`woL-?^3TC!fLKD>0XqgOc2~z6}i-?@IS8EyElFn+yDw%@&8kfPfdeeB3b6JnNY?P(# z2C2FnAvzCI?R=H!4$(`H8fgLz+?9^BL9%=!Jd({4cx)C`obop}vlKSEVo{Q}x9+w?IJzt72Ud-Bt+`~+-tLw96I1yaw3 z<^~;*`8n&8>S^I>@STyqwxH{hwztObh)5a%pQ_7vkh*KhPnbTPYs5eOITxYos|<@i zb+2{HwQ$EjeiHRd#8Ydk+bL%*<1~Enqb=^pD*6LH^_Jg%r(B+ycNk>Fk8r(-UZ6Df z1aYvDyX8FQ@LVqrp;5d3^~&K-_|ypOyiuUu?Bu6Fo>Hj(f&1=5xKIy5>&a^ko^kX2 zc)rV%V1s*?Ck82!%etfnrIExl^MVx0zPI7aB;!>D<&ZSzK30h()rYU7q+ImQUgUV3 zvok|hSKGWA%AswLb7h$`_xrx^)sVi?M9w|t2GZwjo7y72gU?6G?%(kazKk~$@mfjZ zP)@-!!AU>4Pv!9b_yTD=|1GUkm+bO=*snqTWaxU(5J@{hYEPd9#rIQ?I#LFD@h+&0 zcNf0#k{*MmN{VjmQcj|3L>-BS5q%1pEz^DjnlEV|Xo;lLpp}xYfxeOS1hhetXo6>` zBqay!mXrmwUs6HP5lLl0CnUWGIw#5L_m?E`su0fwIwIb68Om>VR;K>a5230xrh!yj zZ36u%Q=B8;bD}g&-FJ9PgH(!^L_>*|68%7QjmXo?O`D&n9#JoldLL&x=)SDWCXlM> zd7{6FQhex!RwQZ+dMVR(0h!-9qrhNLP*N(~mZQzX0sy{nxk&1XdjPKxY z!x%s4L+Aa= z?y_87JxWGtGZPgg;;$U$qOTnCnij7G@d^-sFOpY)!mT55tMNCnc>S*;)qvZI`ycz5 zIP_hlRqKT8<2~c-g}$^GRJ?DHVuq`%5O!D47edS@QY@*TCr; z<7GTvf#h{Kr+(99D1RH0`w-`n6Q!v!*2zyj0rv0mn=A7xffU^T)LG4GKSjLdTpHJ& z*BH45+{gc2xvDhI?_bltNu9ZVOk7hwYB^^oUi`N!vAt@{sTGDA!KY@;oL@NK7Q|Eg zH*&m`ZQWy<4G{$?D1ACA8s$6t!$@56=r?i+sxQ){^d7gYO$S zt35kpJ3H|XNNRI0Hn^?#mZXoXYp|Tp6kM+6hF_!;|pJx zIa{R0KOV0*7pJD`2z5pzRjVXen^U7jxD??=q;NHLa=s|Hygat;nxua%SA{zDQ%^nr zyIfTLoOr5M?;$_c$NhLR_)pckc+da7qz)810`ye+rW38B&|RQcGSsQ5>YdL0is;?W zOm%BX%-7^yZimze%%R7TR)r2mxrt>8=Sohkv^lef6wxLW{`IbfC8-WhE*IDldJdKq|$1psLc>il_&XQ`34f zlyi2ze50N<7>;;q%V!WRqqH9&UL%>d1xP*Z&=vHN^nHtXs)d|$N*C$V?&FClNzSu_ zYCAaXUZfZ*Loa|vOX4=Y1K$Mcdq~8s%XQH@xL*WM08;l(w&K@c)UzoZFAG9d{kROL zHPmV{&qaAvm*a6=3LqEN&SgQROMWr z@~aI}dxnqD_sG{0^pi}>HSLQdS><;XbAFYdv!@kt4SFE0>WPDhCV*7D?9bi0q$T2O z7aliwU48}b$E((zge4TqcYCA4ce&Je@&zx@>?*{Vo$uc6>>Jj3_$awhKaxH}u5+?>X_bCyZgg||F%e%uo|=YKv6a>~u|2Cc@WT`TSG!4lL$l|jX1 zE>2si_T#?GV+m6&q)<;CG@x8QBI4N+&my}~Xdh5~9|x(c1U`NzQ7G@}$Suh=b-uH$ zW^TOC`8ayhTzD(rbo_JrUj^!kiXxXbkG9hJT}w5_axOfwMh=Z!2It50rYW2nsC~2o zHC1;8HiD|jt>jS7kIUezBA$WnM_P3>ay)JW=XW>NGi|)(=aAyPH|W`%3)dxF4fqV^ zT;r(c3B#2eITucQ1NBoaPqfS z<3+9u*C1R=awyl2ec@6>F3tJkqH4)lY@6DSaK6a7oWeOu^)RN$DN>=d=5oJr3g<~S zl}mbrDstBF{+@HVc#%uvTq4KgT1AfMtOTlB{V!MLw3ZP$t@9hX>d98V>J8_MoC_Zd z&adjKF^p%2;e2nJUq|Gp-X~#t)3kZ04>3hf%X8|;@wksOMNYvrV2Yd~a%c(albl}_ z_|$wia%kk7Bd?PDpVM}r^Mbk}aPs@RFLEx<_cv63W{RAm4sCh3Yec@<=BuoKo+5G$ z8lwi?=F5S@vYF%_N5$6{!G;+?oXP6?V7>{z*S(52ZQ_QA4$nWBD zF5yDoH0LGAIeu0J8Y}zDQP6Zr;Yxec6p?EXZpAus3LY7lBBzMFs>Wx!H;os$H14NY z(S8eL`*Gjk>nM)LS3u$JdPFWQ+-momUW@Z6@CR!8_p6xvX?1O-tUX^3M!wSItH8*0 z=6QDHcw9dor6Q-`JMNFMMc>HU^Bwod-;msfd7`=>{|afh%C!Ejc=uIO9O#&&93b_D zx_`anslI8)HHcg;m&Oz>E&I6KB2)wC7wuGCob5d=>&Gda`-tlKCaz1k(n?c)H9_jT zd7Oe1{LUCSZq zd-&8n%}Ycth!S;kL$ecABx**~jc6RvLZXdC$BF(VGP=8EBqb_B^d3~ z?U%lrAoc9g6VT7n=kMuWbEX8Tr!|X$F3Qkapc|5$_Z%J)y_VDlq3V|%_-UZ6csfDl z!r$l8uWOobuhTbrBZaELWTG!XF*0-uNWHbs``lU2Ng+djMyUEO*e#Iib$nOa`36{8 z8Sj6hm%QmQ6Zy#FzQNnUcj3Lg@HB?pqBNjHC7H7ihZlZA97ylAM09Qqq3-*8k1tgzh5Wk3^@4E=zKL zD^I;w&To?+L4LPnD31)+;Zu8>f8ES^1OAzer}cKRyTXNXU3jJtIUZk;I=_de&I_DN zxU~F?E2rQ(M@~BpZK}rN&p@g)P8+T??jsK+%Q6-H}r`ZKa+Ai2Q6o&o ze1|A zGqnpowU%~*La!24J&bdnOnV=`9Fi7g!5XssRd(lB_|*F@zJ6|L&TpctU#T1bQs1(O z!xs{B$P{bg%O~jvyx*8t=9dX+3rlK=P*r;l4Y%dImHZ3X{0$ubZBPEv53djuMrmrE zSQn(WyerXFeAB6Za5d%a2)C77Kdyba znuhBK{2N;QyISk1R*`>+>%a3`c~?-H>P=>U_d6^(LF(7mIh6YW_s(#?b2cog+q&U? zul!AarJR3F^fl2LBJV&qZ9$?BiDnRO z1F3IQT?VOdIQs^Rm%;Z`j)`|#9j^8n|NPxuWN`})sROI|1NjOeD0R>m*>L$ zW;XvCH~;QyxL?3-hceW+9r!m1`AF%9Q1yEgOF(M>o+XMJ?E3N(wIG^Aw2|mGNc}Q+ zh9Pdw4M3_74Faj(^4khhzoX6VauYuF`^g!Hy5({opN?lfRsB{IZ6n%8be_nY-J|^~ z&lTa?kH4|NEy+(cC-Mp+u{QE)n^MyD3V5)b@5F-vXk;L{Es)jBwLd1)WeeCEu4sw?V26 z@{DxbpbJR-Vj=I<&*4+s8*cxeMyP7j;3)T4Eele<_Mn%t26I4O`E8)Hppc{_qdoDz zNnHk{j`Ox4_4}sNiS~n3e)Sh<@pFrCd*6AI@_o5K!tKjP$fdCi6=U4rpUy^9o2VB^ zm9~uNXHavQmfIyT6K6GU4c^|^iEgi}NyJwj+{ZsdXcf7Y`$1~Y+#^ac z3E!QOq2)oUH9CP*n@$0#{jnOQnaydryh^WjBH$RgoEm7PI+9IM#L_LX|FL2G5?Z>~}%KMV{pwsq$ z|8^1gm+DwYS}t>O=xZYNC6jPzop{@5zx{m_a6|^4z&KJ;C+MQHWo{h}F zw*4r#Z5~J+Gb@QUg49ajevle{PJoWd6u%PP2A!6^zd&kxopqXDq|Y}KUvH4JmbXAE zv@l4ORvV$XtdYRMllZrC0;HE8}sUxdu$z5l?+7m`mdo zO=p!;)#^ve`2^^(%$e6kxmHY<5l?L!?*(2XY8#(3Q<@){Yh z$c0-OdxV;*y=u>LTavdU2EG?^dy|2D_*H29cI~I`_uJFMr{+@iKnLai7!6Weeg{2F zZ5z+ccqSNm{>Sq=o(Uer{!lZ)!yq*i3^&)~86MC2!p-$~7RfWbKflxBXMHpFY4J0` zX(%mzi}JeL`vRo4*O!k%X?s7;=Fz6e*5G5Gzevif8t3x3X>Sqn7!hs_kFRFmbTw}# z#us&^&g*(#=XT580Lmz9S_!|PmR;2uzPyqyg9=O1QNNOsc+I>Pd^M%77^sS*3}_eC zR?fR~Y6kCo!&I%(^~CvH9dG-vmYH40A1FYi{;3wF7G1^mDLyOXEaQ=K=`18RU znh!pFFH7^o#%Mv<#Q2|~CDCGGQ)mfcQ^IFxX|*`mbXqdl%m^{GELtkqoLXwwTnIO` zqFQ>`Vp>Mnl89w!Z);g$D`?qaDkVI z+Yfmd+EA?&wrv=!p$*r{z>d($!Hz_(hBiv81Up)*0y{>l20K=(j`-uGouJi(XS}pG zwA$d1UI#W>uLm2W*N2VO8^9*e8^I>j8^b2jo5Cj6KZH%9w}6e)Tfx@STf_F!+rswN z+oO~|u&Afr0k*&133h26n7I4tAVA9`+M`BJ6m5GVBC>D(pmkI_xBUChTN=HtZCAF6>l& z9_%!IKJ0XTA?yr&G3-oz3G6I=8SHF*IqV#LCG1>%73`<_YS?-DH?W`SYhmZ>-@-1? zH^45`H^DB_x40KLq=wegt-v zeiZgA{W$Du{RHgS`YG6N^fRz)^mDLl^$W1;^oy|H>X%^G>sMem=vQGk;?ZbB+oa!s z-K^h)-J;)u-KyV#-KO7z-L5}?-Jw5%-Kjr;-K9T+{Z4-lyIX$=`@Q}ec8{*>hW3MQ z!tT`t>^|Lw-LFT%9?<=;2lXKAk9suhAw3rMu$~b1h@KesCp`}KsGbb=n4SXmxSk63 zXFWCS2|X?BNj*L6DLo_XX+1OS89giPSv@=KIXx%rc|AAm1wAk9FM591i+VxWU-iPU zm-M2rm-XVXSM-vwzv-o5uj*xBuj%Druj>_Hf7dI)-q5SS{-IZcy{T7+{Zp?AdrPkk zdt0vqdq=MadsnXydrxlwdtYw^`#^6D`%rHR`$+!~_Oadq_KDsK_Nm?)_L<%m_Ak9X z>~p;X>`T21>?^$+>}$OTtY-9r)r~%|hS3k!GzP$0#voW>41x6+!(eS=1gzH> z1si3If%O^VVEx8;*nlw+HfT(S4H;8mqmAjXF~&^TSYtM90%I<0LSr6mB4a*mVq+m} z5@RuJoUsHpsj&<;nXw!;xv>&9g|P}YrLh_|mGKSiTgF=0)W)~4X^ai9X^l;=>5MI~ z>5Xl$8H^pU8I4`AnT*}AnT>l@Eu-#1>uHZWep_AqnO@)kqDS+e{0a z*G!K*OPd+NrC@cfteF{HM%tlfR`75$JM2+2C+uZ2H|!NNFYIq-e%PyKLD*|%Vc6?t zQP|(j;;=W&lCXc6rC@KGWnlj_%fa3%cxT>%l%T>%%@Z8^G#TBUsaF3~O0UVTJV}tjB5rYg?^gy;f`3D61{3&uS0rw>rQE ztWK~Ys|#$j)eSbr>H!;T^@2@o^?^-d^@EMG2EZn@2Eit?hQKDbhQX$=M!=@DM!}}C z#=yR1je|{Xjfc%>O@z&4O@_^EO@+;3O^3~D&4kTn&4$fx&4tZj&4bNp&4wE?!1wF$PfwFS0| zwGFnbwF9=BwF|bpwHvmFwFkDRwHLORwI8;(br80XbqKbvbp*Dbbrg1hbsTn>bpm#{ zbqaQbbq02Zbq@A3>jLb2>muv|>k{lj>k8~5>niMG>pJY`)(zMt)=k)@)-Bj&)*aX{ ztb4G_tp~6xtVggbttYUXt!J=Xt>>`Yte3Fct=F(SEZxLe!!lvNvjpsJ%ZA-&MZq4l z{IEY-LD)l9H0*6F7FLLau*pPX*o-0$Hit+Cn^UBK%_UO7<`$`8^N6&t`9yly{30W4 z0g)NDqR0x{P-KVwK;(pNA#%g^5P4zyi2SglMM2mFqA={2qA2VtQ5^OwQ4)5wCZ$` z^nwj}`oKne`oYF{2EfL82Eiuq41rDP83vokGXgfTXB2D_&luP^&p6nmp7F5B{x6R1 zKCY>{@&7nv+-+=Q!8UdSgWYiB+|JI%WOHXDBO)UsBQo|GxPFmWM1aw@Acb1&&T`m-Wc0CpYu5%#$m+PpdofM z8e?nG6uSk}V(TzHwjRx~4VV$T6*FTS(GuH)_Sk03irt3Uu`QSr+lsldZ8$l$9UZY9 zI3>0dov~f$itR=rwg=s@yHJeXjh@&&=#AZrd9nM@7u$;d%0_F*8lAE(70 z#9-_IO0k0&iXFmm>@Z#zdkD*7NASkjQJfn)hPTEZ#`&@1cw6idtcX2|_r@N>2V#%o zgRv(jMMrIoJxP8g;;XTzXd01KR_tlq6?+Chh@HUR*t7Ua>^a;YdmjH4dx86Z7JHH0 z7x7?h^reiM*h%3COsAy&i};ob4YJm-7kXONdhd@{a-ygq&= zJ{4bz8{%i-)A41vF}@t1iJy&|;^*+SHSu%F&qi#HpGV#iKOfuT7vNj*3$ZHme%QT_2N$e%_0Jboq3!H5I# ztLVRo_+|WR`axtx8ovgI;@9HW@#}Cnz6uY;SL0~>di*|q1D=oHh=0d#!VB>=_`mqg z7?n_q@d;aa%mn0^N~pt(gnG-D@DbTX zTqBE)VRXqR;nT7h+$f8~XJrXkE0g03G6imtsqjUa8tY`q_>xS6^)em4EYo9y%!seZ z(r~NHjIYWvu~BBl*JO5lU6zf_vRr&a=D;^)PHd40xLqbOnj0Jh75 z*dYtyPFVqV%BEwNtPtOo72$ibV(gL4!1rY(_@Qhj_RC6fP&Ny{l9l1GtQ^0Q&BkwK zbMQOaTs$nBhd;{Z<4M^9{9U#X|4+6E&&U?zAF>LZkS)PKWlJ$ez6@jK%P~$~iShCk zm>^$?GWjZ$%U7dPz6Mj}Yf&#>hX#2S8s*h!lCQ@!`36jvZ$z_v6J8~+!CCUnI9pze zH_Nx+9C;nimDl4xLG_PZH)HZo5`HhHg z%G+pKBDTug>9-@F&miw0@4)D&c6lfHEsT!pkav;aMrIOuH+d)WIneSR@;edVmG7eI zj@TpLP5)lR_vL%&cOmBj`CjsFWPi!`k@rO0EAOTGDB?fm`|0;Z?3Ev&|2X0&@;>_g z5f8}w=|7FwCqGF48M61~1LV&mejy*EIT&$3K1Baz#INMT^n(~3^|kyEc_`wre1zs3 zWY&_8lE01koqUXDB;u(2F#Y$)_>qs}kMbj!ns^k&#AE19JdSyZCva-wNz6|?h5p3T z7)U&W(-J38N<53<#B*4Xcpk4vynuy?7qK)kI+l@;I0rhVv86xHvHrs}rsGbfO(MCT8O^iMjY} zq62FZo%md$fSVIVd_K{OwTV7_Au%7fBnI%s#30rshVZ4t0<2G*j$0E8@zum4Y)mZ1 z*Ai!7Q(_6eo;VYCB$i@Z;w)@WEW?Y5yrEnkQGs&B5=>MqMTKG+DizC7rKrRt#R|+-tVD-m6;4&G#(c#Zyh^baixune zYDE>!P*h_H7o=Shb**9p&Qxr~>lB-?R8fPo6q~V3QH$k@EqIfn4sYfSRrZUb0so=c zit`kWc&nlb=PR0Vv0@wErD(wlMJqn3Xu}poJ8oBWV5_1NcPP5BUD1tiD|)a)u?u%9 zc4Mbv55B9|i`|NS_@1H{dldWeeZ>LXrRc*C6#ckcaS%UL4B#HcAbzA6!hb4;ai8K4 zeykY5Ud1SWq8P*dio^J+VjTaaID&nOqxhNP81^fUay+)S*VHN3GI`I%OKBD$S@@W}-o9MWfP=CS^9JD|0bJ>A*~-6D>*stx6Gd zm0p~z^r1tUk4|L(UCJN|$`HDh1t=<~qeoeYUS$#HDT~pkoPkr7B^Xf7#A(V>3@T@# zq%6Y%WjS81oQ>0!bMOk~Tr5=1!(!!pyjr;cuTw6>QspANUbz@&DJ$>>9oVGo#MhNw*sScvHw33$MB@`IR36Yfv1!w@juE_cv^WH|4(@a&nPGG59L`js?MQFbsp1H7tpM_ zh#9Krct)UV5?WL-Xj8?ZU6p`YDmiAW6qut@VXjJzd8%aesWdoMr9(-j#{!iRuTZ7o zl`1pNP-WsZDl1;Avg1ruHeRR7#d4Jc=c=4IPbJ{(DiIf{ym+U|hqbDFd`T6+22~JW zRfXcCqgqu3bCnz|d))jeoc??Rh;H+s~2(5v2ydFp-WQ}<%NdO!Nr2QaAaLrL9_A@xBl zP!HgA^&noM9>P1+!?;p?2p>|9;KS-sT&*6%N7RRLjd~m(RUg5%>ZACW`WUWLAIHbl zC$LI=5}#0?!fN$td{TV|*Q+P+DfL<0pgxCBtIy*`^#y!JeGxaQqZ3%?s3&2KItHIp z$Khsm0zR*nW35_&FQ`?xMXkmc)yY_=*5FHO9oDP$__ErF4eB&}MQz3wbtZ0CTd`Gb z#~tcyY*XjrTWSZktDX3^TEGsqh&$C@>{R>k9d$l-sRQ_~I*8rs5Wc4_z#jEg?cUysORCA>iIaR zUVvYz7vhk55q_;+jKk^*{6@V5N7PI4JM}UgRWHZy)s;A=UV%TTSK?vyDjZj@#-G${ z@MrZ}JgQ!Y$JAB$Z*?^uSFguk)f@0P^+x<%y$MgLYw+}Co6(wFi}vI#xG1?UAv)?# zWNakYliAIeht zQJHcORVf3Qlro6wlp(wXcpu9nhM;dS%SMYOYuX^GWhQmsdb~v2fGX`)Owu-@THAz|X`3-wyA4ycEvV79qE_36I&C{< zYCF)P?ZnC2E?$M8?Iyb-y0twtVnnZY7rh6gqkP)kptBL=j4>HQI>Y4_0w zBZjoS^issIc0YXqvJ%!FAWx52sO_V<0;8jfwEg5OF*>SPdysrp#H+OfG&3TWXb0)9 z!RV-&+9C3_5wFt@)084BXYC>KEM$ynN62N!&)V8iayfG5)sB&G)*dF$#^|V9wBzJC z5$9@;(EI~gFKLgGZ;g1H_886lhzqpG>2HsChxP>h!ibBsC+Y7**52Av0Xe(gE(a^!!yYR{7^F*@o&?FI6Rh%2=hX&yq} zHPUj~LDa($AJI;dbG%1fqm7||6gl&1jESK53W(gtu?8^mw4Aso>b;CI^TIIb&} zEkv7c5!!W&F-up0*}5f|qg#r(x@9<7w;Ub1N}Qrwfll2@6m+Z5ty_(vZVgV;t;Is! zI=oU>g+;n*yh*nnD|H)ig>EBO={8}tt_GjcZN_JHwfLfL3%;bQ!$w^_Ht8C0yKXD) z&^6-Qx+d(M49G^)x=8dIsxL zC$K5?EN)9Zhi|5y$ClI!xIOhEwx&iWvaM1lVOwepzLgq>?Wqa)cB&jZQWdx}RfV0Y zYJ4X(8M{(7_-?8WyHoY}UaAp$Qq%DLR5OmGX5x3LRvb;WyLKLfATm*7nO zOuSBCilzElc)h+1XX(rF2K{U-)6c;h^>eXYKM!xx&&S#N1$eW5AMIu3wG|^_6&seg!Vpuf)6btFS`98t>Mx!F%*;ajAYCKCG|8)%t4O zq+gG<`VH8q--xg2H(`^$24B~2#%6sjw&=IuTlzZe(AVQmeFJ`|--@5=8*xp3h+b2blhVo#E%R`xYtmO|1`|NUPB3fVwj2h4W;<0VHO@Rl;OV& z<=AJKjh`9jV83B5er}kD2MzP_3&R2&Ff7C`4U2Hluo%BGRN#EyX z9x_zow}ursVpxga8CKz_VKshlSc7ARwfL7|9sbu)h35^`__tv_{?D)hql_Ez65}Sk z)L4VD#?2UStVNk|3(Adkm}sm=g|PuMj9W3&*oYQm6IzYUXftj@yRikcjIB7u*oIDH zJGzV=C>T4@ZR|qP*o_`z4|$ql8~5UL<321h_Tp8>{W!yT0IxCjVTrLH zuQeXTnZ^OU&NztW#v#1PIE=H6hwx_O2+lE%;%&w;Twpwmw;RWCq45abXFQ4%px)_5LAj2G}b<3$`bMl0DP#z{D4 zjKLp_ad_C6fIk}LIBrzn5u*x^8rArVF&Y1B)Zlre4*xdl@q*Ea|1+lHMWY#`O__L! z$%>OqcD&S-jWMQNj5Rqh&g8^+lYj{(5oIPX%1u5@H07hh6hNgZh$>SElS~DeZkmo} zQz2%WiZItyj1JQboMI|Lr)eg-Or=<8nuS-I%CN*#j@O!IW2tElUT>OADH&yZqq*er>PhBnfBwSrUQ7u)Q6v&`thLYAP$-aaM(16-FY0soP95$B~vt2l$FO~TvKVsJrP9NwOmfD6;) zct@H77p19iS(+LjOiRX9f$AUWR$;<>*VFjZ@R-V1D{s^rz3mK>B=~mc9TB(ih_8 z>5FiB`eM8yy#foN)2nf1`g(jQeFLsa--v6|H{oOHHMlN)Gghb9;`;P0xGB93YtrlSx%38n zGkq(zr#Ir;=}p*?-i+_1Z^NGS7JNUw6+cdIL%q2jt>zB2nLE*L?!qi{H)flAFvq+L zbIrSPvUv|W%zJT)c^^8>z34LUN5Omm-R3?N&Hd;xA4IQt0Q1a)=ra%DRP!+An-8Ji zJc0r9C{8nvVbFXSCG$9j%ttV6K8gkAV|cmwI8Ha8z$?rrvCw=9uQZ>=BJ&x%$~=L^ z=CgRU`5ewLpT}#=7qG;95wA5zCvm)(C*gJG7%Vl%;eF-=Tw#{;zp@`hW*)NwH=0%W zqFGH}hiqGOGVU~Mu+yx=cg%Wjeb;OxcSYQ9P9uM6HsfdJOzbyX@pH2s51O;_3v(_G zm>u|~*@=hD0=hFqye7koB^f@vHX|QrW(4rMj3Aa~gz)-|0-TjG9dF1e#IlScoSjjO zcV*1Lii{GxJ7Xq3no)``XUxLaGs^IdjB;$tn2qfjb8vsgT>La+9v;Y;k9`>n@bip? z_;to29L`vb-(*zaj~PpFJYy;Tl(7ttWGu&@Gb-_D#tQr;VO{c&DWg7hC%AF3UlzungecmO)%%8Nz!k!+4+N z5H7cj;Qf|Sth9{b1D3k7Qlx>6k-HQTz1d{e}mt*dF~Agd|s8uDCZJXqJ_eb#lj z+**Z|)@ppfx*j)JH(qE7zA1|{V#AMq5rq~8iV;e%PZ5Va7LzrqCLA`Ah zL$)yt+YaLuws9=99l6%?rpG&6Y`iF=D;VN`Bd9 z#|B$Ax4wdmC|fQz+8p?r%}L)BvDqfjydLoln@GP68Dlmtxdj)Ao*?NiUM1Ryc4-n(N;iyCt|m4I{7_YA@< zJY<_k^DQ!8+2-SzZ2`>>$WM{Bh2$S2{$yK3Gam70+hX$XwhBCDTY{%;OY#3~%kYeC zIsRd*#0lF9{I6{#p0};y(f*Ej(YBiAe-WeXYv`kqGoyVi#@N@<#72y_SJA{pOt4qe z%aCK!zMh;IQDxsiqr~VawS6NwDPppH6FJ3RL$5)ONBd^74mlF-wPXYG-j{s~ISo16 z+Uv+>WL;BYCpDiQa*nf9=g=Co%)ux8YQK3+CHf(Qj|V zfW4jjOhe`Ydk2Q?omgP+!Yl0ESZMFTEA6|uXAv?p+jo(EU>?8QFeH2&Q z$M6yRVO(P$$4Bi)aIO6)K4w3L>+Hwzar+6ZvY*5!?5D8Wej1;&pTTeE8*$v8hCkWOc*LHW93AyDa)z~A@s!<;|FLJ|X?rgIpWT6H>`wf{F5rY+ z#6Rs`JZtyiU-o<+=NvM&?E$=C590sqA&kl@!04>$sLLuuM^+K$Wfh|@YX)ACRf0uX zGx4gdQk+_%d=+VEm?E$)~vaBTh=_hGiyHHm9+pL%vy*mvlihCS&MN? zRt3J2wFI|jEyY)}mSJPoa(peT5}UGCV0YF^+?%xuhqG4WH(6`&P}W-fHftS@W>w+$ zS=D$xYd!v*wE-{9-iQg=n^2ZrgWBxPsLQU!)a)&&&#ps5c0C%i8_<-!6@~0ZT$tU2 zcVsu?qU>$BIJ*V!%5KGnv)k~Q>~?%Uy8~ay?!;HKyRb348xLjo;7Il^Jej>4|IFTl zlXCWAOwK-(=k%f?XFob}4xlrq4=>N@$18FU;*6XDEXf(f8*+y5#++fCn{x=~<&5AR zIiq-I&KTaEa~PN8jN?5yM{sG*QQVeu4ByN-jx9MSaC^>4Y|S}^J918ATh1ALD`x`R zbI#)1Ip?q==REGrxqzKH7xA5(=oD6}Ig{|+oEYrRiNp7D60j#nj_>CvQn(Hcc|Rvd zMc$3P_FOf_&6UVJLohi~NOZ^Ks+k1^CS5h4}L1Mc6QTF}^an0=G_Hf~}L6;*QD7_+D>KUQTX{_}=77nhz$g zpxG7iqsc32_98z8OkPF)5*h!F)hKtY!9>SedIfU6aI8azqY9@us?p_GkAhtJ>qhlYw=IF&H z$9|q$v*Q5y^@wjc`pDZH{rINiAhtLLaJyp=TOC8V!!eBSISyfuV+7xKjN&fG7=GY5 zj2}D3@e9Wh{C3Jw9GP+qzngL#N2i>?@28x^u_>qUhbgD=@RT$74Z$|jVz+VsUs_$dQ>@$nB+`Dlhcf8&P+^qT2XY`(c{cUuQM0(oDTFk zojBDgV7^mCztf8Wrw@b9e3YC43^{`sc80LPS%8;2r{i>IAztAu!a`>;Ug?~HS2;_t z*f|rgc9!A{=PbO&S%xLfa=g|#8*g*Y!3EB_c)N2RE_BYvJDdw}k#iy5>0E@1os01< zX9ZR`m*CybrMSeo4DWF+$ED6nyw|w`mpNDBea=<5+_@U>cdo$)oNIBVa~(e9tin~! zYJAkW9@jcI;N#AXSmoS=PdICEgL5-J?X1O(&Mo+ivko^o>+xA<1J*dV;`7c%taUcw z3(jV&b8f?zoGn=IY{dp=8@}pn$3|xdzUJ)2W@i_^;q1n3&K`WzxeHsIyK%d75AJa8 z#Wv?Ye9PI3?aux9w(|gXIQwv?vmZO12k~9!0CqbE@jd4de&8I&-OfY!p>qWHI7e}> za}59KJdC~0as0%21ou0SVxRLEe&#%m{mv8kx$`6*be_U5oTqWXc?Q39PT-L9EPm}g zhr`bE_^tB-jyNykcg|=&Q|Eih}e{<^bq|=DMJJax#(~SRdX5tyA75{MBal)C654&=4wabBzxSaTyOTcw55g&JX zvC8GcCtUfs-W9;7TtVF63gI)Z0({mr9XGoQ@p)Gf*1C$Z&NTyHa+P4cYbL(zD#ce^ zvv8}c3}1DXW20*}zV4cX&91rlhHD;fcg@FE*8<$(T8M3~MfkRBF?P5raHnetcDa_~ zyRK!}?OKjKu1fsCwE}m$R^o@QRrs-MHTJsJ;3uxNc)+y||K+N}K36q<=30;at_}FP zYa#kgFcQb~WIzYb$=^YQ#gXCj8dbj3cgX_?@c- zM_sKr=4!(qTcF2|op{96g~wgp_^Yc2Pq=pBDc5d1?b?HXxc1_NYajmU>cw-e z{rF$k0X*;O!@phqc)@iL|K}ROi>^VuL>R(J!Z2Pc9Ksl31Y?C!Oc2IUCLBh&Fpf&$ z2&#mmm?RuSwQw9S6HZ{Va1u4bDbxz5Q74>1gD`8dHBD_&3#&Tf>-XxUZ9APHjB9!7>VHVC4%J4R!92W?)@pfSj-YLw*#lk$iOPG%p z!UDWoScpr6MR<>}81EG-aJjGq?-!P0rLYVi6qe&kp%NbwR^TdOC9W1$;UmIoTqCT( z$Aq=GPFRPJ3sqPxRO5PKJw7dLz>UI2d`8%WH9`$OCv3*&g<7l?w%`jw9c~fou})~f zmxQfYFErw-LK8L$&G?$I4V#1(d|hb8H-t895!!LP(1EQ&C$ zup8eK_Tc-%Ufd<@!w-dC+#~GAkAwrbPw2ysg?{W64&o=m0DdYA;sId@KNE(rUpR!H z3nMrnjN+HV7!C@D@hf2*hlC^ewQv-Ng=2U~IF8>6CvZeKiQfsQa7;LjKL}^=urPr~ zg|qmJa1M_N=kZtJ0-g{q;z=Pol^I)@gr|fUJS)WEUqS+&6Xf`}puh`)3NH$3jB+RA zB)0}Hb?Y$3t;cw`5oPW)RJhHkbZ4TV~RT$HEsuL-A+t(3#fOCXmEQm z&F#Zg;_dLAHJs*qR3-D_9LM(AF!fV}&ai+ThOWjNGdiPQ+b1%ai z-OI7uU5PilSKu7?N}TIng}1s_<9zoTyv@B97rNKs9quZ;(_M`f?)7-Ldjl?UZ^UKp zO?bb%1}oj0@d0-&u5@p~Rqi@`#9fbT+zt4sdn>MUH)55$37>Q~<9hcte9GN|&$?T& z#@&X`x!bYU-GMK-J8_G<3+vq7_>#K^>)pHX758r3>fVE|y7%Ji?tR$o?!`CU`?1A+ z0JppQu+`m=1b*s1iT`q+!anzD{LFm@``r`xx%(^*xXCvcP5^9Tk&tV9WT1GF-pwEXwiX}icX9X1&kF%j1#?>Ao@@y=A%Lkpi&H?N(|v; zVgaUz(@`fDVyak#da)Qy;tWg|OE6QMi59UGt>P@q63Z}KEXQ1NHcl4jpi`WSE^!_T z;(YXo3(zYr#5{2kP8AnpzF2{NaR~;+r6`HZFeEO=%f(8(LR^7G;!35J^A3iPi<3{lyZW0IZS#c0+#36i69L8Gl z5WXOe;1+QdUlPZ#UObF1i{scJ9>G_{qqtQ(hK=HJd`&!o&EiRXLp+7s#M9U&p24@o z32Yb7;!g1#c8cfm9q|Hoix=@dG1|a-Rh)$Hi!r!MjKkex0)8mUagV6Lk3<#j6V>>! zn2f!m1`mij{7lqizi7nI#WegFW92V{PjhKyx#a#SRbl|w?#Gga~kBB1v zEPC;%=)+TDKK@4x;At^vh>rR{WX&mt@Vr=ne~Z&G%2SBZo+7-&Q;d^5Gw@PR37S1K zF~d`enVwmg<0(VYQ;t(TvoYT@2mPM8Smc?9S9#`Rv1b8Z?OBL3J&W)<&tfd~RN(cV zB{<8o6mRe>!!pluoa3p)TRbapu4g6A^Q^*KJ*#;Y^O2G1S%WJ*Yw;n^I$YDk2BKI^F=Z;Dvs*-Z0X#OFP=^qVm{>IKgha&5#do;sQrBfjLR zr>~1x?`fcaIpQmxt@I5T9rdcGk-Rlxqo;}HHDvANX(qppj5^OY@*5G~^t8}y!|15( zo>p>8#8yum%?@NtdfLfvA!E|hL4F%KBX~N=JCX6}=_0=q@m)_hO;^M(JU!$A&o2DZ zvl|CJd+;mIUL5l5!>>KPIPBSv-*^t-Ax|G3_w?hho`ZP8Gl0K&2Jxh42!Hns<0;P} z{Eue@PkTo3|2$)O#&a0|@QmYx=Lr7kIf`dJ$M7%DaXjZaf&cZK#Pgn0c)@cTFM7^k ztak$Ayk{}qdk$sZ^BD48;FX4v6^QpDUgeE8a+dc_!b)!puJXp=quvBu>y;b%D;Q)9 zcon$btD<=dSs{DXJ__o)GJH2V#rxTe0yk>mgn~A%; zR@~#Y<44|X-0RK7e|jCb&+EjGy#n@nMIPZZub12x@u1g7{=%D&UwH#K*@I9`Vk_ zpS|;VCP$G~u6I5j^De-Ddl%wy?;`xwyBJS+EATh(50O0qy{qvr?;6zPtwn9#I!w*0!t}gq%*b1hmb?vU%iD;#d7E%@UJW|(Hsh4M zT6E@ZL04WK=H=C+FRuX~&D+YWSc{xl@)~hnUK2i^*Njzp+wh6J7Oc)|#V7OHaD84o zK9$#j8}d5w>AWu7nAeTZsSX}rdF2ABFK@Lu0pT;@B6_xa9amG1&R z;k$^{zGxHM#5W0__Ql{vUmQN;OTb#69AEG$aEnicFZ$G2=S#+yeHv`=>F^bw9vgi| ze9f1JO+GWe?#skCeO7Go*>Srs8(V$3_?FLs?LH^I?Gv!WC*n?@7Z3V;_=PVY2Ydni z(ig-*UkJbQ72uD)={W8y#Giacc*IwXKl^6jZ@v;d>6?kCeWmz+zFBz2SB8K1%5lOs z8!!6iVARyP7(aC$CQO}=vZ)JDK6N1`PF;kmsf#gbY6YsNF2T#DF2&@j%g{M>Io>q2 z66a1`f&ZAg66Z}_g&k8@X7{Zp&))2Zw6uKW#ncm76v zD1Q^K%CEtP^Ecz_{91e@e+#b3ufs?4>v3&<13s3&71!lA@?D$ThZljL&4vUZhr@g{!aAzyD-n+jXr-5PWA7?fPXhm^Y6i+e=ipJ_u=LK zUYzdVk5~8)V4=Sci~Rj~mH!|X`v>r9{~(t5hwxheFwXQJ!t4Dbc!Pfw%lu<_qyI3L z`^WJn{}G(+KZ-Z|kKsK3aa`y>fp_>%;$r_Pyvu(YEBt40sec0R^`FJ%{&RT0|2$Uu zFW^f5MSRE~oyKulRGZ(eJ?5{7!803%JcM;+uXiw)%az!=I0B z{s4CPgSgWl!Y+RSzU!Zk-Tp${?JvR){l&P)KLhvqOYjr_Ox*7;#ZUdS@H2lI_WR56 z3;%2!@Xx_7{d4ha|2#b8pO4@A7vPA0A&&VM;g9~sIPR~&pZrVk7ynW`=3j=#{mbz; ze zfey?KbmHVd7disnCUqf>6t8WpFDd1shQvY(hh@8O_0Mm>FzAORyCu2iwpYY)4nH1BGBG z<^{X(o?tgF4ff!@!Ckm4xEt>a?!o23y?B3cA65o?@qyreToF8g4+i^iWw0L~3LeB& z!2x_EIEZV4L-=TL7}o|5;bXxOTo)Y0$Ae>76+Dbj1jn&Dcm$se9>w*+WB63?IBp1@ zz^8*JabxflJ`+5Rn}cVtHaLL|!L#^E@EmRpp2t^%7qBsS5u1Y1X2xM~5;g~8@Qq*` zZVM)0OHhujK?Uvzs&Hpejorayd@rcM4}&_~7u4hTK_iX@)9}Zj8OMW}_*2k|M}l_z zIhc({gSq%i(1FK-PCU-9Ls(-6MLZq!;-5huo(<;XU%>$WHyFh8!4Uo(EWiuF>G;23 zAzlm?VU$#i(b5dOL@L2a(oDQmD#aLS7RE|t7$=pZT$+uE(i~JvbMZ219;Qh1Q6nut zt+Wtz(jrWi7NbF`K$Elt)1;+nmX=|Lv>Y>~O0-HVFh^R6lciPYkXGXqX$?B1wdj)8 zp&(VETdGD;T8|!S1A3*6m?v#QpHzeS(q{BawHT1L;54ZYgHk<8QUivhtr(UXu|R6V z%cW+VE^Wgrq!uicTCrGa!)v5=ERi~}RO-a*r7oN$b>j_E50**0@J4AjmP>o^CTTCu zmiFPzQZLSt_Tw$m0sM#5hx4RJ<MPt z0N<2?*dm2+yHtR0Nz?IdsStNcMc647<2%v}?2=0GU1=tEOQrapGz)vAGJIbu#}B00 zxLcZoA4+p^k2DWIlIG)HX#xIIT8JM@i?CN(jGssq_^Gr64@gV#U(z!CTw0D_NR>Ds zt-wKPC4MEX!Xarjel4xRVQDRXBdx=5&cv#wqKT4Z$T&lsJq|JCl zs>PqBEqGk2!(XL(JRvpUZ_-x$U24QXq$Zq@n(jb|F1#ppV^pXIqeHv!lF)9vG_(g}LVGbbv=8G#y%-hDOj88bu*AhVIZ|6hq_a2^~Ri=qToej-fAf9H)j(V1DQ% z`a`EM5IT+1LT4}-nm{RZ7DJ(P7!IAsg3txLJaiGS3`J*h9uG~zl28m@8;Zl3p#;1x zB*)T_0G7tJ5od?e@aB*iZwY1M+>jOj5whd0p=_KV z%EjA44qOm&;_V>;7luT+^3Zg=KU9d7p(0!n zD#iyxGjL_71Ro2{#C4%kd^|J@pAD5^O{g573(dyOp*i?`Xl^EdHGrHeL-X*}(0qJ5 zv;aFo3vp*?5q5?a<42(i+#6bg2SQ8nU!i6AS!g--hbr;&&lT8ZC=R^do!HU1D< zgNH+F@yF0Q91m6DPoZi&7Fv)04sF2Wp^f-!XcL|d)!<*D%@`G~#pv)BoD{CZOT+aT z6K=rR@K#iZ8}YJm6Q+in(GcE-rf>_UgMHz4~l+>dL*2l27+06rZa z#7*HLtO*Zu&&}aOGmT+zGY5&Obv_*vMDpNBK?i?9{H3fplg zoQ>avbMd>d14qM7{3R^liLi*jg}wND*oV4;d^8jU&{Pmab3q6*3JNf@U^-e03ei?j zg!Y1B%qp0H*##w-Q!o>A3rf*jFbk&^l%c<%9H$k`#)5)5czMBGoL(>w3k&9BNx=dO zpH)?`kbEujDOClF$k#=@p$gbMM?c_s*S3L?)Fwj^y1!$j9X1kg?>DkaTir$OJMzB!e6l zVj&YkGRf4CPsoWOlgNya$)q`CDrpUwMrMV~ASZ{+BtH$AO)d_ZOD+q^CzppTAU_NF zlw1+Am|PXIlx8!Em`jF44H;1ewzY1AR9t~Mbejiduo(=h&JQuQ&JRh=| zyb!X5{5fPBc`@V*@|TbuFXCBsZt z$S$Ve$Z*qj@h zW%`GVHN7T#oBk#HnEoUCnPfk%^Ckn?-{eFNFzMt_QzbIqRGA!RawA8WJjjuzs^lnB zH8R0eo&3mDlT0+#B9lyY$YfJpaRnQHPQ$C`}fI8y_1qNx#SHoZq$Oif6u zsTrARdY{ZPwIH)iACQwwt;xxzw&YY(dotJ5k(_P{A!nF6kuy!5$xlsP$VH|P$;GCw zn1+#?Oe4r5 z(2%56>cr8s#9wY&T? zbsM=saD6FW{(ySC+>vyV&y%ilHTqTL>ZGS!ldLT_pzk9$B7Nm%WOKQNshebVDwVrQ zW~UuwmeV(K4{5&BT5^t4I-fT<%gI76aw?>=&?%o!9o)yvSgC}idP~RY$4NJxDl2i) z4W~-VU@1W><+BIlG>bG?8maA|9-^%!hiir804<$oXhBvoImjF8G%!w5;z(@9Owr|+y6k}mpEMqTw%IYlbcyBf^We3w$$%qLBh`c0Bv zQs+r&mAk5WQgY=|K6@~$avgQ1WTl=Z&97X@=M9#*mdcByi{xVIfomao(=}aMEZuco ztuB^sxLT<1x#r6S{MPqMN&&y`y|S{7->lw+9O9O$Y>=|tO8M-;JhvF9jnXW)K2Bfq z+rLZYT~dI1A)hgr=>D729)92TuTCeV6&|I0W?+#=A-Tb0ExE}fpIql*k$#lcd!$QO zCEu#mLas`^t5y%bD)p^elZ>l6m>f`bulH4HP}Tm_L#hrWYgg^#bX6K&bwB-tsx#;$ zR-HyBSDi_wRGm%wSN)9)s9KYCHm};=^Qz=swGW;6s(V-}qUu!Y$f^y<=&GgiRVln` zKWfjav7}ek7^i#EJg@Lt_oRhh(d2xu$XZVF5%1l#Ys=khTcj{K+9$eJm>lmj-e;^l zr0(w8W9310OKOjkM^cZI6R0Q3*>z)GCdyfLySZe@i|SVEm?6)r>qgG6>p?E8TeagS z^255(wI<2E>usqyP2O4W`;OD(UG+-k>GDZ?o~lV(^$cesV=$L)SkyhXFWR~wlGRN0SPVvnmbA7YP>ApE+o^K>e z&GL;VNBYk5Stlp>&iDC3?%)?)t608i&wYMg)Cc@(kO%$Rk%#>v$RmCU-o^4!zeMtw zUou(dmqH%*3uW|#-wNuJeyhk+eq+cpe&fh58XJ<+ zje%sIu`xNz*p!@O3?kJ93G!1G&r?OcoeTx>cPdSfKH!5B?$GIl46j6KP%#$M!hV{fw9*q7XCj3aj$2avmsgUAx&5OSX}o;+Y2 zP98LlBo7-C$Rox?@~APHJZ4NG%ZzE{EB|ri8~^cSx&K5`GMY)nXeCu+7O5GtNoQjY z>0-VDxPKvazvug$nM6IWKZKMvX}7;+1q%I>}$M0#u+b?1B{o* zLB`AE5aU%c-gu21ZoEN`G~Of=jCaXI<2^Fj=uV~>tB`3%PjZaW%m1M48_+!9pj;!M zDd`;$L^cd)M|uVXlC=XmkUjy8$$9}T$@&4oq<=sgG9aK;z+pK&;H=@W9360)>>f}m zAC@Bn3dzs_3!h^e5s*(E7Ld*-k{$`z?|xdY(Xhnhv>e)SOU=`=SHpcCXXTL%3*}q# ztVX3|b|VX)51P{`ot)C>tbR+*ZIn-cdL!GMyhf+>+j0RjZ_5iCRjP7Zp2z&#@_gps zmX|Q+w!Db>x8-GxDpz?dKVs%n*(={buUpd^K5p-lFjWx)MIdEfDS+TNySsBBcWo2C8=XAz% zU$QchH7iO{V0%wR*~%PerOckk0(ZzR$|dHzC>L0di*hb-EuD+ZcTq00Y-Qy}U>&ux za+CRP%5!GADUX@yraWbioAM}dhw7%hWTuCry=UQ5Mb-BVo*s(pd$x}AdxfOSd+B_t zXq)#+Wglhxd#wX~lw#_-$^rUymBTDmSJ}tRy2?S83RHrd?5`H6v}%$r1u7ky6w+za zWG|hTO)PZUHL=YxH7S)_D#x36`LtBZn$#eVHSzWdRvt9nBLyoDo0iJK%8jNL>YGi| z$=gl$l6RZt)4$iWQ0}C-H!CHjW)`WFqBKh z4^=#wAF6mUKUAsB%uvOLnW0KOW_DH@GqbbOl9`>A=Jt+1^E)d6%eeXeq`MY=Rs zxzyqh>I*F_(jjF{>n$~3DRM{WC5f2G`O+mC$Qwv^6;w)y1kwicr3!(qW%RZG+mO#3RKJ*=diI zVlZ_|Cxbg#$mmYIr!s_f+DjeYDW5u`Q=yz{=*eiRp>L-;by5wzn4fBhV>Hz;z&<*J zrBV%pI@PT+!Em%wP~9AZb6EBVIfg1>c^^zR1cqhQoor|vRw_?1v zQ$tW!*RIbEiR8bAV_lDT{m*c(>v5m|3=g`VAg^{kLSE~7fV|Q5AbGRvG4giTGV*TM z!#)PpKk|52O${a8)ZLLhkJOS#o>S_+$m%X`>Ve37*-bqd$umnm99fOdkw_k4^=9NL zpQ`HZ$TL0x>VT*cj{r3;YM(~~b$V1y-v(-4RH@uZRijHh8mUtBK94{(Il54OPc=uE zk`tqA`ZiJL&}pWwvgev;Ki_8RI!2qROQJ1&n(4CWbh04&UHU7c^X2Ah3H|2kQRXyP z_c7XBJrHg5ZLS`)j~-?{&DA5(4SZXuXY6^3P7Ae+rCO*bnbSf&$FeQd<1E`kJ;Ac= z)G^&k<#uXXxBY&d)N<-h>YHvm4e{dX)P0RoC?>mE%?Sp0-qbrc3dv*7GaBcvb0Xp?2=cyM5KAXCdj@ zbC2IJwFaZZ)OySxrg}1GnCit+!&Gl(4pVD0bC~MG%n@oYMn|Xv=!{T@Fn@&Fo0%ij zzCHIc8pr$*>Y$$c{gPEHGn3URbduFv<|nIp%uiOQvz}x%i=~p)9PW3tI*)p^TEOUN zbq-67Ru}gCn*Jh|9jz{5+0p8Uu^~)D4WLsB2g@MJ=+AZeMGWd zs+KUCs_tWcs(PSjsb8wPlbNaNLFS~YyL%p@Q_RdX^@u%BGAB(v%A7Ry6m!zl6D*si zmN7F;JOo^#Z#>K>v17iA+TVo8&859%aG(jB_(}#?Y z=|_KfOn-7@%)sDGRq18nvvNIqmCBiFm0mkY_g;mh+AE#DORu%muD$Z*NorGOPEs4& z>p7}QafqSQ*@%VbM`z#CtABm9j#rU?xtO`=Vdy*v;R= zr0%UfrS7dgrtYJ?r0%0Vr|zpoCbjqMtMy8n8QfRvoiv;5o78}ePAZlAYCV%?Pxwo)Z4UB>g`$t z^>!_sx>$>}XEdE1T2Fg+r?XS*WzXJpc57+WyR|XY2ep7STl%MUQ4VPh?HNetu-4R` zjp>wX&8bVZAnGGpE9xU!OX_d5cGTZ!ZK#iG!PG~!4%ElAFnfm6`A&5l%dlu2Trfs)pF`et$PU`F0F6tXvi9L7I`CZ#*&jWOBYKQH4 zkj^dbh&_+exviDi^BA2w+R3zZ>5g_H%|c#CEA+afol7f}?`UVz^2t+apVPURRx01s zF0<5K?Gj7tSOod><-&Ogb4cCY4U)n0!W~$MCwT zZ%^kvp}sDi_k{ZT^mKAV`kjVd^iAo!W7Lb%ZF9D!XVi_-FEARV-)4T4evbK3`qlJI zmni)jGo$ny%#6}+rdwR1^#{z1)}PXe)}N>UQYl)0l>RIEl4Yaydn_BRKW3>|eb9t) z6Z-1&Ch)qf=T1nM`s%YLWV-a#=S;|_Gk=1Gdf^0~(fX7L7RjvpWY{t=gYTZ{^)k|_ zeKRs$%({O@KAnJ!Lb73o#U)ekossRGshcvA$>5Aca!5vWtxUaVhLyTkMix0JBa%+v zj2!B?jBx4!84+a5j1_cRWvn9GWQ5Xbmk~yG$Vi|QpOIKSQxDBZq3)hxCc`q)$ncCY zWJJa|GBRU48J#iFJ4>I){buQAmdetTGji#qWK1X1G7{@%>0`LxEPWjJo28FudnV}* zGQ7x8b7J*LdboL&_ayyBhKbJ23|I1YhC6vTqY8O1!;^fNQGylj{K@i+08%nHB>BRRRLzY^&D@l9HV2U|=H{fU*@bjBcOa{nTaupU zR-~7?4Ozq7j`TJMleNv^q>nj*tY^0EMSU~hE7N_=32eW=Igt!7CzB1$DP*8IjcjZl zLpC*!BZJK2$>!#XWJ|M|Y-P5RZOmC@J99SK!JI<|n?qT%$s9(8nOAt{=w|cyIyw3h z^LC#cJ;j_ron}rX$C#7Japp8~ym<^c(L9c{nkSN3<`gp9Y$kKeR&t6ti_A4Uv!3Z@ z7c$ShhV{>4zjE|B>{pIHkK>Y~&o^&kbfLM3Tx8zrGg zp4mh`Fo%*4&0*vta|HR=97#SkN0ZOZ-N~2cp5!ZYFY*n0G+8e<_on9Kkf{~R8t=)v zYKf>dS=TI)q_ZWFQ5Q>J($x}2x?2X2RV;%@PsG~2Mv~nv&OTH0o^0C` zy%*ayMeohFP0{lFsy@atha6|gCdXTH$%&R6(rlSdS}l2G4qG)< zpTbs6)pOaNsd|=W7X9gL;Z!}3V>DHt#qpY|&*Ofl>hrnZsro|hcdEXK`<<#UvET19 zwm(-tY*|((S3hD|LLRj&B9B=L$TG_c^0+0uR<3@6rE>L?ES0ODvP6?-?8~0Bw5gk` zU$Ar_FIw7>2Q2eg>XIdx`m$x5Pp*E@vXIU`%ltai^m^9tTGRB$7EhmPx@JxGo~8#{ zr&BvyQ>b06X=D}ac(S2&9R25(H7xbgvW|RZSx>&PY#_@mn@Gu8L@L$<=Bw63($zYK zbhnNppITNi>S>)w?PWESHLOaOOCVN zBgb1Gk`t|uNVD}ZX|+Bjv#ig(X6d( zx2^TbyH;QFp4FdxU=1K2S{ss&tbybbYXI|?SsRiC)T-f$l8uvWc4SvTZ74BtBKrc4JCJ3!^m~k=46RAg4}0~ zBoA1l$%EGJ(50rj}d9n|A9OUd}m>U4%@)(l>%=h0uP&$rjvEVWe6VX3A1l*}d`OZD8$ zRL`aQ^vpf}UEJ*7KQu zjx~R#pUP}PUdwDv-e8@d={Ga$s4Mh0%v_;AW~mi=IsFy7lvSNnvTBl#SZam-l%-ba z&ojRzUuI@Ft`J|MRh-c(lb%_&zH?R+YM-ocNv|xvccjawg(Y{{;y zCLZhc6YSlWdfq36a*4jdo|`_&m-p!<_S{Y9kbcpgm+1VU56OF=9~kypX&2-u6aGxr{|m_^KvebvvMwxb8;?|^K!0|xjC=MB{_G=WjXiA zf}BU>ikye!s+`B7DxtNP3SdHyCf?x0eiY!SU@IwHaBO3kjFH}X6_$Vcbe@d5{V>Gs6 zKfb|jL>VM$I6lTEoWu=0L=BY>K0sd##wcW<0P9eM68wZKxQ&NUoFvH$Q}8K%$6t7X z|KP2$?|2`v7>lWxjYU|24LFT!cmgL~lKe3kX~;w#=3_68;Rec~IZKi|n!tnz48#Pi z!&kV7Yq*OC_!kW-@xy6IKq|%~3sW&0d+`rGaN)-*(FGqP1FvDIEJ>k=K|GQ%4zsWb zE3ge;;TSGKc9kR-RD%!v(E_39iWu}qGR7ho`S=l6aR+bE$4%mM%-J9O4TC%92I|0y zT+F}%Y{VDXgQNHvzahXwl7=D^e?Y4u@#(sf^bQ)JHwIx0aRoH|*IEGXB4SF>`_zAvff%fQ(C=9|#Ou#3Yfu&fDjo5*`D8&h! z!)4sW13X7LG%vOd{^*05Sb$~NjPr=B&UuMJ7==`1V+sC)cMXm|axoW$*n$JNgTGJ? zttO8j8leaBumGD;jI+3m+jxO@y(K9S?GcUMNXKGq!$I7~V;E}jUj`71fk?zv+`|jJ zf}u9sfJ$(M2Ru<7-l&6mco+U?gdns=4-CX;tiv&!!X?~*T1Vnjjd-4;E&|XRCd42P z!;p+De1Q@i#YH^8OQ=3v3(yhK7>MDpU^8~&Ail#XT*3`Jf>xJn6y8TT7ULJ(K)rgL zv*?6K#9|OeAq^SG!7MDo=h%v)_z@S-=pBhqzL2C3(GMRX8}qOfMfeiO@DncLI_}{K z-oU9o*CNzJeKbOIv_}|*AQQQmizQf%P1u2b_y#9%9#?S(kMIwace%#H3w05IW@v*> zh(s&~VHDDkfgH@lLVSkx*oNIWgfg7QCH#&DkbF6B;EO(Zrws@{6HJ!zARP6hGn@+``}Z7nO{h-v~xFW@0T) z-~s9ca9u$MSTPl=QHr0@t^wB@M57OeU?S#WDc0aCoWnhMH{^WBC@jYo>_X*6T>r5e z-=a|<#{sFZU?v*9$8!xG5stAa#Si!mPtdM0k1zUQ2qqvGpJE+KP>SQYgx~Q1&+u*& zN$QRiOu=ld!Dj5le*A!QxP@o<7p_gYKA;|&U=%(<0XAYU{(;nt#~Yrg17Ea4Fv1as zL@dGz?8JUl3X-I%sD*dY63Ix%J@n!Y(Ljtu9_GWjIUfy=TJXnUjKV}@V>%XNB|b+n zuHXS`w%~ry7_AV3?uf$*9L5zqz*D?I<(51KXo$9mLLUspI4r|zY`}IL!8!bj7x4Xn zYX*iO1=+~Q27HZ+c!kQXc&~wMEW!$`$8lW7W4wZEYxV&_n1Wd-#5Nqj54eP9cmqQl zmO%}?hYt{fu82h<*5E5V!Yg>R<+_9p2uB~(YRA6deT1Vsk}w%X*n_L^Y|pZofq7Vh z)!2%!aUA#Y6qPz~Oi&-q5RW8$f_2!BlemtDFmz;JkctWT4C}EC`|txU;SW5AA(-b{<+l=1mhj=7mHg=!{Kj0j$;0|7*YADwryo*4zKo7)WBvO%u zX;_TaIEe3X3co<@%(kKi{Lusv=nX5T;CsA+62@~KEfIlKWFsGIun#xzH>57SuSEbt z5Dhb?U=BXR=lBBO;|y-#KAyr5&UT?D0uY3D=!!Tb;$viEK9*x0wqO?y;ye6|Yxo0? z@fzxftQ$2DfM#fe5786-F&v{Y9@&_Mh4>8Xu?>511V7;>UO|oEynzwHNJl2}u@d`m z0uS*DYFEy0cwq`=qYwvi3_sx)+{0tMhI1tMfrf}ge{4iC_Tqb-!6n?q8>mq%gF5iV zdk8@UVlWg*Sd5kU9NTdOS8xk|;u-#hOEl*jOz453NW?@;!*XmyF%F>&r|}!^;&1R{ z*HR_aLLCkdP;Z`7n1%vu#y2>F>v)0SK0J4jhXp9WR{V@N zsN0wKW{5;AhGR4=n1X9?>BrZD2to+DV=z)M5i>9!YjG53a19UP7RPbHC``a~dmYt5nR`>3~TTOe!#D|4{0Qi zEzaQ&1dd`phQW%dn1f9yL0ke~Tf>S1oWTQVA8~C)5IP_gTX6+<@DDr^c^uIgtzbet zteA=w*n)jHiwAfHIf?TT0ceJf2uE)WM?(}*p59ofm?Wp7m$*9oZ*Q&@JA~| zp*PZyk7ZbgG8jhl+(S*&MGz!#0s5*-naSd7F3 zoJY-%`Mw<9Lj?LG51a4|-ecHaG(#J7LL^2Z4H=k)Pq6`C;1GVmWju#Imh%E_aRJIW zo^S9%T{OT4=!_T)MG`ESichf;8}J26P>SO?i_5r$r*KZ^Ju`yP4pHchQQ!v=q#5`e zyKxXd;3EFO-*6hwcA+6!BMJjxMlOm`f}=QvUvM3d;W~k3Q6CM_5*^S5-7yHGkbxZJ zVLp~)9g6TJ4&Yl{#x1;rJdyWVFrpPcL>xZH7bw9M+`^ym$>5yAcudB86ksz-a23x` z!^}F-3K8guVMszA)?zb`;~cJn|BxhAMP2Y?n^GJSFary)9EWihSMUdFSb0x}w)hZM zEJh)|L@B<Z2dx z@fiy76%OJUuH#QM%I17W2qIuX0pv-XyJ(7D7yt`qVG&l~bClu&ZsQ+R&f&a-KboKw zLJ)x%48RDaz>JwFzy|EZIXr~RWFAYrgCMj;D55Y3qhP@lEX5jZ#$lYm73foV4T28> z&QvQGHGh*k(e1Y(ec3CP9_EW=t9;Y%FD zPq>KdxQ8crgUY#lKNgM99PQBseJ}zkn2RM?jcwSCqd0?KaT9;yHPmUmH$e@&gC>YT z9O99Pv9KTyh1iO(a0usc1-J1R%Hcen_j+iKb_hiTdZIsuBN^$)!Zggo60F81?7#`! zLODEUaQ#IPA`p+Un1Tf;z#bgN30%aVcn+sL&Ue&C0Ggv0hGQH)!8~lhb^L>>GkMKG z3xr`5aj9!7N_w${=#dhv)F%l<6Q)y9XcZxgD?uyumBtIBYwtp+`|*N%;q_Q zRtUuiq+kN3BOfcV1-tMye!&ft!+8$-f!gSVUKoKCOh7K?VhPq^JNDo(PT*%;$9?$B z(ZCg2?ep)EoYg+yG& zJ-kG%`MgG>B|2g-=3^s@u@|Rs1-J1RUP4~Lb|Dh67=t`4KmiJI1lmHb=LkegbVP5Y zVKU}n6*gfP%5WN&@C@b9Kjr+vAdEvEmSY{ZpcFsDc@d8n8Xy!=h({VGVLp~)9kyT> z?&2w27V~(aJ-TBE(qO?%tj1Tk2d5=m@6i;k5skq}gBA0!0l(ro{)6*UjyqbQ1BN04 z^H6|7Y{hpth3j|*r)7NIh$T3Q|M1Ro-v6RM=3*<3-~kK;oJ*L2B7BMcxCZafcS#SMiSj)cST?E2} zzDU7j%)+PGjGZXMFSvpGcnX(wybi$!&CwoV7=XDb#BQ9x9sG-Gg={ApA_y%Ifu87( zVVI6e>v=81H2j8EpYyyzFU&w0uHrHNgX;z!D>T7uT*F;FfxeOF0NzD&v_}}ap)Wo{ zG4|pLp5P6%O}sBbFATtFOu=>hg*Rxqna2k|pk@)Tn`nui7>lL&2AA*;T(e!*)FnxPFkAr8ZkjC?G^S`^_YT*P(U zgIvrup&GKW3PpH~*HCw`Juo2-8JLF8unAw`7rcP;PQJcDCv-<5_TUhHMy)To4xulG zBMnv*U@N}CX*liT`GcCMj~Q5u&G;H`@XJ@6i;#A6E+GlykcnLE#|fOrRk-fq`i~%l zqA!Lc9dl8F`}hYZOW0n#hO(FUM5qt`v!oP)p%{x9n2#0MgkSLhwf6BkfTqaA5^O{X z&f_X>;}sh0=h&e&LJ)(27>QIbZnJ-)=(_zBl>AOFGm0FM`%qBTs2L~jho7|h0M zl;AK<<09_jC7i$JbqUS!A!0BXDfk47u@hh87;fWFJjZ`-)!2z| zaT2HTE2@6Wbp>NE6-!Zo^*E2;5pay>GkV|*ntjJPgN4|QYxo;_8Rr$EF%qemh)Kx9 z0u1rI#felG(rn>Km>YYB+_6;4i;cNw&E)sLK#luSKP#XJi#j%j`NtI z2HrtSbVN9MAP&QjjC5pSE|y~(4&Ymy!xcQhYp6f)7@{^Bp*cFCCx#*k6Of0c*nqEa z5Z~fQT)|&>4fO=a74^^%&Cvm2=#Gz&fytPS#VEsRT*qS=e&ifPO}v9fXpWIcg#}YF z7fZ1gJFp+$;Vf?8Z@h+nlGjNzLUXi7H;h0E#$!D;q6phij4!bpd+`Tq{lsfBEZB}G zXmg5dBt|0*V=*2Xu;LSJ!xgxl=9pm|_TUYgp5b)@!!QybAsML{gLD+)EDUEkuaJms zc#MAMI6n9mCs7XhJjVe#T;PT(sD{o+Mb=8ja=-)O?X}A_+TE+!s!av7PLWo1fvte@F5~$MG-E+g1hkkonwTB z_!*UM@*Wo*5Q0#2K?I`E9og89t8l-?{UHxOqUmkUIn2WXEW%P0U?tX|5NBby!#Rf$ zScWU;dzWhi#=(lYSc)QiiDNj4>$nfMKX~m$BXmF*`e7`rn2W{Ogq=1-oln1A97sL z37MFSRoH-?cns|?o-=5Kj)=xU?8dja5C2D;d+3Hf7>rTK#C#NB9Zusm{Qu^>ML7B) z5nmwiG24PD#A59)A?$6kMP29K>&M zd(L$YR!qlSe2M)yj4SvH&0lbiAqufbKn5mZ0k+`~PUCmn#}hccWIOQ@KE`BxiqEkP zR}uIR>xT(jun$LZ5*Kj;4-oo_b-;>T%t0ac;1HU==Da}!3ULf^Z@6~j82-jTaQ~O* z96}L^K^TRPF$43l9P3bqGx!}3@C@b9%Q-LLj~3{Fu86}hBqJSJn1*>+itX5qBRGKz zcn;}5jtlA{8oiN#kCA~%n1OtJhK<;bL--zNaRm?X9K1?ME~the#2^j%SdQ%|!Fk-o z6TCrXS(d6J1QCeA0DO#GEXP_D<6B(94cvny-!f+2;CDz;-LY2+)gQ*a6}|iR%GUeS zc#EEa>M!Hp71iHHr{CZ9UVPYnkt(TD&-%PSk>bc?DV`iHC6X!97&28dlW9^O`LQ&g z93w3w$4YC+arU3nOP7kN$4e#T1nDq2Q7R)dq*J6>x=322Yot}W_Abv?=`NWiJt9Am zUXt08voDXmuCApYO16M=InOrJW zA(u(s&zQ<+s{;*DU>)X*nEJmpN|jh=(*GH=t=G232Fq<5ku>=2-%{*l-dX6$j9-C2wE!c`}%-K$Ufnw~yPI_OGyRet*#y%X7_DhFwL@JfO!7=Gu={uC+ zd;BP!kS=h2`I)>Zosll#GOm!n@qZ<*kvFB^C2#ppsj>W?+!QV4yV3_}jbOye5mIkV zq&CBXOiY)j$+P8Q(n`6Fyb7zaUM`e3$e+s_u?d?|gl%$d`GCA%{u+nngYsGVjC>B~ zaYg=Bz9#=BUzfA^O-{e^+nIjlN_JO%Am5k #75elyb(`5E~fFQ{MQANeEc6<*^F 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 z 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

wjq>K>$QajMf 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%0Al%0JMx7$=I-x+LNahEzUpJ7; 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 wQUufi~j{O*HRgZtSK-Qozg+B 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 wHJy9C@G;vwv9;LhMd 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%0AJ4gWYS-vzOZMu-{{U*#4CL1^XKN z7JI$@Rr}la5ABESBOJ3Fg^mXts~ruFw;kU(PB{K_Sfk^jJ4Rm;-7|VX^fl2VqQ^&H zAMJ_0B{~p&Tl8Jg4@N%`T^YSPdQ)^=^xo(&8!a2pc z&{^Spz`5M{obx5;M&}Oa9_Jg*e>*>Qe(5~w{LLw2>@jU)E{y3G(<^3hj4LKHW>U2#>ZVB=ZU)|E)aKH++A@G#yt^N8MiuaQ(Rr#-ncj8-j6#N_jTN{ zxZmT{cxQb3_$%Uv$4`i#9)Cyt()btRx5d92|84w<_}DgG+LX6xX!FlDr`y=uc5geW zZAsfzZP&Nm);833f7_#Ne`_lf>yoU_QXAj2NDk_{*d@vqHGt{F23Cb?Ygw< z({4z+^maG2%WhZJZfUz!?HbzcYxhCBgYCX*r?l_TKB@g>?Z>yD-hNj5qV@;cf84%v zhs!$j?U34Ga)%VzUNmRm<{~B}3B1>OJ@guJJ-*K}T)3gviXhY_?uDj^C!wk0WoVkX z>=Gd|L?7q~F$6kNjDlv0*Px@t>|}v=R*Rrx#RBL!@f&o!i0g_^18KkYGf`ZI*OSC3 zXqGSq=~sj4pVSn8V*=l0rGF+Jn%>l5K1Q$pkNjqS?duS1@t>K?7<}?U|956SZz$*Y zKiHDbnfV`XNp3+x)krL!Zi!DWDtpbHq{05W^@V0d=U zcmeNxR^vU*m3SZY4aEHsYoBA7<$l5n={QzKv~Ho*$sbsK2>BPiLn$rNENwDMMoWi` zkxm&WV`Uo|FB4^gY%kl%j=Qkdf6B|1#pquqtm9JgX%c(~73-)wv{(4MEpipV z>d^A)f|ghK4nK!p-0~`^<<-iTSL?M`)Qi{4<}2tN_@kFCp_^J>{j(+BKU?BGryA$@ zR{ed6o_3f?FDd4fmRBy*x-@-+xJ!g$zSG9=z0=0<9cb|#Xz@7`jd+ekBVPX&U;h^0#1`Mg7T=r}-<%d-ev2=^#aGti zD{Jv3b}+7ET_<`q5Tm&i#|pf+y+S;Vqgpn>K8U{-(TsO&o5i0v-d5*Jn`yp`#gS+# z1Di!JQ@I?3_nCW{s-#=g;`I(3^*9=E3`F|<@OM!Lp%)EOu2J5!Hj6i{GZeS*;HXgU zjjB-GjxNfFj!x=)XS0~^?4rzfR+taQ<6Lc;#e+CLYGbwxQmiWo%-Fl9gz+ z%y)KDySKAiuEjB--N&#$w%pUsVV&>Hv<^}#%n!654bGPjw68Efh2wb~4LDwDKi~Sa zoNs*uhogfBy7aZMjT#2JUj-fcN#gTzyG>(Zlrs0@@!;8a@qYy_aj)geNaomGr zDUM}0p2G1wj#W6;R8O)Wd|{IP3mo6#IEJGOd~2%LcDkqC+D`MG*sJ5NKejNZG|z|G zyev@S%kMR*w4lVF@9ULTm|x`2^A%_Lis$*gzJSPBP~s~H_zMeCN=l0TGfPW+qL;U% zuvq9ZJtYX5vV{wiY4M8*gdH#~J*3is?5?^tFCoeG7AMnr2^Gz;n4Lhqy zQ+>sBet$u(nCvOe^_7e$_T>BK7Z%SsH;Hdnp3h4~5-EXzFMnoU*;rqRC&yFbX^m@y zr2A%hO7lum^8B8NVjCy-1qw@xsRG9NN=u48d6Nvs7*9cNsVCRhnxT<|t5CbN!lITM ztm*%Le^vm;J>p3s&{(5kQ?qVkL@NGmKVEB5EkE@>@`5tQx= zc#Hi-R2An2jz9}@t)3g0Sum@xIA3c`Pu}0gnox}X<2}!bC;LnC&aIm)pSQFa9iZ0) zUva)aKi4l&2sk&nGepO7q23PhP2Sa#;~Y2o&b| zN+Jp~$>+%#UyxUpRpcpf_Z1BE+3ZY=GLae47~~w|E66RGEz)Ltip5x8eqnK0%Ww;z z`6;=WT$qJ{ht7|FHKC+fP`WJttv+G&$g!RRTuiY@DJn`U#IRaWA|@A?jr5gd&G(mh zXA63z=P;IPz91I~{Ih(45+j3*1zw-lQv}B=EXvN9Tk4?^E3PZ_7l;vBj}Q|)7Aia@Bl*v&h!<(^Pjn1^=Br8-2V z`*Ki=1tkI(jIo*L_xek?9maZ!1G7DORC$wpNbf7~`a~9D_^5Je;7u;X6sQ5i34bjL zSyDR`}MF&4Ep*0TWFmy{M4h*Wk)&tKr{b=E9ojDnVFXi7l<9a&7n zF!W8q%LZ87#`SOaW#^{p9&zcoLn{gjZ$3%*LI1j0F(ma8Z z)`l^fvDMT1iW7`SrrNX;8B)@}A6iE50^>_d#?P9B>DAX7Bh{0WnUC(Rcdu6eh&)ej z#Pms>s-@)vf~T#P8I-z-mZHU@jg$hdGit40;4?ZrUG-ScEx5yJulxo4Dz(&~m!tX6 z61ZvM9y1xOgX+lfEf_y5rJzhq!4T~`2wy5G#Em0RSe$}+9<}X77x1Cgsf&*<&d4vq zu+mi@Z`%A`><=JEZP;OEL|-h?d#uqYBmBO+93C^7Xm~%`;8vg3sf`{qGOutZd9_Lw z<4S2b==DZ(x>j^*iehxS63wGW$to$!L;pgz#`q5S#E8-Yue+a-XDa! z6`3>-qA@WSV=$e!8%8F}%+D_^p~#};l~!(~)hd;Sgb_u*ptNEiCT=4zB_{{7U`v$q zlq|ADEw8ai!5K33Nkl(Amz$O^JY3TKp4@`MK#AWQz*v}Bnv0oqls_lO7co<36wLD% z7Z%VgrBz~DX))%55`EsynLHbX&B?@2(q}6%ws4+r9L>Vol%U7O=*2J+;|fc%N{eU_ zaMq+2QLr(dTgy;xtrhf{O1t6c%@^RgPP-G)aKe?KO$+Dvw9`h`(nw#)1b;yRU3lvZ zhP#lKD60hZJJy5lSmoTZ^GHQP=10LV1ny1oVqSA+;Cdi;WB8cF7#CEk%nlj%cJIG!G@_ z6VZU-kTIAQ^LVnPn=kqjonS&?07C=`IlIZ!9vKDR!W_DjQj95+M-0(kq8hvftAF|>}*CV9+gk#n8Et<^UfPheWVne6w@p#`Ac59#KnT{p5XE({duPdE{^ zisH7!p$5tfXbV-ir{LyPoL7c!MiE3RmOnl$InoPDwdq*9T_IO=*DP(xn}wL@T67`s z851H^e%@J&z8r0QdGcEBy4q?;UtVa}fI?_@x?%cFYxtb(>{O3;4o;xm%EU0f1)mc@ zSHNLn7@*5JOby2(~18}IFDkZ=c2=EH)Q?R zdxoX8oZjVd?b?N5E*j^XuPwQ#$+cxZUGKa5tVYqn@X)D0$x_JV!V*s&9)=1F zambwwU5pUWce)OrV}RTAzu#U)}4mW;*_$}9+AHB8rCDwQ{uQ6+E96r_l}T+&p+a^FKvv38%B2+f_2= z;da?F3<8)(uu_Y#^~=$`Sy*&?w5jXtQ%A(lq+13(MDk6v#crLoG1p{jvj{4jXB%y; z6Y*Lyuzv~Gy3ua^3V)EAZri8xeq(@VV$>tg5 zqLKJt&Yw>A=ihYV9K}-8~{1w=4Cp!U9_R zVu0p}4BP|?i&JqE4$$JRCH~m~+G>*?i|_;(u?dLA)NZ0J>wNT;0_~9$xsSn(Gq1H! zdbzb}O7Gg|!9e&orsvB#poWL}6V=*#~TL=#q#p7qu zO4*mg8$J_?eMO#PY%>+$CXed(GZ5OkhM-l2=FQ0S(KEu?uZ{e&ZqR0aEjVkAzsShx%zVj9 zqs_Qm`f{{;m2n}o%fz>5szf6;o&@~#_=~lDgtzqxCk+c6?1kwM9(_f2KJWk1r0Odk zUsNKpb7^DH@6~R7xD`_cV3P~C38S2;Wi9y`F1>>o7CoF%5hBw?lv|6Y+ZZSqV!oUR z7f=1gHhXOTnysT*|ipooJa&ll(vb39gmi0l}vrm@*|+Wx25lc8&7D) zN-AR1Wh}r3v3Bk>Ow*XB@McCl%?D@r>BD@@5jNX%4HhgAw zcAwUOet6k0I~&{Bv>^baKl0VyH_%^4oVsNOJ!d-I&&?nW;4lUa_XPy@u6j(5xefH5lUr|aP_8+kr&{uOQ zUTtl~Js%ID7;gceVQN$1D19SJ+<=>*_T*zYu_WY5B) z8_&8T8~b+o*hr+keqIW+4A%2*cwxrieX?E{gxXt9y>hTGJO^)c`SP%cAtOKFEiBIS z&onx{zK}7jv_fnXo?U?qA%WQP1zcj zf$c%;bG5Ei&pLJMB8;Z>6x3i@z#qV%HkPNYS!Lou6-5~1pA)eLFwWf?&G7KV+ZvGN z#mWFT*;%cwmZw|nPoN501Mp;uZdHUGrkTYU)mT@K<{D;Knf@+YYl^H%V#ES;Z~gte zmVNSb+e?h{EkN0Lmmd4ucwW=q!qH#S+Di<>y>cEV4q8@e_dsoOOh=3R^8&*~b~deb z{9bLW&^9eik@RlOHT?z-GTtvTmJ<4#E)xp#%4Xpmgn$?}a(LH_L4Ah|Nlh7;I&@&) z5q(DtPDvTsxBtM5J{hU0g9nZ1mnw#h9o}{5pb>rg4eFbcHmF~}L4yXQ4oU6Pr~lAF zgNF1UnAWF1b|A0?LX{m+2l~6b5xbq(UW;heG!LdF>{sg>@pvNR?X}h%sBry9^zSpG zf8W&p{Ra-{pFVIz>X3}Sg9nUA9WWw&@Q^;K_=pe+hhq0h8JXM4wb%4Yh`jM(Cu zHal`hm+R-e&dgco)E!bg)Q%`;q94ReI_|`y^BTS%qiH)!@UjN824p* zC#KcGcZ`UMMeF+*h(e$HXcy$HL3?f*V=}^f=UAd^Pv8IRG`%vs`5rVj28O3dPa5%N z%ouuWO6&fuv$($g$ns&ojkeTV8u9PmtZEsAboqHS%i~^Syy>ei;`qVltWiyGvz_@a zX2iLS2UmTYgN9&hV9UhP`g}{vPW^onOf4->z2wDm3%e9&yRfFv_dQy2)mnnz515c) zJkOkeDsQ>uUK8*{LXD!YbLf?5O*|pPxc{MZ7&#h^IjOL)#PCrsGF}_A9BPo(O@>=< zmDZIr-#WGJJ>x88Mr7QD^m?O=Q6PQUXoQkeo4@fEQVzC)wDTCG`!nvJSX}FGsPG#M zMle0nY0Ej|GH7Dd8q$-C6|!#uJ{qCt*HWkq?0A-G?~h033okZ4_$rLdv?dAsml?Qk zKYANBMcc*jp?3EYfiuJGaE?rQD@f9&kceZh2DBGy3&N4nY_;z5O{5r z`^=26)$GA;?W|e+M1W4Gz1gfkA|a%h1Lzh(8zARNex^$=?u3l7o?O(c(Py+zcu<3L zc6wPO1|Sk>dqQXk?;Mdrd+KQBNFOy37i&TWzZf>$i#dTlETN^t3QqsX0cA`dDLP-+ zgbe-Uc>dGwzT>os2IVS>h>e1u5i6pkx<4Xr%US8+Uc1}tfh~TcTk3^wanrjhty8=a z>5S9Tgr}_^`FhVZjVmy`NQ&Ew{!mwpSrl(!8bMs`cxuC{@SM?aOp@mW@VKInO89c9 z0gSP)KXma&C?-b?A6g7ykd_wUO$&Z>(WW*2h08~pS{Nrb>m6=twAE4Udw!1^b zuB@zgR#sM4Ru^iM?p(5JheeD;z8dxH-6+Yn2*=%-9zj- zsd9x1&CNlAUx}Zxk}9k{q#7jeZKD(q1SwRqwWzC7o#8R; zM2cQb*a65fV{q#3>0ZSwy1QP%97pCajqxq}qY>pR(iR4s zbL^7)gNKN4Adty)v@A;tE>3tbbYRqerp87lri?QZr))G?Hjz+4l7wNjYTDR@y6X*1 z8KKVUo0*E1bjp|KS*37UCp!j|{lJn|fOhg0JE0n8*jw7M0#6l86<}d2u3#-d$b6>E zsKF}iDz%)RsF02Q6t!qX2rAhV|HpN%Hg|&Sm?crkrz3TF?hD zU4+S_=ZZBOn_#a1w?kasP4wjl4Q&J|WCg<2C2z;;FEGL57OCtauR{|==2~<}i@!-; zZ}UxwV|^FL$_z9)VG>cog76yPByg3utR_Xv62@uWNIO~#-YoA+BtRNCL7FJutd~pl zh`hY&f?`6vmTa1dJ& zT4tcREF;jHknwdwQG%)F4+C1Ob{T83&`Z?|ZALM*jf#EKPI@)UOXS zb`jkaTqMpJT@qvAcs>iJPhm$=Z22s1iTugi+1q z^VoNsHc|z0%(Vh!IQ6yB`>?i&v)eEfE?~ye+HI-eI)0kKUYQs$HiBvvYkeBW^x^QR zI}|*{p0>)vW}h)k^^oTw&9x!v!neMEV}vJ#4OG>87w4fy~6MA!o~p>F>O6 ztuSbjaLWRR>BR}S#S|md1c>oBfd#SE$Tw-5sGT%>Tpc?X_%*nx`bkC?FuhD`QkhL` zKzN9z8HpoAXsBVK!eq7@$ey1tKjSXa=l(DbAnPwsRfacr2yKiaJ04SWmxHnb4`U3& z;rTgE%tDuEcf&ex-;6&`=b7ZRYDc121;EdZ+re1XsTyA?7T?7>_<=#+-Rrxq^dpFS zz}V(7jCy0a@-Hk?`eL7^j{p`MBgPfmmK5~uN(z7YI!@mpD*KMb0C{xpJBU`sFbtC8 zLaWbG9YsJ>5)>@NEDKOY#Vm3totqUPEbcj^FUcwx0tSkOltIZO`f$aNS1;Hcqezq9 zZfA}GCA;Exjhzt?oQmJwY=|+L6QxivqXZ}k!Dg&hR>rqiR6@Hs4r91Nl5GZYUcvHi z_U(#RegtPr*Wz#ol@~#SAYu7nn#6$FNl@0!)3~v}m~igQ7SGemxV@%=xis^Xta7EK z#LKW!GD93n7-3K->q6G*rNg1amyV8l2RP%QLLNK-%5E7+acZHlCRuvx#7P!4sob$#M2*Jv%FK9w14Vt}$7tDMme(%ekC1Lc+I zohY0Nc|${pZ8vZ-``Z}SSCb5)yooIm1vO%suJ`Ves#HRF3Oau#19Y+NK8Ri@mn)Mn z>rf_S?_91@h6JU4Xs&LIeD4RiIBAOk;UEXwRg0Nt0MhDF0-dW66r+Ue8@C|PSOQYA z0N1QP6LMoTC|0C%kc3oQ3lsExx|MxJ<1;I~JA-U@A9!Lql!H=swL;3aS{1Qm&?YkD zryNRL+>ymywRx2C2|LE+DngC6N*`DzzJjsfcpG+My&Cy>VW|add&JfHp)4e8Ap>>0 zGIsBUncwTZ5P9%IT<=Jh)&-ZsvN_U`d8zs+_88<-VtWNF7@%o^i-=R6a5vbX7XX`t zpYCsPdt^2Jx80qaou4LE7dDn3R;Px&o3YuMvWV6;xX5v@1IO2}T3$Wj4K6?Qc7iXh z!P{5G2xDE5MgS7J9p|}Tg=Ld>Xgx5&D`&wWw}S)hA!2GbXs#yEDwqEK{c3toL&XXU zlne@S3SU~5w~zL2cA#xe)}=5n*k$-i)|<2^*rB!mm6?=YJAZE+IfLck^qk|?IQ>TR zcuI~z@H-fWnU^OS0*H2{GvTdo*sV5BANSG8ZRjz8-pf@Vwz3zC+xhckx|V(lhw$*5 z;a5J*m_&=^0^KUpY#aqcoi_P8ewx8rtq-Hnzg1_0)puBD;}*u`d4?YZc$bd9A1|um z8Uid1Y9>tZ%VzV`f0|VnPruCd0jh)>g88g^yZ&v>-gsx3y~Fsb2z+2cV68T=wx}*A zpKp=R<$P*?Q3HIupFBWTz-a@%uO6mzSZ!8U>!;ZO8B=wH;IGrqSI8e%d4HXLW!@ET zsIWTxefzfh^~;*o_;o%RKM{T1yW!7fZPnmXy}|`UEKO#CP}S~iJM8WHFV8Te_yyOJ zVH`NS#l`a5)#mdUceDSBPI#CrS5#T?@futXd}~(v*}h?zWojqn^~NZ z9mvxSuZ@jXt7ZEZ7))tl1e$NA7PXdjZ?32=iWI@GGVG-_aI3;XZ9_Y8bIrR`74b@6 zG{zE?fa|4(#;=fkwwokt-kihqG-37Dj8bWl1k*IfwAJT&`Ehf1Ts`9toWCH6*;*Bm zI1t1PO)-|qM=%Gt>rjSomcQ|P_1zAKXxg9hbRHxsa%CSbCpU3X#4T&K9pm`M*5;0+ z5yNuXKD;}oDzJtMGo(5ybg`zrF7foGhU8$zW5*MIy#)T7Ed*xv8x6*6vgF zewzZ#`nLsVwo0Lav@aE9Lu40|WJ0{#>+khP`}+rnu!J2Q3`e7*JMZ;IXNSj!yXVI{gTq1Zpx-+<8}<%|$mMuv)IU0_fYCc19qpV9&yP;_2BVX~ z&hZ%xc!xXtdpo`1@c01s#iN7W~kn{fN@bKW^_+mbbj7H+36pj?eC3-hr6iS!QuJI z@lk(obk^S)R)+_BhljoMeRRS8K@WB9ogeKE_fGZ>2Zsl{ySszk(cr9ie!g?QJ2*H& zw;b*DMyS-@aDQ~Rb3CXH2mStFZ|7(<8te@Yjt}>HCxG{kV1d0m>J`tW@Ja3AB0 zB**>3{^8j%#{xq*z<`|$4uOg>MrOO`g9@}eI6OH!J3)8!c7|wce>ChLjE)aMZoT6{ zA7eB;8Vt{R2m2s^J!E~fb9{`!K0Z9#8SMOrGf+PqV;J|(c6WA$hdmHwfA8dYH0bZ5 z<@{iDOt`C0WJ%|Nv{fpzrB@!{Ud;H=-@ z9gYrmdYFa7-uZBMcy@GrzPmR#9v+>Y9q#ur+XlO516E?^4E5SS2aQxGN4vXV1gP6^ zu(u0?`Q!e{@c=XQ>;(4xN5c_Xu@7=P?7_>K`5L?_gLk zSC7ul_lCF>aMlAG+1c4Y**QUe2g7~z#~$Ve=HTdTZ*X*Sh6xC&I2iU0j;pit;W@Yt zg1Z=O5VknO;IMykzI!wR8#p=Y_4bc<_YcXBKsWnn*FIX+JI4e#hJoGw`REw)_z-!3 zJ)NJNVB+9DKo9fxc(30Bx7ryU?;agt9*@9P&;ZOBaJ&8U9rWCBH5lymkA^2Z=ldsn z=f_6}=l%V&L(KD?LvT*qG621Suk9ZVjz>M*cmSpC9Pb?;p6q}L?)8R;)o|Fu?So@9 zw0DHQ?+?+4{lQ=deZcx)XimVSc>e%IF#_Z44F@B16nfX9z<&1*jt-&R(RJm?$JN{n(fvvgZK6Xy z$Hm~I@Vwy{DI2l8-2tO)7zr+JXHVmK-qj~1PGs;Bj%Py^nVo%yYBmzLV^R_~5~Ft; zzq@BPEjj5n49~*k;ZP;(m^adPM0p~+xYz#-bxa@|2pc9`ZEV8@^2E@E(hZP-q{zqCIZv7&i-6k(%JPCI@Q{Ik{d}fyhQmW2KPxt}5IZA@q`J~#F zFh?_6?sT6a>eB#6{V~XNfD>38T82G(w7!Ln)yLJ$#bIn+#&G=706Q}FMs&OY2{Urb z5J%y?9jHY?eY`^jb)8?CYtiQq5k147-30%e99l)Wb*Q7F3CqPjclNj~&%0cK-HPx8 zxq5QOupCd&`H`qIG7{Qty~1r&O4W+-B!9wf_OSTVEoJNw*B9_i1qUA3N6TnA4f^jw z_Kb(P*nr)(QTILWvOdgirFMxbZAFO2%>D(Iq*GYc+t`2ba74fR+44s1=`a+6zpU{S z`j&W44xfd?QJ=i%Jz!iZxKY$6b z`zMRk+u}WWa)sh5Dfk$*zG+2tm*?aUGK_?c0y9FCC~uo^9dSRt{r=12__j_Es0W;J zwxT^TR2P0V35(2b6j_HlstqOdU~mXx8^_CwVWjAcjD*Y8>iG#a9XiGN0LKNmMVXoh zja)~pC;f1D3u*jVxf?MS9n%>ZWj?N{8OPpm{Ui3Gl~E!}hlKs2)} zE~+}c=M7Qa!G-&#6+(}suk<0I@beuVZc15<#Qze0h(uKJfz{8QaqK2FJuMuvu+Yz8Oxg|QvTs=ae4S9M!yM;7;hnpm8T)8LLnWO{Z$g2N)kUir!SmvnB;;o(}b4Es; zk)BX11zOJKi;N*$5J%c=@zERe^*^`4N!~+m8CgcX2-D5(>*ewam(b0f zv3t-+_d#j&Aho(jxRnqSe_Twz!FmJ&fB|KaRgdrsaVp9@2%Eu3SWjhFa-MxUoHJYD zgoC`CqPh zcx5zFpkZa=nqC`mAi*O%;Ktj6Bsz_Z!G>GKW=>=Eg-5qWb-)#1<0l||?!vDYyo%F_IfufokTxbvg8+SE zILR5SsxuCstj-L68GnUH?}lX@UeAw$soR*@Jn zPu2+Z;~VgEBLp+zuTLz`DK-pYFsAOX9;;f#!?<5xFVCOph|~3UV1y+V1>Y!P`S3We4JZ>!=y!N)U0`yq$z_aeJR+Ia znHJRIYUagiOLlx;7MS=w?&fvEQ_H-yT60n=)tBd0Df+K|@Jy#l4j31nF?gPdO~$L75nwl&t4ZxA>K5|kkOyh(nd^tgDWSKVZ7ehZ+f*uB5FlICm<1#er+%B67>dH z=5!tKcQ9n9Cut^Axsf0ul&~|#xRj!--fL^na5~?N9irIOm7%|kzIVz_@xpe=#21Rh ztht%P#J_@vJF93WPgT)9zjA0b?X50vargim9wQ!tFdSAoHNPq^`rai8ayksFHOmdn zEHByah;$s>;4JKOtgDaoq^{(g%E<0)=1%b!Ym@unvsYddyhOuA|I=CJ*>v;Ubc(xs z>$qnC2~k8>`xwr@I{Bh^btBGXG*uvXXI@Ggu#g#JGH$!(fSR69 ze={R!XW1{HlE>F@!%#PtdQSdC2HuXOAHZuO-`;^Et!vC6Wq}UC1T`Nrx;CMRDmphU1 zI9$0t(f@?76dm0_q%`u860SS(L=JZ;6;v=HzG}mvRZ=sqH*3c7IgL}-EiD&6{U5MR zgz;jsFJ`$dLmt(L_RFbNHT)vE$ZmW3OqD4E1D)D@?oPha3qd(;feU|nx-!!CIsPbk zWj`iXII0`vSCYc;2Nqd3V?NnLi$6#_*zoZpL3MKr(E#qU@W2u}7o9wwyE&PMYF?F{ zb&bFu;21glE#q*|9518u9%*nkMOJtXMu*!69?6jxWYZa6HZr)J z?Q2(OmRg@-4QW!Xfc_wYzONw3f*mJhe=-T;I{H%3kNQ3vk zhDlsX#ZjP%93F~m!eIDT2Z0P{6CTa#sSz_l^s!GpmWW&Pg*8g*1=h>a*(OPzR?iyR zHN0x`rX11PBw7T5bk^@^Jxyn`ICchr^zevhsUA>s7#M$L-C&Hz=TY<>yaUs~PGA~v zf3l`?-`7OV>xjvE+H8D5Up5Pa?|VH3mm~tPKNr4!AX#~lX{jryFk~@R=Dn&uc4%5`tI3b~(|Yvxd-=%%ssqywe2ykD8c#xqJvbVKiDioUt#xrFLCa3 zM^aWZxmcPOY(p)UTHPMw2CCOC(?FND5cO*BMb(R`1~2YByZ0>**v-H%p2^Cw*2)^* zd&o8cx;jM_4J8k3)a)iEd73UkRVMo}Y+pnXA0bE|=me}H;VJ}Z?vlbXaC`FFP0{j_ zsbTq5+bc*4lfHXfFh@PO17RO5PiGhDIRZw-LB49^S0}xu>5iI*c~%vdUcJ4%P8OFz zts>Mv;UEv!68OUsLUKwUDAL?4B*^7e`eaW=3VgS50R+1IQWaM~!ArB-ov1%6SHi)i zuxN~De8Fo2R_{(aZCtQ^BZn-A&3IQ3QkXm_@puGF3m7(kE@8$5*QnU`;kpY&l|k^XlP1eqUeIpc|1LFN;A?+=!}axbw(;nl$x$QRIN+pP>#X^tPLMP;DHy$ z<{k8_4c1KTBU=&I53_Z5j4qXSrcw3mq@HGmG~&Vy*f_>j?AxJ?8R0_fVN9Rb_}M$g z^HLAv12|w!r~DX1h=up~!;=oQ2?vO4e*=Km#UUO_>7zWo%l^biG-Z52Qh0>C$4Aqc zL5_iFp*N=ZWT~!=f*Q4_QAQW*48G$Fl8}omnm1~m@VGHq+j%Y(7}^swem@mGoLmxc=PC0I(>+!Tg?)w`XvYV%Pis}+~I{5xn3xL6VBnQUpd6qsCUZg2#jF@G<5QLM_$4=jPR;cJpzjuEk{v*H!Mstp>$g`-Yr!`k$oM8%X>2FDWNx5Lm~Kc z6J0oe&QF;X-k)z~bCgdPz&B(-MLjV`2&=bDK;8`cDw`C&a4i^?gw96XU><@h_&$p8 zCUh_xl?$KIiUGOWRll1#Ua*w*S;??MfI_j;B)FrmDu@_dLmvGIrSxr`8rNuB)ofSQ zXcJDxJL-w8Xm=}fBazTHvvOg5F#(yIcVRP7^dYaSenY!zC_a#MFJf=P(Vw|=7%|j2 zrXZ0FY|u#=5jjMT5`ggpN1cYM&#vx;p&%dlta9^WFfb`&5J6$sBi~~d!4MMDpjwA& zKehcd_d`qjae9F_NsBIPA=tQE7dRD!TWUC#z#T4*z9tM-gBuH)&M9|3V;bd93~6_D z?yMB2K58EQr-E&BUO2;EM@^x&cznW5d)yZDEWB=$JT)!Gi?V3wJ7U~%Y_5S{cc8Vg zAOPzjVNWDwKzVd?_528x3ONuvOR9k2VM`xBuYo!f9%V2f|2Zoy5sLL zr#r?S6QdhW{DK68SB4p1v`X=1nDI425JnwhWwjWZ<28dW~G7)A6nAlqgMoG5CF;6K%A`#AfJknDiU(2b@hvMP^1ZoQ4 zIJ#)zu)=RH=Shs>~l?$_sv_1eC$8B`8hW0{0q)wtCM&$_aDEaW$ z@&Uuj9JqmXA6{+7BJp*G=Pmhep?#UI_i_bO*1tiJ*E(S^ov>Cnra^}6XWD=4zl5pH z82dr*L8~BJ@+A)F(-2*mOjPck(u2yD1ZNIZ@vFjoVcDR10nk6WGEsY`H}CD7BwFEF zlif5xsu;4PdfL(`w>Wa(k|==IU@nXFIiek_-eg@@OQ}X|@1tr$HoSQU)WVgsqRW(+aYP9(|lX=^oMyv6g{%U^X&hRyzAa z?T|r8h=x6mCx)eHQQ87W)n+$oSyoeARHsa&{gsE!XpJ@MuwAmECgn3JMv@)4DiSYw zP+#e%BWsZJ47!##?r8)n)N)6ON%c;fYZW7b4zmmzDGiM!T_0~F>0`@Z$>sM(Lv5=Ogi?MI;6 zIHYy##DSJ8&86rqLCQ`woIDHsA=vz0AEKzbG{v7U2@bOr-Pk+|;Msx= zaef`mhsO*g7>TE;;i?`x4=vfuL5rnm$Uuy~Fl!y+Q-Gk=A$)wTA7u6VGhSt$!Jjmy zP*$I5L8UYTGh{oV<;>F8JD3u}4;Uk1Zv*uWzuqk&4C;%!Pzkrt2*LFy%xWnKFpz5@ zt$2dtye!qvVvMfrxX`}kVUz{&WV$k#9U*!E9X1(naDw>=9pnae<-!X22P-EJTcNP2 zetr+VCo#_99F!srKCvP^@VuJoo^iOOvn2#}54mXL1EK;2U&gPXHAN#eH+D^w)_1S? z-Y>poa|10F1!Clv(+u1Ku?!%)`5qrFQ zQl`~j%KGq~RKb^D@6<7nPH)*a5XabJSRTlohMJGSdrW?P<7f^>Mno~f7B&z336dCw z2Sargr@DaKmFm}9*pNQ0Kf!U|{OMs_UH!7hf5Y_?e@6I&;_UT4 zFn4^yu@_uptZpCR12268{sF!42{8Re7$Z}`C=Xgn?2Y_V2;{{T_R{SYHS}^zSHHF} zI6u2H6I*Vkhm}@W!H}$H*m&Sb%gdo`iG90>%nzczHS`9g3S%FQ2+UuYWBY#53{E)T zOk|P-4W+;AP$Zc;^wmdNW=))qbX@%)8P*aVozSc5xOu93%Ouwlo(&Cq(V`R3|&P#E2tOi z&Elc3zkdRHE0wpI<;~W)QtI%iyNUy0rYhHCFW{Y0ePrrYVMkIlAWkD8Nd?r}Tg0u! znI%@S*$Iz5g>+)sxC-rU$VXyDuNJwb6SG|7dMCU5824S2i-s0uS(Ypq-KinGz>QYd zof)UzjPD`;C~iY(U=3}CBfwN@U45oq4K1-xFW%&#Z7p+2`OTc#v7F_!C!m(28v}WF z*%-95(s*spr(uxMSy(yX-Q+@Lh0THjk50S_fa+>J zKZH}6z&`0nxsbcdSc@ZDm3~i+X$%e!avPiM0OEy3I28Z>lJo5 zk1*%Q*45kGhYcg%d*`0=!xWok?CRev`HcNuFSKu(0x5rOqgg&$NA1AXZ`cpR`*|58 zWBB-FdjTo8Yx(~&gZZ8Ms`4K)kx!Ji#04(azF{(+fbBTlsM%SBnGq5{UDmdoI5F80 z4Ye&cTpjHTa|c3!`G4RfVT?^xhAabckGQ-KK?Kdyv56hADO0ngHvluRFxEuR7uzZ& zS;`jxW;hl+^y9kvDt!yo@Hj_-?j;?7@nFzv!3LpYq4w}gE5>bQ5koKbuw3?QMzM8k z?fFPE@NHoRJnA`b4tWgR>+jvb=+9_Ifv}A+o0?Oa(EN08bAz3>6w$Bqb5-ltzR`Jo zksr-Eg&Jn_{rwDP(V)QBo(RjnJ6wDntnM`%@zZOzaDZz@m@Qo;6gj`fIuG~v9n~n2 zevn_Y#-P`KZ;e42xw$V@2YI81N@QGpd*)O1-s>ib!IxYf2m|Gvw=g>xn~%;aXv5N7 z%N~ov)vHb$aW;sjKONoN{047~dsQ0R1N+n(N~}W*``HixN7d8<@R-SU9EpQJ(BxEj~K?{1LVmi60@=O^#lu zX4~TE1>`NZMlYmjSR1{7*)%tL0o6vd6eV6jZkijtfSQE1AM~y*C73L3EU7g>Q`pwg zG;51sW1RAPFpXFbgJ-yr0COBV03Ooc zFz)5t&0M}N0L#bfub-FSA~&WgGs0O9uf&n+c_WYC*SJ{D+x`%?1-4H?d7qhkF`Q7< zHTZVY}>;fl&bG{CXa1+#lf{_$HF~e_2Ggi|uP3(xJ{neP4s?r;J(LG+6 zamGesZsl@i$_pNmZ^WJ^|CZb*w%7OI!mSuG##&nI_F&ql!4-Xn*&$%?_!T2R6%DlV zKTSIWYyv+o&6iypD-|Q8j#7+yV_S}G?s#rYyq!(s9K40V)~2H3vI2p%MyLzA>aB>B z-l{5CSM9tbYc@;1_3~{NZYzEBPsrN5)5KFq-aNPCEcr^%$cc-(X9;pFnSVhbhJAu_ z9VdiVi%&tVzXQqDc8PA=`ADbI250S1s2e)9GVO%1NUmQf6TAGTYUKrN&M3Rtw)%l= za{6gQm4S9MFO_dgeG|>Lr4)X%&K47+((N@S;dP9m2&ZG%4Bi|mK~3Ss{C?+n zC{=q11b(U4g|M}w72DajiuqA@3hAXDtWJ5_+NP!ceFw{voj0>JJ@ZyeMJy=$aF*IGcyOUy*!LYY78Xs97Hq-cW9vy52L?72e&6F%{ z0SR(iO0rgsIDmm!#W$!vSKrf_NRrfjgw{n{ufELiCWhaOME?vf&(GZic|2*<)6|`b zqk3+WbRL3x;Dgn2z4l~UHt}8})v7Mr(vH@M%M_-miXk zjyLIGn>9_Akg|HCLjX$hh^yFPEzyA$!pVzS1=5Q-c`yA)qN2E|E+PpqAhN4(Pz0)V zg3)HO|KXW}=8)f5iHM?tN)Z(=T33TN@w?mLc1GM6n+LE|{|h|ME5{5Zn5*#}B!v0Y zZykX2D4hXeuSc+CHTmLzwY*36anOL2P{#QUCF>d!?vgEudg%rlZoJ!igPBY9vW3`( z!6%Uq%fns_UnE|ts`2T3Bm?vP7Ao{3IUET{yB*RGO(V5|h(A*8P(a$|YaX z;oyuwEM#_z#?txb$`=yCBs=>DOzG@imh%gN@oXq1ZQsq(;F4gT+pMq;Pj_W5SMH1` z#<+#iovw{uzk*XQtQ{AZeKak27R43Vd&yf{hsM2@2?zxJC{$uN`EvZhg<hN0QKUPF;=jgGW&|H=O|2= zKt&5}+F0hAsn#gUT)3+#fksoGeO%w@Yq07d%JID8gd*D!-iG$Q=?g7P2Zm+wG7k6$EaLe>!18v630hO~_;MN-tjI!*l|l1m9w(kA zFuEkiOAya6DjvcpYJpq()>`({_i*Kq1cPeI=acCHl7}Chi>z3YUL4%Pp-U;Et7)jI zCZDZ@CDOy`W(KRzQ#fA|>*%{!3_7qwlD6*cK3r(ER{E(LQfHFn`btLs{Era+v)UwCl8lJxl#VDt%WhTz{;sf$Cg^Nl$Q>$ z*xR*uGKst?QXxymvx(&UFmj>+cq*QoOd6|OWWze$ zfTcOQLBK_mMZG7SkJoE+lUO7w0pL{Gd7|OS^q$;;O2Xtuu?X2G<|VFXZtxtFV+J6% z*f9*>Iw#r4mq7AU4~H$f1xXnsatjeHm8Ryy;>)7U`(pY|SXd0EkDuq?Eha*!sX1e; zgD<<3vLiK1+n+0+PZh-PCgC`WB<*q0( zL@V;}Xt-eqU#8SLTHGbKIIv|LWZhyMi*Ojq7oa*d+Nouc3^dg6D`{zsY`cq=sj|3_ z7DySv<=`pzFD4YMTJrW_PS+H4ngDL|;o85!6<5oDft*?RGslx$4#cquTQ7k!MpF!L zfjzqm|L%LvLro`h4jwx}LGaBlxlueQbJc~nz?7`jKrn?hfWEUOopVizOf3G<7cmzN z#6u-_VJgW+-WlHG^wHOquXg6={1f>Hrnn`MY_$r-SKc=m+_G8MoU_r38u)D_iAq@l z znw5f~PwQAy;>JRwX!I~p++Te zuXnZHX!0sU%^N1-tyAt6;Ms$Y7Ad36XM4*oZD?Ioz^&m%YqY2n4>9( zL{<^=S+1^dKteCWz*lVwbPFf!A_(NDWr3eSDM=l|ROzOa+VU7zuBS;H7!M?)OAQ?5G=Z=b^@iOb;v!26+I#`jMp@#Lo0=$%*Xzwq32dqUUBCM0ibLkX92O zt9rc@7)2DTx;im0>V{gQuL2arV4z}AH$eB|U9NPwhJ=EbewJZ*1dx9yZ5d}v3nRfw z!etLa(r@C|9E;cUjQ&mo&E$1zAcPC~nvZei)buL4C925d8VlQocWt4wwdv{kw+aNH z6S*9JX56B|Hmn1!Gi&3_-IS|5e2c(uV|cmwHCSiv4T5BX0CnQG$&yJL6r78tsGje; z8oV~mYM{;%txd7Tl_Hpl5~pRL6oYwBwF@RXHwWlQ(UicMBFHQxHSLMU?oi(CmVidW zYgNa{wni_t-CeyCY)ruwnHLy5eGFsCn|=ii^5e;uNPeTlnDhLOA#Tig#N-K2yxMe6 zfSBwA6jPnS?Grs`Txysbdv@edK$zjL@Xh{bJ{ww}scDdj19GCQF0mYLP+^=##aG}=L`V^E%8&b+?tw^*J_EpelQa8syfsA{19s%dkt(1U)r-toGE1G#h zG`61tv6_|1pdB2~pXn@Ky-h;*NjYaq70oz=- z@(1UDxse@)a~s=nY3x6I6U^^w{?xeRr30apT^msY2RLJt$_AM}##ERo@+L?UJSy+Iejw*wktVQf<{2R$pTO*WCkyGT! zm&LFhmg+gXQK>#HapwPS`Ba@@z4%hSnSjZlY4*G8zwmn__#S@e%Ui|sm+|~%Jb!VA zaAWcIi>Epi?)fj%Gyk>yj`6`cXaFW;1b!_d01G}=`DSu^Guyv;WRdz}9rckQtc4&f zMj!CqV;=|caTp&*@o^j^}U$hJTDx-g~;A2ar$An~F85QJT!RO}jk_^&#N z0CbbZtRN^|!I2_B=?jG!2xa&OoH+?;b{yCNK~C_^R^b6tctZWke{2da%JLsSu~1`H zRe!}>kXH|QiSL2GE5_iZH_$T`TZ^x3q5by!ci(@H?H5&7Jj&DWvxlD%#vp&iqu$lv zi9S-_OziI(QwUF|Fu(`nu;a&t`3sz};_*1kik0}d;ANCIlRKP$>hBmWw7@$55U3#B zq%c3$c=`1XwPqeU*sBNk>%rq%@VTD$xt{j9p7yz(c2>`cp))iC&BY-p+JQTw_)DfT z_Fp3*LX3v=B_c8ysmNfY9)qPX412`Jhe%0iq9ywh30W@aF#8}e*%ztFzDPXwMS9W~ z@{6wwLw;7S$JuDz;3d|g&z*2M9GD%&Smf_#Cn^n@6OQnUZ?rL`1yMmjMloNZU>$ss zk_jHszF>~9>^GB*o}3YWRi;E8`SY2sXh|~h%OS(05y*cD!dw!_e+e2bCa3^t z90l_z-u{9e`INLmP{8Vb&exF#;5P&C8vJAO0oV=x@e}mD;a^S``vONt7=KCN762~? zh^!qT1*m4`hbl7X+MYdjT;mZ(85;Stz@)@Ve6_@*#2ShIT zJJtE(t7-JlX5%$ObdODshC0@!gY7?0zgI4=@Y5hrFi3TD{_YbGc~rxDNT~G_A40-< zh2Qb;5WnBYgGFrFOKKb(M^CZA!|7SlYFLeL(pEs*jcbe-)-;N|entU_D|{wM5XLY+ zkLMSBQl#RTHv=XJg4EWKc5zD3D%XS>Y#s~~6?Y?6%ahG=fFZC{6Od|nG!!T|lMD}+ zn`?hC7W;kBJsqBNn*v!CUzBQH)r?X*@?_bjOP2g}a|h8wd!SPvfYyfM)JKC@?Z`Ad zmoSmSIY|qH1r|9-LTo1TH@^5(y6SShjGd-}7*AY8#4@DQXMslFFkxS>QJ>WQsw?M3t$;fN2GVY2jlc=0pF4^BDq7D zcfokLP&7l&*OcK~^c)xzuU=t)TgVCDUH~YYd~z!Z(P@NQ&;`?K0IP0c=?$+Q|PbZSNFyAHyY_&oZY)&_{;-4 zEEVygy|T_4jN(?iW|jp1#t?%H*;GN&FVK1}T@(FzHJilpf=@ciQFa%Q10Er4R8TNW z5siy7y(*mA;GBFHZvQD{=`RAvTJTDemwhPc8cZGUwe2 zLI-6R{)+0~4xtZ#!OkXY87ONiYukZ}!mgHp@gTUwW zvHIcte2iD+bVQt<&h=*IEF0~wW%ZY54Df2fA;mkF8~k~KX8dgWFvbHjyarJQH9Ag^ zxwjz$%M%i;_~-7_Xno__q^>AefMea84bTR`C@Oz^QAjpX+cNkeT$Eds6@yjiNDz7X@RS{7>b+nc-Y#Mm7P)8 z-E3w!u+ZZr+Dc)_ZOT?4B6ursw#b&mfddApkPs1~Xc=;qbA-IwJK)|Hi$EjuPTz(C zXJ6J}3(7FaOGgy;AeeD8`Rw#8S*$G^56Pbxi!s>6Jua3`p-Cok{tP^bob(J( zp9=nJTzxL$gvvbFvuJ+4D{+H;&KG#Ig)$wdfKZ`=#$dU|mCTvd4fo0**2|Ssx#q>q zMD{umYAkqfFF<2bgUv4B-b@dw+VR#+h@Y5#a~5M~VW*{_+LC?mLZIy|zFxW)&YI*3 zG#b`w7rP^BP_I}Sqa~dH6F;K8gy7*@S%=#J7faP`k+hNUG8i3CqcfeGp=rO?#xIAFmUS*j#I(vjjjtf)qLKjVPBQ1&8NR1t?K zZXtp__7tw$u|o!i%778i7X}o>(7cMSgNWZ91|=fU#8x;8mjuG z1}SQ(ErK4!WTtM>F(*&7 z#AVB2Q14G3+gPy6@_f3|?tq?GWEyDP5hMV4VZj~2?Qcr*kp-a`xN>GJQ;v_ zWVbt_sxs(olJXh`@X#L6mE&;wgnRUxjJ_f=PN0)>(KtpAxVVB8 z88E;2MtjYt&%YfayO|Mqb84_!o#efxX1w|Y1=tEli&Xj0m5N4NEG>p!PbB65)(#!+ zVv*Rer!E&GUK7Km8!9Wp#Lr$Sw+U3$@De>IBBZkLH+IhVIwud}FI!aI6;mII&BZ-t zj2*Pe#|tQwH>2>%=yYOsWbdcbFZ`Dje8<<*N_MS-)0DyFBUUh0t?CY42CF(%-B@D&7BwZ5%+%-$B)KkTW~aZ zj}T8F-L(+Bf7%fytX$qn+#m;mk_m!`zS`LSKp}nPR_$2ofj2O4z(BMk&!NU(|Bm6b zNj`RoY&NOG*`4>1QC~Z;kx$NFwSB*m(Z1^I-(JAB3~aeW^PC)&)W6x+MklJo0_t#{J2Q; zsuo!VvFhmj9#W|5dwH;iTp&%+6b`MHyiG}}aTvh31!*%+F{iYp zFeEGpu%U!=Ic&=xW(K=hCxeN534FdbK|0VPh)Z0Y#HPT2x8&3tkeQ%VnB9^=fm=a{ zFv%eSQ@-cV3vHD{VDW@z%#@S5FZM~2(~V1x=Lx`~e1~(zo?Aeh^4=~na?0nbu_Z)K z=LskU38<j2ppicL@&%G+2tm|NVrvHU%l#@G%nEH2U05L=6TC(r>+*G(A`A9mqf1lg8K019nXLqS@cRQfbQ`-LjK(^A>~ZcxVE#&L zDgVB=d4ZD1${jdc7h=5B=N^%2V76{sH~oFaq&@-xYqxyL z$=czE<_({`GOu;5G;A9)6E`dn^+eseLYGF;Jfy%C5Ay-69z$>Nyzo!$3}7xB94k_g z)~fZx7=Kmp6kZr*nCroRea02?37CR0OWU{-(>Y>COad`)Zh}<Lc{PRQZ(73VDh$ zEgRbnU<~@VcDkigEXHA{tS5o$11<$4qkVWcZA^}BLaT1ZU>qx(MKFPRTz<`=@eCHd z9;MfuZ6U%zJ|>d&oAB*h*!t8fck8Oixt1|@b}3)a7A(j3oZSyw{#I|57K6AWTaOCp znyf1b-SUbM$3BGu8dt^%gEwE09Geult?Lg~^SQbHbbx57Ge3s?2UjmqQ^m2ry zlL=rwM~BX82I~cNMHZyA_*Ql<&o{xutCtWd(Nrvih)#`H*CY%6iu#rbd{2eXS)d{f z`!GpC;mp7_!kFl^n`Nfn4tzma0OOQgJcM2VYMZ9elMW)27?ca;YXw#uJa2nVa^4A) zuiDzGjq;YV6%G4jNj-S}VVffXLqUfL<}0WX3jxL0-hbXQ3tjSFz@XV zHPi9KKOwl{Qb{oG^>;Q%Q#ijegJ(~CTS3i zlUUBg$FOW!BZ+z}CtzQd1z_&hr2}?#M%UC%l7k=8{pa=0mOgPKF{5!k{L#alDBcehx*L+KY51vjh%g97hXbIN;yYyvfUoeG zDZoD}Ww`nrBhMCJbjskyb^KVUSe}YBEK2cG6)}{O|KUR|9)rsN&JGfK**^j_x+n5v z@BGmt8q(75uX3bFwZ>cySYuN9JdRi&tEbXo3))ny5`oDM_@i4Y`SJHRQ|M(IO~$XU zY~DacdF!TBZ8iFVBqyBzjCT1Pt4T!N^U@bC^g*M3-i+8Z0HI?mq^(m-H!JjPIZ48E z%wdSMW-8;TT=Uu`=2>2r#C}pS{K!S*5VzKzeFkzen-(K;KTG_F(~!6b)qUL^%<8+B zPO={&mK3Da-CeJ!m>*2rKx1o#LkgP3SVNckpTg$1=)JldjYC7%l6n16)db38Q$qjn zabYj~Xlnn_{DftKb=m1mch~&UMV5X5{%cB1_hesc=FR<>pj9WCF&IY($FHZ2_ z(NZZg&1P~TZ4L2@rP};pfi3w7Ln0Of)g-obZ@Ly&IiG&RDB$VFipVy%xB(k zNk~@5w^Lkc!Tn7=E0rU|u-}lbzArWp(={rVQmYCekNMyM57<^XDgB}^!mpP`!os;# z{F64#C5d(n1^!BO+ zJixB6fE@_s+JPB{x0P18y~>6UQCKg++!*Gs_q?l??s~(1>^28rYH!sSDM2Sfm#MDi zBKL6b6<|Me4EHrmPO+EeC_7G8$7RcQhvCQu_jP!)n?#Z9-Ypg^COoEhMcYw*F2+bD z7Zx>?_OzK7&a9lY%%Fjnhj0MxFwvPFTg5fDuxKDk?erbtTzYm^^t_n;D{k&0Dx9rw z*kO@+D}zb~+=ybd7`$2DV|)hiE?LE?9|z3bQ^Ir$a)&Ka8a3Fp)03Qk_hI!7*Tj!z|wUv&3W0RBy^FobwC5drMEoLZ67|cSQ zNR)P02*{K=&6fFKkzgMIn^6v0-MLe)WuJ`uxW#zMoz6dMAOniI1uhE8RS`%I8BoPV`JHh z57coqM%*c)CQjrxcDm*jq8$y-?YwN{6%f#5+*6FYUS8o6fE-sR#&mOeRlYJ+gBN!V zGaT06eyOtP+k#0Jv0f}BEM3AZ@V&1&P6fXBZ)+sX5>*o=+5z4;mk0L}il!H+&Pxk4 zb!AGaS+S56IzJ)gqcZ058BYh~^IHy135F~7HBAi*X6`DYS@*rpl2&lgl6}@jV+f3I z-1E7A9^V(E`3qv%mNy>5@?&jeFVcE4EtZkZ+8LFMtAaOAd_|4EN2bBP43AkGjirnM zG15%Sj>-dA+Y+4;xY1NCBK9jOBg;4HH`6RC=L}p6nVo;ZKyWl;Jzv7s6fi8G$ZalD zRu2_fM?-O+KJTDvz_R{e+wAA4d0Kb^Cjs=~rEy@)kQQGM;|eefwO*68;iFbMkl6>U z^Ez#^$YfJg1kt@Fm$iv(oGkpJ_2B)}c*RlskX(nf1=6|dg&8WZV~>|IXbv%Y!pO?j zkA$Z|3u;1pjWWP&OR`Cc-@?3uw)gds|AO0G%e%W8kjv1YOE|1+%CyGiQD7Yj#bR>U zX;0I|wU4sTOj_(zv!W7h2H?y?iL`&o|-;U8Ti@gU8c?ppk(lot%*zp%()LH{*H z77YKtroiqw*j@I$w5B+(Hd|B%wR5V&v4bLj`=`9iDu5vpoB0H%xzJ{};CK-2up1P| zG>X@!ZvlW=NSO$^T#PS6M(5duGq)N+L{brU#33`&6sFBu-jJs_HbXVON1GC2*6CwU z<2sndMvtlSw<2-Rj@g>bckVvmK)R#8qiI$?T#oer8S@2P~Eo}s662aEwGeM*^gZfOV zEq6(*e&Q5H;T}w*QNdfZcR!?J-NU=V4Q5_=LIbG$tjSlnIRGc&uFJHjH0IUK6nEj| z$()V@Al>0^|MhI~9h)0mphn<)yvg4J>H;#}Z(Kg%kEEWI+A0Kw#wawb9dVO|N(`$uue5K*9#*7c z8);oqgAO8-9dE4xU`x9PY=$LFn$=Sm zpv3TR5uMgeylw`RilW!B_QE5Jl~P(CV$fkzPD#PwZM*#6-M*fr+btd~`T*R`tC zV7DzYIyI@i4cAtViQ7@2^X>?xv723;skTIsa#L|4OD{p+MWzwwm&ev*`)Z%Q96Ghy z!Rc>YGGqQYoz&eN%+(bfKrNrwI3qAnE_zFxXG|u6m0&Ywk!zfB8GMa9P64#ffHQ%r z2Mb>7X2+%TJ!Qg=5<7;;Ii(~k5FTZh@gqMHFU3j8_rmn*DS{wdX`^s2l}JIxF{j{R9k zHD+mz^{uhqn0YIMHi{5)XYh87Jf zN7$joqp!BiR;TPp-c94$-Z48GD_RRfL|kN1ea==?Me&ejd5}}A?P{YnO=~^YxgvyX z=~Fp(=KXb@%Hg>DTX(-8BCU|oSEm>zVVi8yS?xNCE_hHQ7SfERw+wA$;2@3&jlyu= z-UX&>6uZsDDep>%pLty3GJ-lpO^5ENR&YWo3cpx*X6}R~-G1;ni4phP5NU*q9#4&n z{sBQkhl9p^CvDnY2~K+5q)?*J8g{?fg0=$gtB8512O8xe>iGfHt?>UFn z{x%$vRgs4{Y&)5rbd5Q7+sd`NG+&vd{EAO~`cCapiaqZ*G6?9|%;1RZ zWe`qYi{OWP><5dLcv!7*W!hAC@Q1sa8jy+gg>J;T9-K4-5I!sLc&9m|v1Dabpew6{ z52g!l|7QFdS7-It-GIWpnxJClVa?(N&pGaW(!c;>uG6Bs1^v7N8^t{$n$*+m!tw;6 zT72~Gjp6a2Mn&lNZ{HKCCYkjVj*W4%fCpy3%|MfuO~-{lG|bAvhathYseGB{$sz;` zhQkA`1=xk9v`)uH+3=AEZy{KJ`GKZ`@OAacU>+bGg^KDu8G@qy9JK319=3U4nE*Al z+M`LW(N2-7DrehmgIoU+FQxS!%Q0IzP97=+@Vj>i4<1}%q;-Y;9T*KTRz(>@ z8PhF~wW>x`ak3R#9!LbZp%_P14BXN-sC=q39Y|OU>cKa-iU1LYv!Wg$FD1Or4JxL0 z{`yU1E@a)%T815|>iJHJi@9FC7O2dz6vomSEGd%P3UaKbo ze~)r%N7Lc-OsA-hfnB>>SaTO)9u;#>1jLcKf6kdRgdJ@W$18LmOfxGXa9y1A{gEff zicO>ktv$^n2alv+TE3lH*F%*^u?Ra1gBzMPhoCA+69-O#0rCi&t=$#K`wSk_QTBR6 zPgxaT?)D7`m{|@4Lo7f_$OR_&9Jm~~1d`dumUw~(W9%>RZi?RM{)`l#-KntFmB=pv zsQ|m75fU)@6P3ZzoES8B6=qDDKmkFCHF+PhPkNEGTFMlGBC3}isjBfD`c6D;DQron z@Fb9Gj&F5y0-!SB!nTGL-+1o{JDyNTCEdTNsHhyN9%(!UE(H}o{<_%|5@Gtt@&NuH z=C~t2t)7x&aO`vPQ9KI>+^mx!itQE<&5fqyBt3zc?G3BXp`ABY2m2Z~L*l75GiFLZ zXh3MoX+XZXP`;=Hd^2fa9&DPKGbrRa=juWZEbY6Z=-M?_0x?MbFl^rS0Sp~41SSwv z@r{X}Y;B@BW+DV6eGo&dKt#t}V>ULG5?7<%Epamp48&r%rOifLkn^~4WJ)^{$~x$r z88`|bT({$&N6l3UsLafO#0@rQnm08mPIe#xnH867_<`O${2_i5mRAj4B*gUO0z$-d zu5blq1jvV6R6#sn-{zR##bsvrhl_j7k#Ngl2D4Cei?X;(rA}JYT?S?Y)~Xl`OMuk} z{7!XH23(CKzL%Y-6B6ssVR4g4rTUVVJM(R0@ypbkh9IUBB;RRVz0BS>k!^YWBt>j) z7p5@~QZ+gr4z1u%hNJ?DEnJi^SII3<_~20|$R=cv1_hxSlsSj0k~18e9J9H}9n|Fa ziDcYP23ctHWrs7xasrnx*^0&J1aujrp){fHXK4bI6UIi$vc+Jc0c8>5gP6UIrK({q zQPoT=SWNf%s#(DzGx@YiA;|)zz!sYV(fQVhB!LBbIe%<1?TWF+Cs8a=NTEsSNWiuf z7Ey`LUCIi0VGmZXLms|5yxqGN-&zm_&d*A7Z41kJvc!aMc+KV0_){ZmBi%MIbwtjz z6trqk%%MgG8ny<^x~q+g?MujhDc9P1)yk(P?4~q9(hc+mQ*XqoqU9zacOp4KI2~%F zYLRQIM2lWij26JU;F;oLQEL<eOCSHdT*cbP&@oS6E}tX!9_8e0<(ep#lDDS2`3Itrt$20FPY4Q)dHmoB%Oa67dHQ z%jFt}{giRs3ydi)i<)k(_H-YYDWIpg-`?IxF3Soqp49!fDd&UU#eVs9t|Av@4tGp!na;mzU&8ng5^N7@D1 zQsU0uAUI(avA@0xVxs>1eu)}AJnHJviV#Q=c0in#C92MY}$HUm`dKa3&ll!vQ8^UE1{Zz{w!_C<1jis!yqIwd`pZJrA!rERfnH5F;E@_6es6;W36aa@vYJ*}6U@CuOEbFRngIm>&jLeY{ z+@4F104_dW(AQt}jgMedaGs67dew9H=zwmRe>%Cj**&5QW&flLWdGz_s`h!D5PCa; zra2SU7n9-xVV-YB=umPRp7Kn1ElI(URGoy>k{JxCUL{{9Vk??!X01q>y})gmt+n)K zlAbXk3zOgR1mT3s@eBpmslFhPI45ItA(BtdkzaxQ^^)7V!c1;RPy+b@Q`Lx*jsQu@ zejt9?c?`!40kMSY62y<4N18_F@Io^fb6GwqYJtlYr4WG%2Tr-Vt=-i1vfUJVoin(% z#{eCTN|mqyAwFv3B+`yAKP z%(~eL2f~{vZajdY>AEg14OG|oBZ$0Xo6#Hmx&JF3(x@(QJ_N4(Ouzqpy1^Z@nb6@! zm#zS{bG^p#QSAit;*F!;<2Vh6?+;Lw_yHmzo}HFL^nk@612Y$y^L!N62ysk^4<1kX zVVvq80m8A?K{;b!9S~}gCYzRcIDt&lo7^bx~31w6b>4*<`7D%aQkXv=WEOe)cP> z%SgCJq(wLR6pk%Y7fQr6Sz5-e3EUYR+83*XTHRgenlvM^G?_qJ+8RPM4Tgh$ux?1k zoFIVd1(`K`zuK!C66jdErlmxw%au{*Y^`5LLW1zeh7=m}L53^2iS^A-T}*MH4Fyw3 zM4_@TtNm>8=iAky97JLAM(rzFu|S?cxNVw4QqR#e@Ni7C$})@ir%*3i^HWfKCL|RW znR|~qYw)I233ih4p*i0a!DQBKh{9%T_uP$4qF<3Be17|LPwsu(-h#rIpySkqUtzgR z=U6xvf>(a9Ntk4L0Pmm>W)92s_Jv;8vM-w&%3>V`P14#+uADBO9~q|r>h&fnt}Ko#Q zB3*z%n2C^@7x?u{>c*&w0eE3F-uW>ZW$`#>@9C*EM`fs~@$FKu6S1Y5&%k-%>xsn;F z=lLZht8zxzlbpME1NX%`5Ie<#c0V0J0{lHzuOQCf?={l>yu9x2h3`MTzQ>exk6OQ{ za1hZSSU86V^McoKexEzKe_z|BxHnSxPi|HVi2+|Ek5zP9K z0+`*PL{-F)3XIY_$~GLeX*`!`x(%m8QcR^3yS#ie>c6W42fy?`)FBsm=CaJ_V;h})VHj8o zUtNE=c=vN1_Wrujh_iqCFgmZ}eCogXIAYh-!GkybtE)QbQ?pC@A3pT|sgCpW=-ueU z#o*%I)pb3BB@8=?zo?^qtOw8EwVH5w_NURHkvU#GYggrMtG5tnjL!|BKg^N}(q;h>McF3oFo(LHg_)Ln zX@<*fG{dojjzYCAT0Kz$%J<5L=w3!WO0R&8i@c_%c4C%GOLu1(WN$|7Cv{!zQA*73 zLVN4Rx4WUu^)Ma=HP=gyEr((D(vhrC${cE#IingF%eso)_1_5ZRb(`(WUjZNrrMJV zE)#p!Xgk*xod}S`y2t1YQ?HP%$(B5N%e2?s=`eUe!rVDAA*P}QdF znqz!|_3!UjdItwPElfOIQn67;6?{rk_@g3~r`6L)DSOa)dLZ6m6V@EWVE;xD+uGp06YoH6_HjS@< z6`wJ2s{XBB74afmRpg=5*SFktQ4LBh?ek)--Agh{T32?bCERrp5kk8ul2{!ByqSGo z;h`|C=iE}b?!)F(VLD^Hi$q=V#WgU?>9;q_<(KCt(;@{UOhS}enUzE~^xAG@pj-Ak z54B^yv^(Lggvd1{6W$TUKJSXpR(dL9XEwukyMTDw+8)n(KgyzYi*<+>`KNR+!%9R$Hz7c-j9?o^6Y=bo0qaZe#<9* zV3P#*eM8+_0DbX!>d2Cl*C$K?Ret4ND@XC3xn3@H3x#|W3Z=JLaju@9xUnTi!S?bB zkHdOmBJf#b89(1%}v{*jhKd1n- z+|_wT?A~QY4=I;c8mq8jY1VXMU|hXnt=KH-bFl06$zp#yE;YwAg_-)*b}P*XGf=J9 zQ&Vc-Ml-cGIYqu*@!$Nq2;v_s7=j9Lyq`>H#G1fEttI9(z07k7AOd~K`2hF zAP<|Fd5CIOamDebWElatF(E1HicdGJx;IB zpJ_Lnm(FN@%#jFZo^97G(Lxx1FG0*q(tC*Bk%4JmJ< z-l7JLm>%bkOJEYzoJ-~^r3A!c{qyZt4T;;Tk`zdVeYl$%@2Dp30=>5vERTx;YSdn&-{A_lQ3axGV zolcCJ;{+*=vd*TP-==)kaUJ(}u}JIm%yZB;YRcn6j3GuDTo;YTd(&|TwK2yVaKCYy zNnhRJB7i8;u9_895F?yI$XlLIe@oZQUO*$uNqBMa(R#VthchYU+b?yeq-bE{wd_`6 z^oiJ`J$f37lkaD8+n2vnK^j=R@_7EgeR0 z_H9Ss+*3i`p~3XUX8KsceJ>d;%nocGU*u!O3#bdgejlNRBnO7~L3%~!WXJr5qzV^t zc{$+Z#FUT>;2SIZ<}twY3Idj-&_pa2G{%BM3+?0#CLU&=yn?uz-9LD?KSOIdp8J`X zVerbgUy*fXsKNc#?cL1pwuvfjnKT6Z_J$Y;Ok(`K#7UbAiw}+$bBdBKy8+!ho7h&= zpPPTiqmyzWkF#KH>zy-bBZ2Lfd^R|Y8-6?Y9y}mj9-Z|&IG2&cVdAPSmlzXsQ!fd> zxkl}RE8lH#<9}JM zR7wrI4k6Cf^XGLt*A|pb$HG8I1t2Gy0LoUzL6Gu!AIp#^o7Hg$ag>YoUJoif&?@K} z7ukc^LNcUXLf1|!@o6J{4MGrtjmR65^%MwVCrcIpap3BlnrT%L+!pG7q_yewZ z&ro|>ZFnv04Dot-;VrK|iLJxOfC=JNTtzbRBsh^@@HScx^&6`9d(|r+ac$`P``ObJ zS8JxPjTm2J(=fM9`s)~#*WB{_^!kM}vx|JDmCyoR8&anwm($dP+1nMz))7#p2As2s zM>`Pk?6bfY`DZevbOPnZ^!Cfu^JCI5V}rwOGx`M%&ofI+GF{1AGcf2*BbUK-Zkyo) zsKM-Zm5p_dVWpw?DH(E(%$zyH>MT0L+q^o*ZDHCOp~1a#M3ar@m^O*$xF%!IF?9}K zz{d;9kKAfXgMnY${J)1gVjbxxTU$-D*hZvbOk2)tOdikxC(t9D*_(b2mQvpzKQH|T zK<~vODyVBqn&l4yAmHj1;l^S@ z#hDr$9TQJ>x%yb^$St}^6l2>gbFZ|*JMb9stX72N9E`ULr{lr@)97V$ejF`pnF}>B zy$&Kh_828ZGHnUaIaCRV1E>UxN<@ny>{6D^rZBdpUU0mEAd8y`$F7aR2!ynqcCLkX zn@d~~Y@Dsp%JO#3D+`!cpoC|b;eRj8wN3Ue(u3A(ZUtal<#(7Vfze3UPtDw5i0>KH z?w?|Hpi_pd^U>=zPrTV%!a{vT&oMA$(ltZ>4kc5ZgLs_Fm+YAeW=a=0a?2Lz;3a67 zt?OF!OMor(G5GBmqoB?A4s|kh*k}zJ`K>e}BX2Ei%CJ|lGMsZ+!0$DP4}UVP6o@jp zN@dpL*&OmfnZu8K3RfVT1z(z!wZ=e!JfG zc*-~4q)&T7v*7c6YXh2sOuDZ8g>{&=Iv2#3PaYfZ@Yv*`*uIp`o|i3Q|D z`66o>9bi2QYwg;Mu?gU_3VbrIOc+~BL3Oq{IIW-PKqng>v`jcKBzgpsKT~1H0KslG zyE9E6H@SdhfCe!>BQN2@KGGGx1~gMI~Z-+O@hS90W6C_{7s zpmgoUr7A8SC8dYdH0#R3Hp;2iK0pTD<^!m10D;A$be~K8>(@@)uM466-(dh(@Us`U4F920NE4YU+wkPlx~w;TXFGA?{O|0UYe;!I zZH{#3-;&(-(w^$-!|PSZhw!iqn*Q>d+jJ}kdXZ@T`rG5Y!hdhC@O<97+Enn?QN6A{ z;CEdutLJJ}-Rk>w^$`&4`U<=z)}Im2TweVz|GoO(t5^T+0(p(AdqA&|*Ai(Np5y;l z|9DX?s;>&oDhTX|T~)sTbBxdw-&fVF`WwEOONsdlFc!dp17GCw5#Q75TLmu{s3&U= z^Zo+k&&Y+?ul~LZ^AhP;GE01QP%q~V;J2zDYjTfV#>k)jVXgUs-$g6cTR=C!oCtf2 zR#?4e$PKIz<+1k7)?2Cv)uil$-QSJbt6u$|_4>cBM(V?Q&0qa}9gFpQsP+4+|Fw?6 zk@L1*Hd~j+cL*#}%sc#UL_JUHDN@V=kUswQ5zp{r^%2(pZ^#`-Nn6Qn17Tm#0kFuMO2`ye&|s&VZ5d{_!nxVLfNa^B%R~ zsE_eGQ+r5bq*T=Y|F%4uwY2ejs!`#qQ8#X`-zD<2`9;d#AY|p2wEXJt>eSSlQzw>^ zbLbJh_l#CRy@p?SiBYX>WJsMHj|t-7wFaa6>K`~ezTn@o`VD{2Q966=T&Xx`H|W7S z4*T;hV(x)^TYbXU93`Qr|DR@$>3)G0MxL4iEIOa~Oc|^Z(J{w)))CAufVCUJ(k+A-Jb&zwg@|nXka$+BI zUXxF@#^moVfwNJq&m4b(^2j+^&a1!gj{j8@Kz`Ql&yqv5%KL|Q8=Bnf)&I0{7-_sY z(;kWz*qDDp$t%<|_*SOKSN~X2*^6}<{J5NLdA&pLJhJuw@9)jS=1ZC1tD_&MJp+X- zL0SLabU$OZUVtmq(*1uwF0Va01%(~ess1J0+RS`m#zFc;`)VuiQ8V96*DsFd|M*or z=`C7a=aFwgC$}hLg}$7jFG<^X&M%s4bJ<^{KhA)zR@++mLHzmEU;t|1Jo_0r+g!Rs znfwlFC3oiPOfJ;Pf&WLnlqN^1b5?MVMy=X1z^jA$ic((z$+y3vhRwcy^$+!WkcUwE zz=mDD!Tx%++s0{fDq@g3P_|m3uj?sTms{~nTYb}P+B42|f%3TGL{E{YMvof3yg~i( z@HKLO^>-Ynfq4CsukSSu-soBOBv&tvgh_B*XA1uDzm+u5D(%<2MmH&!HD-V1wH_)E zgt8P_wj;2OL%(XtE@ho4bC7~L5-Y503lGikMLEP)(lf+ds6_Db+09OZU({^e#Qi^k_QN9n1#3%WSg~%m!P_ zY|s`WEeLtBoQ@6)a=qx_-z?QbNC(x{K1MHO zUhl{lr@ArwDD}88P{Lv7RpeheetIj*%V!IaV_>mG?yM&Eh$YJAp&z48;_P3_NN zRW|aisfN!&yi3P5Z{1f4y_B;p@-p=IKpS#7R@Q)Zp&m<`m(^xtwc0$18(j(BayPy> zp56ftJA^;1M($cETOt-!*t(y(!4yANr$&|vJ@l@&@qy#C%_}7K}U+{g%zEE6G`Dd{0$>+e_0zquHsl;$V$h_)SM}Oz2(*VZA2AH3u-qLNb9{Cjc%p& zCCvH`f%=ps9%h%?FO^G6>qL!OEPD%PBjs~R#dC+WD|*t>N?pK}KzjeGQ0{P*SXIa1 z#g5-}exi1Z1FT=W8$Go2x23hbRiqF{m&iUs*-<*el;iHJrASXSw}oJ;=<)K|t)SBJJuY&=SF% zqkc&IvuH)HJ<@GiGqx{$>pw%l^&V0eqeJ{dz;vN!z{NU8Q+bWOrt-RZT~Df&*Sav& zTdw0Or62nP$2zt(Wdr4luC^%Uyv2{JtCtAs8Yj1Ui>lYw>w02so7h82+RpP*hky}v zSTAuDHiGq_J?$Xt&025=XQu-SCrJH6!flbJ;k`;4vOS#jnIj`tQ_A&2&u0m$u`o6A zd7T_gZG+>v(rASw?w=^Awv~v0b`s7M&7adho@IQF-f!t+HHO$*mQY)^q_kK>yeE8#lwCU1gz-z-!$Pxkip5 zrYc*!Mz#*^lQMs4EM1lMYJOn6njabu?b;8D(dxlA$Lic79d$`V^0A|(*EouD)qVz< zjodWvAxiKU*ovH!F*n6xP_V!XSi8XTmUkTrC1lQL{g7r)p1*z}m60RK&(lIriMUClR;$2Wo+dcI5b`0^bOc)sIo z*T20*l#sNT_MzMZsGru=OKgEgybHB^Ip`y7C)yLe`j;W`*b4gvb}KDj;$>K0ccV@( zn_m|fv`@WkzJ+nHPax%A@1@Nsku>L81WVU-U^m{Ogg46Ndbeo&lTc@ODj`w9#dH>rsL?yv|3MZaixzN?Y*w8vWCGCo|>uCi^j}8gPjSORZ|i%lw3?J zs`7f2H#ONne|kC6M;XpqQwC7tg_yisSp(82s&jX!m9U@SE=z>5&#?ZQ3-JN%+TRsl z&bdmY>tg5o0dQvgu%1oZqz04))Vn;a(Qt;S{JPbo#N9FFxKcCJ zG?WdrfLG?pam(!|@LIQ{cH|ZEQ&5IaKdw?!nh+ar`O_%GQb$n_)MC;01z1bFy;+$@ zH9k>V>-u>#lOdh*B;y#u9Li$9R$0T!w$Z-RkN&q^T3*K%@(T4zp%Qi-m9~!? zF(nLbRT?IKO-?5ddgC{rhQoVOGwO%k&@af5Y~`>oG`=Tq*i1{554-G=)2@s%z^;BH7jq`lR32tMsGZ8iV6(czk^;+{vo}| zO`HvQDN1J2!|Ni%9>X}aF0jYYIw_+QtZF`q7l83I=-o|pQOJ}p} zWt^K(AF7huo8>7h>-&_{O_3$yBl8isU@KaQ)-CF1<$E=}mng}iojz4?d6o4a75Y29 zxGK&oo%W2wIl)Nk?8a4c^;O!k{;K(T8&wzmC0HMpK`&hey_A-SA4B5&#JmP*We~C^ z3|T87p1(=BQRfyTY*U$gk*BFqv3_0?b-`$Ti8BV(MMItjZD_IEjdtNY0^0LywCg92j$38%P;Bf$^i~O^_I_tTZ444FomOiJI6ZJ1p9$Q(1X#IrS0Q&ac)<- zLakDEzt$4-kZ31|*S=rssB0{4e}}h*`X%#ZO(~l>%0?@7#E7G6>0SzNxz_EO;=W4l zh1&a5@_dyRSI%&r5-&xoFK2gNS41t!0BS@oEw#SSFrIW{KGSX1z+D3l+6aAx5{c>D zjHI03oz+EqA}!%uNmR~#(U}*m)U7OKS08+ZEa)wmK(XGxNAK6*B)0}yb zUfTQE6OO4~3vIeI|FGA>-$_^2F7!uU)%^Ey=2X8OV~@_3yru}2u;r?el3%%s&)NNB zae^-HWSooZ@|C>0R40u_rgBZ46s6wnaF#R`JVY5+shfk=>&n}vdaQ2Qucs1?RQ29` zwp4BxLirvtZ~4O1x+jVykk3kZ96O~;dqO4ea1U!~c%^sh+)RuZ;ozw{`k=pNAV*e-wD(?}0Cg#sOWSl8Qk0Ig;Mv!r@s-@T zxuWcnGM1OeWUpb**1EBmm&ENNwT_~6>O|$WL782&Ju+R@&=)wea0GTeury!l0BqIB zid7Q2fN~{aU9^Kf7T^5^V@-b?Ih2S8i4VAVRcvTT;l^{HSl zVxg*Iu-~vLCTuK|5NiT1k1YcX@;u)U)(}7n*35*Z#&_yv4+hdhUW$i&TSW zOHfj{aIZbWb~pMmM|kimd@E_swp>V~5`M)hqT23BH)_jemfS|2y#%^wtJ7#o(k~*- zJ`XVq_j6*cQK`5M;bCujc{wzkqhh`NB|LwE{_yL8&nlxn)c!bsDc>*TEp@(o5UO^j zDt+Yz7t3iaPD@7Z7PA(dAuZSilX6yZ&$KW5ossK@lHd9}w|_MH?!~%)V`?(Si)B17 zNhcl8ST7CN^ZeIh9*&<0_(Sow@pk_wUc5HrHMg3iywt!w=EYMP@5Nl6zQ`@v(Cm4P zxx{oWF*S8wO)WBQ@)(wu_%$`gBx{Ye>1K;kQ6AwmeA4NzPQ0YkowcS0ZfC;8_|VsM zItkyF+&@Tnrr<9?XPt=$5Ii-st21f5mfRovxqk>`3B@x8Zf$!@?w@!yDPsg^H3;nj z()Hjh;M;2OLgbs57{$LXV>KX|Of$|g#8D5_I0yn1!~qn5BpUM7BsFQ&u_lRXrBbN` zNP$vpGE*Z(CvB~bVId%qZ1$|z92bHm;FC&$aw!1y^#JNqpioObj-Mb)M2Kuq0x_#e zH=`6nOAP-bsZHD3G)lB-KfjoDO?RR4)@#Xk`T3Wm0TUz;a*7+%l3&_jVvPG5DBGM! zWMWjbaY zEHU7A{s$>q@^j)|sIBw5TJjgblW1IoyKK$~z0SDo&ooL;M-8Q`BTw{D;GRZ@{Hv7E z%+H^(ZD4KoD2XS&OVG^dq4_@z1_CJI&q3Ng_$5<#D>Qp8g(SWE3Dlz$fzfj8GTPITOETGv{G?YC zTlOP(D9bqyR5*wr3CQN`iXtZnKu$;!$VAOSs`;0YJp^)pjGy#mfr!#7R3=7XD}e?R z$D=FBza*NJtqraL4wAW&6!Fq^tg0kWCm{3~Ez#~5UI7Xt?k^?R~;EDsTI^dcEt~=m{1Ew5s(*d^}aN7ZQ9B|hG_Z%?jfCmm3aKJ-$B5+gC zKa{^Y$b!5neKhK$9o?TC0orf$S|%I(67Ezv%-%Z*(y^-nfaFX=oZ>ah*E$1c=Rg55 zjy#T`p%66falp2Sr6UKsO^u{PUyf7q+c^9@$R@7?qqvEA9U^I%AO$v>+=iagD7~t% z0bJ6Ozt_ZZQ`igr&@T*tktX*EBl(j9c!C)xGqyHahtWi8BjU%;19etJ02N#fDHL!T z;$w;Dqdy>@4=n{N3TgF{6wb|lo{e0135>u7EG!KG%6jqPxT8Ug!?u+;(#VV>0ON!~ z(#Q-FfI$Q#l{7np1Yi&W1}XLkQUE~$NGf6|_z1vM1SClKkr@iWAOaF}$)ys2K?Ee| zj0+NgK?Ed7*qIp$z#sw=B;AWa0x*bx1kJe&1z->X2|DM31Yi&W37U670x*bx1YK}J z0x*bx1Wmah0T@I;g6_B=0T@I;g6_H?0T@J}@EU*^ft3z`Prfhk5rCqq5F=yPHBy)g z50Y=BUlrChWoo^&U)YY}#V@>R095!6N94j* zh_McIh$gQC*+P#+`Kuu0=9GUyJ7`_t%~p>irjU|+U6_j^3V#>o>N$oKvclBO0+r;V zfkR>7P-ziVqP$>aF3e%jOgCW|kiPFv9%s3e$ECUu24OcLDW*@7I7!Swa zp%T_&EC&Cf`G%lB7X~4;0*FkPY-#pl(k`lL(S=Tr5t~9-wW~Zz+sR^}Nfx&`V2=a# zI^aVG>~p|?0|p&1>VRPfOgP}E1CBc&=YS~(%sSwN15P^Nlmmq1L{-EOfwL}X&H?id z5V65H=baBE0Tp7uxWoBK`!LQW=OYb8pDWJih6AoT;F<%jJK&}RZaLt#1MWEBt^@8n z;GP2>aA4esff2)5lBzw&N544WfI$bKWDNo?3QRcwwNxKeMFCJt0TQY3Q)IZ81)}3A zKvtuV1byg&1Yi&W2|DhA1Yi&W3EJm^1Yi&VEp(3qjyeE@)SyuZ3_IYm14wnrdEVtL z0CNVQ$>$s(?KzDgw1WnnazM@j+Z-_KfC&ejall0foOHkm2b^=jO$Xd^z-{!35Cb_}9a%7)O8LR8Ivv(qp9Hg(6DPTPf9EtE`JS}?_c-9R-w z>TJ-ts5pv}_k2br8nWbUf`h3jVtBT2hz0Hl;v|CJFHk!S{21NA3~z8R3`hZ8%@NvO zyFbI(2Q$FWwuw^dN(%xTq`wAf!mOCDW<@B?gke@PnM7l+Xf>T-YDPmvB@&g>R}xe$ z{X(BU^L?BOQMm}`{FuHcI!F;sEqv^|`}-lf`6QRC#Lebzq}Fk;in^gLV~+qln`I z>PgH%SA%7M$&z8jxQ*2zm?P*$JZsSam{FhwMc45$Z^0|4zs(!o^t2s5)|o&c1u00L13h_Vd@P_aRThwY^DbQ?PoJR zn!8d`46xvc*?CYQRofLnS}>yg*^fT_?&7t#f114ZxTJ%iOdY_>Rdp)yD?g7nw zJ~T0y;inw=4VTPV7GImg2lle#8C;l~896+W3BNFs85+q<3=WNFKEqAsxVtoS_+aK3 zu8__g!1cPg#dfS4D>Ch#$-Ra_9waQG7<^gBg}%gfp>GarAQir#d2U&?>U(7cA=>4j z`X$9zHm8^JOiVt90hTw5e~hn7$zA8T+8Q5D8O3KImc6!OjSxHqSK46`h$kGd~spp_qSp7JXez zSm+7y4!wY52+P!5DCJglE`$#o1PsWIqEW0DuEE|m7tqp=rAuxJ{88xD_BK|Uxp#nj zR9w8a1Mp&=+&twxpQES7E6uaSyEJwi5#kCZSLR(7EgvJ#a+IDMlyy+9dlFk0vxD3E z29bC{0QdUqX@=plx^-~rpGUH|c+5pxm(_FJkI0jRJah9&=-tM6u0k$u2lsh!)v=Ot zK>(@84So@=Te#M%WOtdgap`(LaxW!Qi&CQ0t3$oCO-cjOJoPjfV)`5xSb5dbSXqwn z<{B>>yfiVqd6<>k4@#-f=62+j#UbWIRAYJ$2Oc9>Ea!EfN~E^W(FRMSRQ`T>R$nUDl@J%}GQ`(y>s8M309cOV!jObtYp> zt*B!01e6Wt0i(DU4*Q_r7bn7fwzdw@ccL~kcj>I4b01EA2c1C($P|D{@n6QkdvqT3 zIo=${-i6okzaM)qG_$Rj~L@_&`do#n=VM&%JkO4eZ;ijm2Yz8UH zw*|Q>IaG;0VI3ui`Y|BEk%d*@)f5zqy4^IY_93a<1Y)>+Dyv)t?bRliV=pEJGT8rg z0ROcwXHY>W7`aD>C@AG!_6zUb$OzIIq5rd1pei-j04>K1M9*!_)(c`ec4n|Slbg0E zx!q<@JsR&W1Iu6&`WD36C0oyVK!~zN50*c@Dpk>1ix2Jutxzh*NI14{bexmSMg2ir z>}h1HTGl#~`z;pc_8swz5qE=A(mfshh%LxA)D$S~c?SXaYVkZLbK<#b_RQTNOZg2d z3-{J`o80Mge0HJ2tTgX<`u`WRDvZ6}Pei z_&mM1Uj!diq4oxoyRun&A~{~AlWwq8m4HXkxRH|EGKv1vdqf7Cfyr9B5tXdVVVLTe z%D0su#3*1T2jeM||A(=7m8xwF_+C*a&mTge6geEd{v&INRTztM5A>KS2iap~S0U*} zOAe51g=m{*DfeqNsi9Fp<@AE7A~t%~!Igst(>+-+*e_&MOr1y~HV#wu%LvKYEyy_| zq40|EuF|VkVRv!fRtjd-St$_S20M}vQPmd4-HI4wV?8tC#>vu@iWCPZ?(ZDW}$XO%{)mx6b)KoqQFkOh@4&+eU(G&x! z$dA=kRzc~{H|R0GZlDxZQT@2hUG*5UH!~jz5ahOC4iuE3>~SQXrXf$2reZ76kBT;9 zF&7e>TJ_TvFP2`8S@|Iy*YzA}^)MB=y%G;cRyL5zrAT#rB8i}Y{NwK-iQa{*1+a=d z&$bOuPC*_QPS%f3$?OCXh_I%0I;y7KBCV{5kq;d=m3O{U4sd0cr)2(5Y4f$_M|%3j z?HN{OmHXF82+FmCz(#j@tI*yo^<-nXTNv1#*^nxNshjJq9^4tOoR>kvIX+(xxW_Dq zyFje2GEi^+rDJQyOFZ7Mqbp~2`cDq*;&z@5_jx zB87cpJILuKhwcE|cTpL=c#VxvT?e5UovxYAL?3Ea}T29+!lLltfcSCY=fbhfpqtY^?PRzn5L z{jEJxf6mQ^aF}%ja=IS{vArB~R)&<$7N|mf)#`0V{>n#B85UPV70Nx@g%RsrOxPp( zR*vA58k8Q?8>8tgTeLhKMS893G@bq{cT}ovoR4Jpf&r`;-BbClJc%+vkQL)Fx zs$(*g(iBN+8>>eSazpBFF_c7U9M)C%=na$qttZo#D}Ci!^Z(bC*YUs+>{+W{no2RI zyir-hvG9PUOzRGz1%U-kM{YpTa{83l;SB&SN#l*8PW8*OeBMq12$__E`*)w zkBAZt)@<=CZ18%m3s-`+iS#M`lvN~!stN1ToSc-STE}Z*m>;Kl?}3B104molo~EEz zMIMS$t;=vXvfhm0krWt4U*u_9BCG8|$h8Q=7aAF#WWXdnqw$IZX!!yH7r4knI{o3| zVPs*Tbl{}f8Qk?Q6y+7yYFt|>?Uagh`Jk<5aaljwG&u4p&rse}Ar7zm$o&zObQVtW z^**F{ACf;_7p#;ko1uMv8=14vgFumaxsiiJRC5Xusw5BFzFhU!3k7K)C!wgdQh^^q z-c^x@n)B~DQ6lm>B_;D5l!7?c(?2qv=<f1 zc9kl;PZq4~G}I#)kO=H5dSRTCyA(VNiRN0kQhNXO$l^q*>!ePLRbfkv$e|Ak1 zjW%pDT08Vc2UWr;sZ>g-8ctcoF+jg7t4dns9OM~z2^!_Ut|W-NBtoYxZj!@xpkU+L z!{!CUA(feOQAc6BSG54uE83sq_*%P4sR^DbNCGNN<)+yvuO~Is0&Q~* zb~fant2CBq!5n+vK|yZt>4vx@HHm_*FpwONN91pIfri{lA*lms>2@8bJrL`aAWMWJ zm*y(TwxJ5y3JerX<$o#L&*=#hVG4>Y~qsJITVG?=QAl94gFr=(RmMpFl%9asfk z^a&QGCv!V?jar%4foXr&k;S#RYgZ!8VVqMlPPwV0=r$6kheQ)Al8m;hY8bQ2myRF{ zRq@@xgF8p4rEnI+Qgu(sy- z^-gnj>Yt8zBuf>+y%xG>;p-I7d(pP;Vt%#~jr0x$F50p6tHp^pjod;+o}`|;uCNv3 z-4%Fi53o)P<)=2 zBEq6{%IqejRr}FeE~d`2DY?4F)i4T@ZTMra;Phbx=q)rrklmcpxfzI3BRmEjk+)*z``{9L8Ja{E~!=W|&`{R;7*ptSqIJEEly^`#zNQ|NC)T$XD4c;53)= zb?X5zhR$cJZ5k*aBps2QD&_fW5nXb5~VDK(&7*nv5-6 zW6+f>4oIqpl-hu_i$;obC4vhr7}RH&1JSRpS~+s)aHpFM7TOZXk*q!^56p+!2va-> zTgR_a|5}KjTXN7*MSII*_I|FV8Te;xXLcWs672dM*vPol8loMF?y}HwvpnC}{k4Ne zhJr{frwUF1;414x#4mVYT#p?zZot!ukjA?N4OUZ?G17=F@T8$ibE!<(4JFBK+)|#Y zj8RE{PA7Fajhv&4_7w0O>2<&+hq^99^^US~FU)v5@XVq?RKk(}D63QkI(>t+(``?s zO}0RNUkmk}1|M3N+22dmqi7{F60Cj5Hd3ImZWGP5pEx&IhnZyVkN$d9=kUfg zDavXRjs`(T5VupEs77Lm>fFN3e@X-;{Z|^(*U=1nUl+sQ1u9e}%4tddMKu<@Ah(#49}v#RF+3Qz?G;1Wnqlc zGKjgen>s^owBhuL>d879ZFjOdM3&1UY>_ck{}@_Q$4pY0lSe(7!*~o~wyr%~t8#Wh zRH7kE<(jIfaRXdwn?893-(js|etDY`BkCA#lErbMTAiwn z-Ro%3J*cZzTOre(+~-oj!qy~XSC6|JNRVCGElD88+=9-?6DLHbdS0b5s^#$b_KiB2 zi&L4ty81#+~{mEo==(fxyTNuO;F*|FHA<&aYHX9BIOJ>4Xe~6l8&1zCu$tv zS&?!Z$inSXy0avj;*p6|=9P14)eZ^0@d7JGM5=cul^sO;SypAENA2gO4{%!HP+h;`pX_|d?RsOTN{ z&Ui~LlCuEL5|uT_%qGk`cf-%EVZ9}}J)Lb`m1%_MG>lVz9Ss>mB9Ie^0h>aFZS~T% z`@dCf9LnG8@1u$Kr`>m2_Ju|Z~q7ff#ve=F5Fpd2qG?SyMqfK-rRu* zH9T^VXW&~H~0z~9y zT)Kvfrg2d=ic9j&Y!8`Ql;ch`YjWlrYXmB>W;nrxCUKmMmfLb0gJ(nVj0ev|@Jt0y zT&OMaak)$g{k-1P@^%#7equqfByS|=Tb+rCXLC~x?jy%pY@mk^T_V`y?KI6u#)oZ= zH>dcYgyvo4pzmM#xeJH}K-vJep7Q|tMSWbtA?w@)++Tq^D!iCi>m_k-1}^*d8oadU zdu`q#Z?X5h_kx%4zV5y3z3P3#Tkfs!mU%tiDsQ#7##`&H^WN}|d!yb_?^AD#*g|Apo}sU40Jg%QNOTvc z^evwE@k`*=FM1(9?)pR-AOZlrB+WL1XXM?_w*zO(zF?bcQW>OABN@)pBMGXMPc`CZ zDnSM??j%7idC)$0KZaVFx^BnSFCmLmSBbeN3GA^G+LXu2Cuvd46nHM9Rb0GQ~AAqep!oQeS|Cs zPl8+>-^U#}AB+r59NRfGnjIb*$#(BPHa?L()V(Wva5#Hl0(bOu?>sy<(Z7Eq1Wp7ALY=^bUfbuWN`B79Mv=QYx4pi@gHK_^A0o_Ry`>*MG0 z$p3{5U>pj)E(}@d@EA@kqvIfFdi;w)_Vd20UeFIE z^-cq(IzUf-nmAOTd}j>zg9#h)Vl&(Uh`Z|3Cb*piqWR~|DeyWdp!G@!+!e12{J=#m zW`Ueis%NwJF=7}aKJo$w+6wW6(?h41&Q3b}=#0|I(K$)y zES>XoF4MVA=Qf@Dbnwv@I2e-+22eQCp_&P0==9nho*nY+lxP3Yvwz>SbDsSp&(3@H zvS)wh*(;v?7oNTE+5gM42d$m5_F#=Y7_*tUy_B{CMZ5W=9rzQwdcPgmZ&&ZM13T@q z@5COlAoK6NHRd@2^6yH}%;@!t!0g)pOI=)CM>d7hlcBnFDTQyEXgEj)kBi_^i|;r9 zifu!dO_?NGq*q!WeH?uiubYxD%D5(SxvgF~Ep#dP14hL69bzIzAivw3w87^wL>8R1 zIkKe%c}$M2hOyMg*9Xwt?0J1b&nv{@U`r@&(!GLChYm>y**XY!BnEzj3eZJRzkHuO zg15qezCF~(J$(#PwLt!0z>5)h34!eEd;k@c#iBqS@js)Fv-+6R2R`e;H0ShjULU9Q zaX}wJ@=N-5Ssz#QaaAAJ^l@DuH}o;3kDL0qrH|YCxTBA|^1waZf`mSB2RGkv?YBG> zCEUI(Z$as}MV43(>SI734>ih3@G))*rK7?%-=VFrrxBO5qrut5z!Yq}eN+fqc!zhM z7c~{=rXS1cwwIaXmfw(#Y>k{o$!GA4$< z8vM!dmHSJ{2V*C$X3Y?1B*1hKg^SlK;x3a&eV9LRgirAeJuKsO`jb7x>zRH z5YQ}x`x(qOnFTxqi`&Qsy$XdAhnD3^n)6*+UktfK8h*y#Z1>8m>V`v2+ zJRfgh(%Z@P`oy^Fl3=7`vRPAY;AEJzP3(0l3> z9qCJ75IRTaJRMZspSnngQ|zhBbif<_)Kxf>$k(4_+R2-AZo!#i{ijf8e`*<>DL9iG z==9NHX_I^4OkF2*me374%wQ@;KdLiR%xdxhoiFGdrC&3h+jQ>Gk;2aqx<}_eoPwlf zvMDAjB&Q-DSQkT&epXs8D8 zib5!jv)%9o-}(}%b+MVBPe9}0BSv1AKivbtb&;AwGsJ_wPeGVXcJi+U*)hD?pI+PC zm25_XLiiELU#y2v$ED7lNigvj2uwno;BCPd!PxXik}i1En;JeO1b8M1OBj*>cN}73o?T3j`^XrlZ+1(MJ7(W`r0)X@t0cLT@ zw*Wxl27#$jeia8mVGc+J06y2FK8g*33YURI+Q+w4nB6HKY7l`lK0ZgHfF_q94^ z&m6TP0_S{umxRCtADR(?OFq6!LI8FMA>s74plkqz)9x!SL`fTA3gyg^;n5b&Fv$V! zv-tiQW}GlH(r}AOJ7>9I@}SkOXshA<96BNdJo>N{HQ6gg!K-kg*%FJ%9cVv|)CUNf z38MGm(`p0?H=Dt8{9{yp-RUMJ%kP3==o)qllncR6FJ#?_E*3B(C_+^855u`GzO5jc zz)J$C|0>|-x(^Xu>VXGBpsX_jv~^Y6iGb?w=y#H~fI|BqB!DWsjM9KMLWJ{sTJVo) zF!CS-8VbZAMm`nCN)#YmTMAT72>u4Ov@gF&=gTi&1cl9gLQNRy#KZurvdn^0&LbIk z09lRE8F+L$ofWDqOXv*7XKJ=U4yr-y`DPd)X^2|F@6_R;6Hs0rzQr?dEwn&whka>m zq<^@3>&THq*)cUn!Q{j%q{o+U+MT7Tiq@Z=eXC*q!9C|uzVc-Nz45%yGvEBmnZG{< zGuPY4nER@Is{$=pq*P&rx7*v3hKkM+JNQCF$typ(fPtydM`xRD!gL3EgRyO}h8g>u zv5Rooxv`6lecsp?jO~QnH~6fDebLyLjQyIiFB`km*smM=scW7wy|4`?K5_(vF{lB zuCd#U-EQo+jQtg3cNqJgvEMfKePeeT`yFF<8N1uqJ;r`u?01d*p23z%`+Z}7)z}{x z`$J>@6JtLzcAv5R#_l)vfUyI{W{o{)?8n9q8arg{uNnJ^vBSn5GIqq+!^Vyp`>C;G z#*Q01VeAoOKQs22u|G2Q$HpEv_9w>vy0O1uY~I*{v6IG589Qxk(bySdXN~=-v46|h z|J2wM#{Q>n8W zca8lojXi7Z-!t|Pjs5$^&Kdg;jQwwny_0a4XU6`I#{N&n zUN`nHjQ!`v{tIJo82gvT{;$UVZ^qs<_UFd_OJo0cV{aMzuZ;aajQu~2y^X2(BkMh~ z_K~f5WMhwP{E@AFWD}2U>XEH`Wa}TYq$hJJPt&eQmBisJSKKIBj zdSp8u+2>@LKpD%4`*js4R<=*-9dHdbHa zkO3)vJu-=pk0Pm956P7uO80LRcNo1BLQMwg+zoo=W$Kf=2^i8a1^$KdR5+P%@@YT- zc*P{fNtHbVh^R3&e9$k@MT0+AIc;jP+4M-t}jdCDI^vE z;(1E2>hW~g~A?QQ^*3unPS_`#!#Yxe1}s_h9s=1ACT< z;r4$M>!7ok&hvC$pwmTX37r?|yhP_~bY7AX#63!OeX zTj{(*=UqA=$q70qNndGmj(VpYSp_JZa%4Rfk`-QTCy@0NQ?7Cia@wU7pm5ry#4NZ^ zc@$o!HRWlhTm18@!Ig8~B@v)--X%F7CV>}?5upBgrmS-*FSwKf6fU@w7s8bAqMD498U+|$bcqBg zKs#1STnrPzi)uI$U1V`>uDDAsr2vIXF6E^#CA@S_Rk*~Ii(JafE~Nm4%P!^RFeSV$ zYnhjs(swDZxRe4EuDFy}!j$m3qA4{Bs(95U5}|P`Kk#-U(B}>yDumJTO72;pfZUm|2jKSSOrR4TvYEt#>(b;s|~h6M)Hvz$gre^MT<-Fd(P##5;aa z)a6sZYFPcUB9MwTBI&n!CL0=|KO+fu+_X%#xsM9eG)q=(9H?CajJwFbK%Iu^p%_U* z%`Wx`Q=8cT1E&ruk?ITB@1c58O%f9tm|t>p^-v~cp|z$Ns(Ktnw*{|28efc}^`s;Y ztjR7uHqqc?_LFT%%ZtF#gmDzu4gy+u~5m ziXC*PP6*s4>^qqew!|mTCNthn?>pWHVExHuUaz;=+e)w}(AGc%gKkTAvZtQv8A_+- zCzgPoz+gl6z3nFa0-*onduL30Q_}YOJzPV_N1x>rS{v{XJ|BQN0fq_xhw_1mULgQV z2#a9OH`Vsm$I2169n3LzRhk5ARA?EPDwoEBmNngRMln%QE+2aa`LUX~T=7a*5n-gs7R5Mq!Cvzkp z9&9!t>ts$4nWvlg1b)DbD12BcEOLgin0!@&}7II*l`4B1bKsw6KL>-Yf^x^T~aVri$q{7D|9&k#fbTgBvL!trND?Z ziSfPxjE=9sNg3A_|0|@Pti!3fZ4z2bn8S6UKgQ1MAtKiW5srwACzxE0vOr2MN!?Qt z7H);fv^{TxG4l;vm{3j<#s$?K5_N|0)q}X{igbxWo)F(bCk4<75^u^x38@T`)tG)t*h>j?MluvjCRI@ZL>G3|RHUXlqO7h; zlB<&8Rn72~DD;$siaXU4c?+?oHbfrhB%Ziay^;4ky{EQC9v39u1zPQ*P9Tx?M3JT> zlDJbJM&5VCTimIE$eZKb6eoaiQB9~MF^DjM@Xv!} z2ZqxyvV6;tpQ7cL8ZpAn?m_O1)wBvATrZQ z`k|9x@=Y}cz$Cr6jDUfSHHH_K6pYjho1uabY!2g=D+FOdmYj`R3}UARtHB`=JAB0~ zfrVxceejLdc4<^*I3Q_2-GL;mcwD8B(G1q}v{;-ARMGGuH~okG837P;K(N=uB!kU8 z7+YLWuLE)pFhNErOTA><4Z$S-%fF<_IH1=7IR^yk5mnOzP(%P|dbk;h4M3C8Uy3Cl z$p}a?0{jz4@aJ2``Sdy<=K#qlOd$Xx3BX7KFp>f&O#zgq09*x7ngWO&0M-F92ZTgv zc0L&g^g1AClJjO8%GL}o3jhuA%Rh%fB*^(olT;r7-}~~ z9ux^|EJx@mfE9)~)A`WjZA zF=T+ru?9F#uNi2e6m|5HxN|}AEcL8QEx`22V3DWr&;bK(+2=HD9WFAKYm%ZxMYWs0 z=yMSWz!056NW7BKNpsQs<6C;L3+DU=w4G_lk0T5V908MWI(pGCD zoj>UL54gny9uLy$fu7B_pS~Ur1JkF)BO1R8>H+01&>p5YK*)%-ae9Nqy&VO~I5iy& z)zjxC#@#4}jNQ}sB9F_AF(m_Tv6Jv5mV0#$gf^By9ZfT+5(RS<`XB=5K_^Nx3gTe< zP6;#@`ptih${(a5BC75fKIejWt-}>5`7GVSA#pzypEkPF*Bl8{r6}YjY)9yOCWJJH zvpTS0=2kYag|V(m2}ihH9 zXjtMJSK_=YQGn@rSK@rg$n)C!P>Fe0V!%=7nbTUA(|MPZ0Mk%x75C6W2d`<$7UXn3 z%t^i*bCjq7}yPPhEwYvi$MjV{e-UePF1#79N#=7yW}i7I z^iTnWPjc5-2<1s(fR32owc#E#aVy3&L^?$96cCNGIUlktQHQ6w{Uv{q>F-Mr-_e+O z7fzryqMTKXbm(F-_HX~)Bg6SCc}gZ-cqS7vE3rPpkqPG0Sb2rCg+(F3sXnI3Nz$=} zPCK0rI z3(ogp_Z4Cxkek|K0D%k*76HT<;R~kAKyO7b8%2;1r3X4-aRUm5t2`D11Xh9M+9nUt z#_>jj8G0?Jzj!;V4;qy5CeowW%b^s>{9><~yc9+hzqpCxFrK|&I@yyx(~I4dVipR0 z`hYoV&eTZB*5V7&@ga>{>`e>*6no*LzZRqkUkK#;7I+nVJD``N=4BBjt}-5$|7Lo* zH=V2NNk<2+$FsrE9(=F{;H6#>byB=^pgaP1gwRe`o8q1j+8aV2hS0tc8VI4m5aPa2 zp;B=)geF4hXb2q-pOO5XFxAT@9gYA#^>2wuR7*5V{#cw?gQ42;B*xyCHNhgzksX1MaZkqzX(; z_WvS!=deB#YtV4r4~2Oz4y}mPL&rmpgFX_&3}-Di!$O?U{udMG#J=nXelcEZ2V0jg zZtfzu(Z^;Mk&ZM8cSHOk6wCb!1L8l&4LSvg*g>#3tT|$}kiBY& zR6TX!Q_x`$MD8V2n8WTIAFED`&19k#V!YC+*A)N~0i#7;A`FBnFH68BzW^f{OA7-o z0fN~NUY#QJk#+705Rv#dSrQAwhBL%EtFV-M1Nk5Uv~#}zRedmtUJOf*#DJA)5F#5X zuB(@1hS3lWau&e=Z#NK0HfNM3C`ewp7^W!% zfjd6!0a8Q3?yiPeHW}9VO6Z-G~p|?0|p&1?0``ROgP}E1CBc& z2LPG}Rt-AAED>u_Xi_F{!aEKT_{uherug`6dvgf%F|{ks6*;;3s1I^|4fGyd3| zzp35)H$^SO`2Z|@O-svQ|J@8$A;fMaFt%=Qy3*i|kOvK4nhyO_Z`SJgJGD zM5vSQY?NxuoS;HCbCSG0a|-%&jX!f58l)~Q&78LA@Ys+ua|VBBTLGh9zmKSAf+uw> ze?}}A{tS-K@a>%DEXL%SlU$=>bI7C67vy&m`Q0hW?_`kQ9ief)4{J^VCVnxaXmNK( zlKx!Dn>mla3vGM}Ql1Z<7o?af?lKugZd2d4qS|9kRQ>%7vLvYfTkc@A%yN>3pwm2;9G@5Us_X~ufPSE zSZKMVe_=r20f8~3!+(&cMdU>B%op$o-=MRWycOo~hC>kkq@=>4+Huc({+3NdfbP@ZcBWY*{ixGaSC z2l0xOk8wdr-OIQYh4+Q*C-|=U!0?+YwJ!tM%`IuaPG_Y_zHGjQt48_==ohC^=xisf zwYA(3XOg`!KIHxcbiY)x*~`g$ES6kk&?T@rurK+&cYmkh&$0h4*@rM%xML7Qu)~Y7 z8*ee>hu=v}*@i82k`lXtm_gxk?CUST$_U0>#b0u##ACYJASM>*uuF{_^KdZJd%jjS z+~MUmvD-)IES<}-QMj>B>5S1iO6M4zAJO?So#S*^I}Rq;IpK?`P9dGy&~ILrn`vks z%9PtUMj{nLaaXjX|?7^$^pzAsJQ3=fm;s37k_p*4GE8q z4SDnupNk-01*VXFNkpyqKQBs~Mym*-i0kS?R$X1mHY01ISlVIY;PFCWp3(Bl^X)1P zLmuU!tp9Y#F}-YGdmnG#+#sbOa2yT z&3r(;tns+*0=}~+X(4FIZ*M7lU(Si;w{xKXzAB^Q8xx+O3e}9mD>!nh} z_lCHm;tq>@S==k)&Wk%I?geqLi+f7koVWwx4vM=?+*xra#62VKMR8AxdrsUF;@%YZ zmbkaYy(8{jaqo$HU)%>Z%S<}H4ErO_!o>wXc(>SdEV_DPnLcsK)9=F$T;2hcG-&sUTTgLRW~}3;#I&>hYHlpHXoq z=wdew(V=D!Bv3ZIE=X_(qIU{(7Eqmw#++)!yG`8VaB*~2+~K+)FF!vo9;YPAGVVu0 z^_t=V2~rX`CxQ0`{(>-$ZNbH{E#~+@e0GW}^}w+$gyPs1-J{~)C+=Qx_le82K8|hC zy)EuTaqrQ^u`RliYI>W%JH(YzaBPdA%#Fulk`4#l;;_uL8U_|tq=O1#iqM0j5hbrY zDZx0{cFqi>0kG|ysRqRz5SP`(=52xR!o@Bqx|0p`!4@I7*dj!@jV|{5z@6-&3#EfT zlINsUC3jUqGpPWp0Lx1fuRUrE$sGG!n0%ft_PG##Ko>h(2wxO;vAEa7?W$b{IgITi z48ATe*a*UxTjE|8_l&rLNa2*gbK;&8_ky@n;@%-mvBdy6w>1uTq-XK0wb*xk%v}nXfQcYhD z3!gkr@0`$OTBrt7IHM=UT>%#+T1Hn*vX{L@43`X_X%qJg@{yPOyWL)HDmcQk8@JJn z;pUp|o!PNNL*sH5sM~o)ew!zt2JSyHkzJ8FG=AXl*znN)6`Aj5#~A<3wcS1Zzaq2c z$neCGvFw{8*&`EU{lhCVJCE!i9y;(z_SnSXPqHI#?tkNr{&fe|tzWfq&Dw0whK=ps z9^1V8lc7=MG<0z2KtFHF!R=P62w+JX-x$lkjkAC~`$kw9=vZIW#XK?KB=i|87 z%5*=oI<_Y}J~3|0d!Fg+{`S^A?~L^y%6@)$?2{F)5}&Q@Uf;bM<)z!gz`mjJ(c%7M z-$vXvrpkmN8HwHQnfl$?vCoDMWO#m)Y1%%%`7o{xIy4HpMa6@BRurk{J=6Z)(1EeT z;R4<6goUpXxTG3 zG@cplKk!Na$Jxy2*x}EH2D0Os{><><&sPp-Kg$khgiy=2Zh3F>N=!Ij%Nz=(AjpeT zj!gf^K<0C>Tz0HGvwh;#@yy5B{;}*p=HTJ63^Z>%4)u>5$VxnvH8GgYpp5?E%z?qf zAhg8W&wG=GMn29A0?q7LP%@Zute>+LB_M?1=7JM49M24758`^Kfz1A6f|#piW+mu* z=+NPj%#Qw%kB^Wx+eZ$L^^Z@C9XY@*ky*B7$M)AUj>s_hq78T*MJB5M>6|C-;wc&{^4QN z>+`|vNaon#Bbkvb-axt|;|L}#GlxOFvCKsO*vHw44CY4N^ihxzC*LAOZ zqo-#bmPS4Ey810Y*gvp(-I{~zR_$NAe$^Xm)(;#USaV=t3#$DOb!{b8}hsTb6FgBbSoR}CL|E1So{}}VNBm2A2Y_AU- zo*2na1P|!p=!2q%$0OKJO)%(MvhfC9FL|cn6P$_64zF3=Juo~>Y16PfJFx=| zw{>jn@EESgGfC7K=Osrbun6dxS2n%()+-y=ztgjN{i@Ad)~{Z@e*N0FH@w}`vu5M^ z^&8f#+tRaU4bJJfn5*7d)wAWD%{?35ShHd4`o0aD-&wzE%iCMGY+3)t`ZaxT;}}kW z4(`SiI({_V|D$6&w{DZZ0)bWU8B8~z-vZ|Vmig5Sh~NGZj%*UM_s8DNjzEMS;4BvB zF;M69M+4ad!{`koAFF39f%~~?u&uZ?0b4C^M|3WXx43GFi-d^;CMkGD-1>UNwfMsY zC-7wa1TB&P(u^#SZ2DGzY`6xX5z`51=QUk0*CKXTO$^(YYl2*GNmJa$Q>j#4BEGdb z-W10rC=H3)rW$#{HtO1h#Y-A#nrc#scvB5;S*!tmX=sPcDOs1mR=+tdDG~3IYoD5s zt01Eo)x@!|m%H15oN(VlKVN*Jkr;w7+;IiBD(VN8>6Z%?FZ zkbOWM8ytkI0}W()n12P)Ftu2e;1y`{gE4jk)+Y0t@PxSMWo&h}Dn)IngvtBwHO?0Dkz}(@3I+ zd7>}QX0+g%5K02^40 zdudHzn$7^McX4usU$P|ulP&lrjD&l*5?Ig)(t}YnqPndKpoJakrGAYPg;P03ZA_5v zvX}q|v_#%1t$0ncrYVskYbZ+~L>la9lcdRGlQgOX7quWX4eA}mPdExi{;#<}+V|(GhI%q<<;t4QMv-BhVB|gFkIOdQmXb_t_0#B;;Ka z8ZH=bN-zPMMBe%YnG3FSp=rVMtR#CQHuC%VeTdPL{}3@iA+(&l4oKp&wTT*O0O5y| zmIx%0U=_ABOc?ojX2Qbe(XaSOGfcT{UVU+y&k#C5%MiOBZ}b5x)Pbmo1!@LFC0|LO zM59=AT5;pxj}&+eH|)>?l!)Qx7hL-S4&c2y{DZ7PH@SklcH~}|&Q6415d1GJO28g~ zkPG;gAe3we^D?EMKVRal*q`?kAiySu2VrO06LqexXTU1Kg-SvzEbE;{?a|&ifI;HH zV>SWdk-yj#??@!lSQ>EI`1v#V!NWEt&~r|slQP(%hI$(fZo>U5$>g>JfcR~aJ0YR~ zhqx}H_PM_Trvblz0th&R8kTgCdZW{}6gC4a{6mspc0wqITr5rp!1N=L@Wc;I0I6w{ zH4syfSA})xAcaOWN?=zPwByew*j%`H2ial|UrS-DU)YCuExCUq+>v@7T^5z~r+Z+I z#t%1|7>rMi;nCt{S7@llQ;F=da@drVhNW|(9i9%Yal}grkCKjX1Rr$x$CuBoB z&|$&bY_>3o$G};3Pl7- zXbW>J%PvfbymeuIjwNV<99O5MIUfr8v8F_0#+%u{oeh z8G*q|A?eLyIwfVQ{~WX{mBj_U7l#v=*S(4hcJvQ znKCRm6$dXYtOwXhOlT(b1WwbCZRFdgcpV2nYzmV~;7}H*hcjCZi6qBG4t8;<6A*eD zn_Y)P9*%86QYA5{rc`;-2i_AkEwg9Q9Z0gt49CF2ba)Ia#lc~68+Ktz@D3l`P&mnD zA+pR5@q~`!|8P|Ty?!9@MZjc+T~`_ky@G}wA9v&6jvHYQe|k3g9GZsxCNK-3iZh!K z?Q7W6=KPr~2@6sX1X&^$q_1JS+2pdoGkAdK0*Hgh#TTeDN`B>!G*-(XVmtYK9prGK zC5Qm$ypD%KaV}ppKWdS?023BuIBOXEdoh7A)CqMogVY+!sz6h>m9V8IPvi8{5_H>( zGBn^EGCDY#0E3+HJvNG97({*LFb8`{Febu_B7?=Xs@0K^h%lbXR}%G-hU2=F3rzgU zy%HYaM7d(aq$pAPq4spxEzx>YCpa!(FyhENd7fT{De2K{NPlXU_BC_?9P~i{K%Bzh z`-%Eau7<7xCp^G916+CI0S**?jB5{J@bn-^nGIqB911~jH6r4-i>=PhOfG#{v}%bp z9qK$y7K*YAK@5x_3Dtbyn_8T}7N^-g;;;;+(=6K9JSahmmQ5J&e*q+)>hY&mP-ybv zD6QlmBP~hP`BT0A)F$q(nVbs3C@Uoxw5&nbi-DNvdR$n=y}k)wSbP7Yu^LI9h_4K@? zjGi(Kks8?Gs%6fR3+n{N`7E@1{yfv9unDA7#sDw}4*#4XEF%eEO6%z>;1CB4O8V(* z!Z(NLiw#Yay&%(*dj&=e<*$>_IS+-#k03Q^47bWU_Y{jH3+9$sb!o}XjV4Wi58JN$X z!M>|Lmcve$gPvRBEh9g&M481e;J?oGZpw1#JEHa%cL>Hi#oZ?ERdGd8FUmkz6mnrn ziFLa!?hSFThEA}flQ1eTU6o)B0GcT^J`7q6VS(qP3? z0?&ziR@^h<&Wbys$@a<1fVhL=-W2zixVOcX~+y_*yiYM{oXzUkn}I>BHs@KUvA8be2)jd+@uxx?hAbPVZ&Bb${xQM%&1w%qxeN( zH~iv_=xx+5jz(|8esMT@yX+S)M{igB;+3e}`Jmi+Y!8d#%=yK+=UH7tcg*7yaVJ=#A|kz2Ok~iRkT| zUpyDR-Smq$qqkdr@mBP98@v;}-SLZeqPM$#@ow~X&oADK-tPOw`+U<@et->hU_b~$ zWjQerpc8W(fFCXj$7oaFxC~diHJ+9V=UTyFh{1+qu5Ku##D6ydnV#Q+!WQn+lZXr%!aztYQF4G)xu;@;YYdXf z4vZ4zfkD~~6koSn4iU1lZBAlx{~Ug-0s!`mU{f8$xB6o|6A79LYz;FfM6$L)2_Z0Z z#-BMWz)64RjsWMe!;7QE%x&z_@@KAy=QV%kssJ~zhpL{6I23w{St7D^3a{*X%H~59p4UBn}bRVvrJHnCj}C3$*af9)}i) zNr9Dl6+LoP?>tNpI%spFtqe1&WeW-rSefxj8 z?g!uc>HZ%qy=u|@7yn}KKb&)3*@M?lD0%q1Yc@YJxcZ!ZU5{S=OvO7b&pz~}cb+>o z^@Zn+@11=9oDcr@-^bkjqnCc28THG$r)K>sdgy1bTweEuSNmhHy*l*8nm4|_<>ohX zKYaU*PZoXS=$k(?kDYkpiQoL=!w27K+5f`v?o%_~9ToqZ6UMK9c;d^MhLgW&+<9_I z*#jqUO?A9K^o_O;o*K3M)TtU(_Qgs`Qgf?*PW`=Cw=ac zpMGx7CFeca@t27s&((jh_{Bx%Z+&r5`AzA?<+V#2)6eg2ta$6(W^Lus<;Q=gx5cjC z+EE+c*0JUE-5oE#wYhWao)xRVx9^@WJ+pS~n%j;yU2|h;Z}iglMw!>2zQMe)wWRm0 zU3+`4z3+*>M-JW=Ppp3>zM*^BSEjypFu7)MXno(@e_r2i9m&)t4_Z$r4`=WDc5HLi zHSw*leRRvVh5yuiZ8^RQ`5##6g3h%#8?6HM!~ca}X5EXn z&}e+dvs3763}}CXbJFT@y4t&FdkXkr(7F@-J~UC&emfq0g3e~Z%)s-?E}qv^!)(%U53{p(B1>M7r@(- zz<(KV4?+fSqu)tryB)9J;`us!eg=I`1^-tA_U9P$E<7(r-zUJwTF~r4`+j^b0#D6o z%iwhj;7?+FhcT`nylvi|@*`z2Id%csvZ+ z(=ncZ#j_Idx*dHy3p)LPKaBQoqkT7c;=e6;z7p*T^ox66v@zg&CuHyvUZ((i3^=R7 z?*#C03^acSp5_7X5RRjpvjo2ijA`qfd!ysxIyBx=t}ZfG_t&$lY6+eLkh~vzohGjb zW+hss13tmUbOAgf?eH+mi zZ;Iw!W@`Z4)F8T(myq)kKVA^mhKt;I3msW&!Fyf^+=lnOicMWW8OCP?p9P^Q>X(rm zQyO=zML>wxHQq&*8bF0N!%F&ohL(%pSMrLtsP+heXZnE^GemN4LB-dR8oun~m2g@7 z5|g~G#2tCP;G6H|tIS_&5SY+}kCcrZdV^r|5E@oB;VlJ8HhKFc1)2qI6aS^~`Mq$ZZm@EC$Tm zNI8Mhh#~-A(Fz8rPBC=C8B^L}i8)rcCDI0I*+dPRlN=!xG^yPIlGAumD=&zqN1;Kr zi_h%lAey^|Z(fO^DvgeSW$KvUX?P7qLGupIto8~>&+-EYor&^mC2+sReo*!*g~I22 zH>9-!tTG>rmq&WVK?v$E$D7gC0jVq>Nm`3E`7R-8-e)>{Tf&?`@|wfm09*OnD)m z7^#|te@+64hIuy->qo)`Z&YS>AtMNFR&nztNYsv$M4{nKM9w?YPhb_;%-7T=00!($ zR+Z4TaFTd;E$v#RAznpW1LPuqFJXvdg9s7Q>2Cu_Kx5iLx6h}Aw*x4kF$AJFW5|;U z1+Rd112rlr^XUf7@aF)U;^)uxH2;al0P{-x%F(?KkZLBIGFfWE*r++2WN%(Tn*M|i zb*|cU7f~isOsX=%%|*4v0GJ!JXPFns&=8Ev*8pKf5W$VpiZ$62{i6zjQYV@B1%vGt zkSq?8%-4|n3-#=s3i{0+h(I#ljGpADINrrzvu?WI3BmPh3$^D!azU_XH?jFNIiO-c zUvMs}9KSbZ?fP^CD=z~YEQHV{)X{<}G8L4Q!vMe${w)yf(I^MYMV537pBB0-vHUIL zE!oW6q`Z`!<%i#+=x1h|5Hwd!@~(PD8?KbRORoNPopj(#4YiZ-KI)!G) ziE~v-Mz<73CRc5X0k%LkbJiJ$W3X%)!RSJzuTX0@sWUPQT{AM&rJAgQ^P+A8YW>-J z4XT%y#9biKaCQ=26t7OISn)K-)QpsjoLw);6F{#$JGx)>BmqfmGBy|HNCLspN_PFr z(K>)P6$W<|geiL`l#$-o+m|HoaIN963kz$ z?*(X;;)>$4e7=toN`RS&kdWHku(U%!TR=2rUCc`S(L{x#U`#j{8%HyP0auwV1JqS` zao-_a2+);T7);TTnc5}*Vhjx7tzd)GqBP07u2cR`?ZWH>S`i~QS0P>(>8>l^0LVgu ztjBCJCec5*3jlY;Rfw$*$bWuhk~2ZnjMyNEY16SS7tRM`R_2mbUiG=7D)$XVhJ zncR;s#ezky5rb+woSOTW?uA3dd+4rAn!fbaUe^~?!Ak6RVp`pGh#Gr4rg;GWr6KyP zqw-8cn8$I4qhGrm$kV;ZLA}}tfaUE_Mp`jN!HKd&Z#j>yxhV(LT@qYWsQ+TC|r3p~V{3w)j zHyGm@kRw#97fZVXz;im$#GR7D`*l=G8h#ey`4PbD3xTVR7w&gbrYb?nw}+QOVqqZ? z^nJr^W+)@#tt}mekhuxS{9A1-(`itr)Hax0t_;tW0m5a42zvvKTIcryST6+3rJs_- z*8o&i2q<49UfbCTwCdj1;$>Q2e*5AuvJCx#{lv?Kxg_X z`U8+k(%uH(G(Vtgt(Nu$d;wF*X0CEwhedVsa^_FMN`W-X)7#={U zxuDW`-S01Y(QK>+bPAYFw(GaVXD*#AjG5ZbHE_3`T5SeO=%U%1E4R*OWmzhn)g!tU zPYxtZowY+Oe>6gq+HzKw#bOcEoMkc*6u_a)2#HF$6hKr38XuERJT(|e#G^)N@)FB3 zlii7pdL+RbK>UqHQBoMXxFLe-GP^7=smSZSIn*CIwRf`F2wl*SNOzMiiqcTm6hqfx z7SHjt4pG&pco)6uD8K1{KiOXb`}MUlvtk`8GsCWEtbcjmNB9a#xvPm z1m$XM=|kOP!VH-b#Y}>mh>m*2R8OA{Xj2upLLM>HxXu;Te5lRMpuS5tQ$46u%!s+^ zfkd(n@2FYC2`%Y_-ir!MHCiK7)PzG{z;jyfj>pJ*uPowAnn~2q8KDG47mcIrkENE~ zW_AOmf(k!T3&^5H@SsB_^fG%$o9AyW7d4p#va0|Sk!}=xM$@K6F|Z3ZiWx!Sr4`>~ z*65q7wua_4ry6mb3(!!eDh6StGaLg3&M6Uv$EfDam?$ldT1M#4n}<*-NeHQGC~hP* zGGv6NIgJSnfNJNqO?BE*=~RW89LPf3sI5k5N`WR4@Dg;9P`QcHIU`iMOw1cZlt`yy zLi-}nP*KwvW6_jvyAtK{Y5kwJlm0{sv5;W9<`KrQL%t zMu6v0a|jdaK1~kT+_OG6hAQCDWVexpsL*%Va1O>etBZeyW1&+CxF~QgpfRN60j4cIRTS2PhzGOkr7P9#K`QQ-nsSL_L>X52PU-Ocbi-YxK&Y z&6PC^uiP5ybbtchLi!}DMu$K|EwJ!HWzej0Dnm@T3`{(n5XJ_(lWwYvMs0+~Dzef? zVW!ms1OXVTta^?Mm(Y(1g;CQEXDg^gx(6C+!B0knU3l5Pa^cockpgt}6>_G7u?8Y3 zBXp5!Z&Rh>QlIHYlM!g10{{Yj>8L%$wqUM=gDF!Kh5?`m=hqOjQb7(kcY0a4Ye~7H z4esYF4BVR94aK6rk?gY^oHe#W&Gl8yHeZ;`w#ZOCnM=aeMNJq2%!g<+bl0@!Ardgw zW=x*21to%Q3T1#$;FAF#K^3+|CnzKBVo`hVi+AZ1qN)?{grl?O>Oy%?#V*{nIEVo8 z1HVcO8E2y)JX*X*bO`v0v%!1#1NcNGDTu<+1|u}XdEC?h<1>5uEr^Dvk~tIXSOpGt zkn$2b7MiY5+nbl=&-yggiZcr0$Tc=WRLXCUbJ~B0{}xQ=Sc--JH0@_T`ppw@a1raoLG@)BqJFl8i+BDZrlFJal#O@(-s%*TLsjN zNmt4E&z#G4xgKkPx2vjj{he)oMyQugPtj}_fvgFUm0nR)`ZMICu3zLd@AZA`F1d}zn;^>&n&H0g*i5B!u|7IH2%qVpNM}{tE)24?v$cr|Ekb)~ zK`M@X6KcsFi&ZrbCi#b&^5mwowNYKTtc~hnd>HwOp3aGgAeIu)%?Yb{AWHBlLyGGWgy9HFOsYd2Lz5kd6m%>y7>UDa zQM8x2|2>C=wbcl^YNlB$ZI4BbI6QyK8o+TeA(GFjFxs#-W`# z=oHgf`f73N3o}LUWHJc%rIE=;U?HsxnIJ>0ZO3}Pr>_;u0(%A9EZ5COgIs50gp3;Y zdIiZfLm)KL+@SMp9Hso9kqnM4!lsC%b5Vy_>LOs+>7R7`VBB7mm4aU!3xwoRupn@Q zdjQ~PMgcG@*G&&DC<5d{XI<;8m2FuH^D6I5nQAfJh#a6Rj?sz`=;)qYAQ_=D%CIT0 z6r!-`T<8qA2oppXc!)M5E9QQVz6whPG3r&w^9uJc-Gc{rfheGR78FxFt?7XZW-NAe zUF?j}W!la*=qbd)a4sAbcV4hLg9r1mnN^0Yzp7@aiff$K5m2B55tx2bRW_+hY*IMJ z%aN#Kv-I~AZ;j}+vSx^#PVzuPCuuKOePMm&c`kj9T-qub3noIdhlk3g`cpi{iZg=f z(P@9|#o<*>PCZ#YMT}^R#E{jCu8a^SL1Np>7_sQ6kwQdDrdq{ZVo51hpF{H(z*S$= znX(NU(=8Wgx}6Kie7&ekEZCh;gY)3x+(yK}gx-vo?OtOxLX|2pQzy&8P1<1@`KqpV z4-u|%(gatknBs8C%8NznTvu#m zbKS*KG3-$}U5|t^j*QMDF1@Fi=n?f(JC9?Ovp7#p;~!&Edm{^|Hk*a`sDxn696+U-n*Ip-0yw1aM>NJ_uNokXM^Y+L>l{ z$DJ9cae(5Y0IHy(s;bf-LAVN_qKXQt6e18bY7wdg6+#pVp+YUB{wb|gL8KxODc?PF zcXsUBL4ki2S3BQ1-?`_U`@TE71NS^eCJ`m@y#GGYMMzb;8LtjAs9w40$1CYV!>gMw zio>sN&YiG*YtnNkynNXz<|`F9unN-hrYe?QvGxxQTV=N-Gb>gs+oDq+IY4w+7$m>< z^!?S==E&H*Tr4MQhQ$c2E4v^qJl%K{SP-aF{Z^$aX$(ZinAH76qBMVMQd1R#a$z^o zu~1zcyNRw_yyogwizpTINP!=U@k}632jFYg0#FwpD;O7xXe{GN$1UnUbi=I1)`BNi zx`}#X^qSOnF@9B4-waAp8VmC+OqpQowZrNTLG?P!cmP>iw~?|ftJ@>>Ja5Y)d8@Vs@yfhdUTqiEBSHooO{|YPKNwAuv8-;J z8lyf!T)!BP)_A%$2i0?e_2HTM?LEhl%Z$#?LVIjI*&puQ=f&+tbjA%+-;d-bO78cBfxri-UwMFaRJjcOm4b(lYN;B`v z*g3lyyLnl7&Z2b*ZJ#z+8tWcih4tOqyzboRuwIF6AJcX-q#Hwu#(Rc8*(3DnSL=Cd zccvrL+0nUkuWC6-4)6jlwzh|GZDG@0z{Y7C4m`Uu;VX~V&=qy>wT%qZ>(FtPP+Q+f z|9;4~!7pNCwe>h|0bCVOacr%TYFGpEkFA~R9z+ib-Q_c-^c{Ex@vOwtgGbroPn+gM ze-_HFA~)d1se||Jz~ihxP9F5+ z{}0er30qb3_OM9P7Gt}y6FRJ5qs9ZqUg+DIeZ}xdv0IsaQ?qtvKQvx}r-AX_L?;s` z#1TuSev;lXK97i!X8!~;=(7>~GWNw2nl+eT!zp=2v&~?2bSYv_VP$@=S%>*FMt?bC z&*GG(HxswlWxjy9wlv#k{)`%_L$gEXFR-TjH5)R233fbUuhD99G%KR6na)P+HCj*S zG&^Pf5i9ilh`mXh=;xX}in<%=^@zPmTj{c9v*tT=GbL^e`}uA2GTlOJBK9xZMq4zS zHS5K8+O63OW|O#;4r%tHxn8u>Sj4u79dtTk?P4cA7O_2|lb+G+H)gx&qKgsRBW|Nt zG9RI5)IUah$dhiPG}e2vNi*oaI%zr zC*xkmEMq^gneJkJlyMq(13kd@M;I--N1UMy4O79$(5L9@z}x9M;BxXr2DilHz*c$+ z*hUwC+v%skPI`~+hvC`FmR4E^{Z48(x;f_Wjs%3(BgUWNnsH!Ut;^q zY=4>Ub8I1@`ere9GmbINFwQbwVw__ngZ&x18OIoB7-tzTG0riP$^MMpjAM+mjB|{X zU?0XY##zQojB|{XWFN+E#{J0xdVaRCM{QMxmL?{EECvKVczXpwrjbA zo;3xU-a$V=2V1b`LcdNeyR^Jb%e`9OuH_wC?$a`>Wv`Y8wCvNeU&}kS9MEz|%e%B3 z)^Y?=oewS_A8<=kj{F1-Py2x^XO7BoM-~Iytx(qYWx3!?AMxN)46*@UiwaYLq)ahz zJsm*3hlhLJ@}y(uD>0X9?0^jNrF@XD1y|ddsswgfW>l>0NN-qrr|hEiDKz9&4~|MF zf0{MF7GKT0U;0JQo>YDxtUQR6cT3M-w6ec4?s{d;n|GG<%GrSe1%3T=;;xAQaW};X8yzMXGSW1eq3fsjzeX?=z5M_Kn7*I zwnQ}OR`k^73-Nhe&;jj(*KO+ekIH;$sN%%tXb^LKO7>R*IU&8;*bbBnvQ&zXcK#>_ z?4sxT?s$OhRg&3C-kJ7opHzOzk?&4UXU%7 zJn8!snQNX|pIo$uQ%Sjlo?E6|&c#X;+|#5UM3Qu5SyqCf@o`@U%F=_THB-IN>hM${ z@bcJjRVC&YQ(bIdyF%y|HW+0+Ih-#`a^!eGys@!Ny1RXz#E$cFC$PyP<6(?LTLz~b zNAYaW_P&m5+fsUO;?^=PzPkRB-TAv4=iVJU_nmvYzHxE-Pn58P zSgF8BT83E3Y6{N6*hop3o3g1Now@h!^}FXDxk>O(KZA0{imc>TU^j-Pfmu*hq~cl<8zDEez2J6D#TDMrsHxX{|vv3RJ=gstQvw zkrtFnkqK*~Xi!QznNBv;vn7=2WU`@-Tic+*IS+Cx1)qkr0ZkE=5@N$Lv>Vo?R9{r$ zRL#~>Q`alCC3ID)j#7D)iZ)dPX59^#U?FZWHVL{uI%_XIXJrNt9J+Ix@RuB-GX+!^j#|&veoN)lP)e^e9vSo3meJeL*iRF&-g-GZ_oLauJWq5rnulKi-)ji++!_M&kruv^JtzU0G N?8E*4_~y^RzX5{460`sS literal 0 HcmV?d00001 diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Plugins/CodeAnalysis/UnityPipeline.System.Runtime.CompilerServices.Unsafe.dll.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Plugins/CodeAnalysis/UnityPipeline.System.Runtime.CompilerServices.Unsafe.dll.meta new file mode 100644 index 0000000..49c939a --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Plugins/CodeAnalysis/UnityPipeline.System.Runtime.CompilerServices.Unsafe.dll.meta @@ -0,0 +1,60 @@ +fileFormatVersion: 2 +guid: cab0ad3a2a404673a7c7a6b3939109b6 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: + - UNITY_EDITOR || DEVELOPMENT_BUILD || ENABLE_RUNTIME_PIPELINE + isPreloaded: 0 + isOverridable: 1 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 1 + settings: + CPU: AnyCPU + DefaultValueInitialized: true + OS: AnyOS + - first: + Standalone: Linux64 + second: + enabled: 1 + settings: + CPU: AnyCPU + - first: + Standalone: OSXUniversal + second: + enabled: 1 + settings: + CPU: AnyCPU + - first: + Standalone: Win + second: + enabled: 1 + settings: + CPU: AnyCPU + - first: + Standalone: Win64 + second: + enabled: 1 + settings: + CPU: AnyCPU + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/SecurityTokenManager.cs b/AIClient/Packages/com.unity.pipeline/Runtime/SecurityTokenManager.cs new file mode 100644 index 0000000..5ea2f97 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/SecurityTokenManager.cs @@ -0,0 +1,150 @@ +using System; +using System.Security.Cryptography; +using System.Threading; +#if UNITY_EDITOR +using UnityEditor; +#endif +#if UNITY_6000_5_OR_NEWER +using Unity.Scripting.LifecycleManagement; +#endif + +namespace Unity.Pipeline.Security +{ + ///

+ /// Manages the security token used to authorize Pipeline server requests. In the Editor the token + /// is persisted in SessionState so it survives domain reloads (but dies with the editor process), + /// keeping long-lived clients (MCP/IDE) authenticated instead of hitting 401 after every reload. + /// Player builds use a per-process in-memory token. Published to the instance descriptor (port + /// file) for CLI discovery; never written to a separate file. + /// +#if UNITY_6000_5_OR_NEWER + [NoAutoStaticsCleanup] +#endif + static class SecurityTokenManager + { + // In-editor persistence key. SessionState is session-scoped editor state (wiped on editor exit). + private const string SessionStateKey = "Unity.Pipeline.SecurityToken"; + + // Fast in-memory cache, warmed on the main thread at server start (see BasePipelineServer.Start) + // so background auth reads a populated static instead of touching SessionState off-thread. + private static string s_CachedToken; + + // Guards the check-and-set so two threads can't race to generate a token on first access. + private static readonly object s_Lock = new object(); + + // Thread that first touches this class (the main thread, since the server warms on it at start). + // SessionState is main-thread-only, so it is only touched when running on this thread. + private static readonly int s_MainThreadId = Thread.CurrentThread.ManagedThreadId; + + /// + /// Get or create the session's security token. In the Editor it is persisted in SessionState so + /// it survives domain reloads (regenerated only on editor restart or via + /// / ); player builds generate it once per process. + /// + /// The current session token. + public static string GetOrCreateToken() + { + // Fast path: plain read of the warmed cache — no lock, no SessionState. + var cached = s_CachedToken; + if (!string.IsNullOrEmpty(cached)) + return cached; + + lock (s_Lock) + { + // Re-check: another thread may have generated the token while we waited on the lock; + // regenerating here would overwrite (and invalidate) the token it just handed out. + if (!string.IsNullOrEmpty(s_CachedToken)) + return s_CachedToken; + +#if UNITY_EDITOR + // Main thread only: safe to touch SessionState (the warm path). + if (Thread.CurrentThread.ManagedThreadId == s_MainThreadId) + { + // Rehydrate a token from earlier this session (survives domain reloads). + var persisted = SessionState.GetString(SessionStateKey, string.Empty); + var mainToken = string.IsNullOrEmpty(persisted) ? GenerateSecureToken() : persisted; + if (string.IsNullOrEmpty(persisted)) + SessionState.SetString(SessionStateKey, mainToken); + // Publish last so a fast-path reader sees either null (and locks) or the persisted token. + s_CachedToken = mainToken; + return s_CachedToken; + } +#endif + + // Player builds; or Editor off the main thread with a cold cache, where we generate + // in-memory rather than touch SessionState off-thread (which would throw/500). + s_CachedToken = GenerateSecureToken(); + return s_CachedToken; + } + } + + /// + /// Compare two tokens in length-independent constant time to avoid leaking the expected + /// token through comparison timing. + /// + /// First token. + /// Second token. + /// True if the tokens are equal. + public static bool ConstantTimeEquals(string a, string b) + { + if (string.IsNullOrEmpty(a) || string.IsNullOrEmpty(b)) + return false; + + var diff = a.Length ^ b.Length; + for (int i = 0; i < a.Length && i < b.Length; i++) + diff |= a[i] ^ b[i]; + + return diff == 0; + } + + /// + /// Generate a cryptographically secure token. + /// + private static string GenerateSecureToken() + { + using (var rng = new RNGCryptoServiceProvider()) + { + var bytes = new byte[32]; // 256 bits + rng.GetBytes(bytes); + return Convert.ToBase64String(bytes); + } + } + + /// + /// Clear the cached token (and the persisted SessionState copy) so the next call generates a + /// fresh one. Used by tests and by . Call on the main thread (touches + /// SessionState). + /// + public static void ClearCache() + { + lock (s_Lock) + { + s_CachedToken = null; +#if UNITY_EDITOR + SessionState.EraseString(SessionStateKey); +#endif + } + } + + /// + /// Force a new token and return it. Old-token revocation is immediate for request auth + /// (GetToken validates live); the port file refreshes on the next heartbeat. Call on the main + /// thread; a command exposing this must be MainThreadRequired and republish the descriptor. + /// + /// The new token. + public static string RotateToken() + { + ClearCache(); + return GetOrCreateToken(); + } + + /// + /// Test-only: drop the in-memory cache but keep SessionState, to simulate a domain reload + /// (statics cleared, SessionState survives). + /// + internal static void ResetInMemoryCacheForTests() + { + s_CachedToken = null; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/SecurityTokenManager.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/SecurityTokenManager.cs.meta new file mode 100644 index 0000000..cbd37aa --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/SecurityTokenManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9d47c8a5848e4b543936670e8482ff69 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Telemetry.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Telemetry.meta new file mode 100644 index 0000000..0dcb221 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Telemetry.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 114afe9c22f14d80babb5231767c7d61 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Telemetry/EvalUsageFingerprinter.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Telemetry/EvalUsageFingerprinter.cs new file mode 100644 index 0000000..4fc4a1c --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Telemetry/EvalUsageFingerprinter.cs @@ -0,0 +1,422 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text; + +#if UNITY_EDITOR || (UNITY_STANDALONE && DEBUG) +using UnityPipeline.Microsoft.CodeAnalysis; +using UnityPipeline.Microsoft.CodeAnalysis.CSharp; +using UnityPipeline.Microsoft.CodeAnalysis.CSharp.Syntax; +#endif + +namespace Unity.Pipeline.Telemetry +{ + /// + /// Structural classification of an eval body. Matches the epic's usage buckets: the majority of + /// eval calls are one-liners (a single method invoke / value read / flag set), which we tag as + /// ; anything with more than one statement (polling loops, bulk + /// setup) is . + /// + static class EvalClassification + { + public const string SingleExpression = "single-expression"; + public const string Statements = "statements"; + } + + /// + /// Result of analysing one eval body: its structural and the ranked + /// API (top-level member-access paths) extracted from the syntax tree. + /// + struct EvalUsageAnalysis + { + public string Classification; + public IReadOnlyList Fingerprints; + } + + /// + /// Extracts a privacy-preserving "fingerprint" of an eval body from its C# syntax tree, without + /// storing the raw source (AUTHAPI-29). A fingerprint is the top-level member-access path of each + /// access site — e.g. AssetDatabase.Refresh, PlayerSettings.SetScriptingBackend, + /// Object.FindFirstObjectByType<T>, MatchManager.Instance.State — which is + /// enough to rank which APIs agents actually reach for (steering the eval-displacement backlog, + /// AUTHAPI-24). + /// + /// PRIVACY CONTRACT — strict whitelist rendering. The only source text that can ever appear in a + /// fingerprint is an identifier, type name, or member name taken from the syntax tree. Literals, + /// interpolated strings, and every expression form not on the whitelist are replaced by the + /// neutral ("secret".Length records as <expr>.Length); + /// object creations render as new TypeName (constructor arguments never appear); casts + /// unwrap to the inner expression (((Foo)o).Bar records as o.Bar); generic type + /// arguments are normalised to arity placeholders (<T>). A path that would be nothing + /// but the placeholder carries no API information and is dropped entirely. + /// + /// Conditional-access chains (a?.B.C()) are fingerprinted with ?. normalised to + /// ., so they rank together with their unconditional form. + /// + /// Known blind spots — the ranking UNDERCOUNTS these forms (deliberate, to keep the walker + /// simple and re-entrancy-free); consumers of the report should not read absence as proof of + /// non-use: + /// + /// Arguments nested inside a chain's receiver call are not walked: in + /// Configure(Settings.Load()).Apply() only Configure().Apply is recorded — the + /// callee chain is not re-entered, so Settings.Load is missed. + /// A bare object creation with no trailing member access (new Foo(...); as a whole + /// statement) produces no fingerprint. + /// Bodies nested deeper than the walker's depth guard are abandoned mid-walk. + /// + /// + /// Threading: pure Roslyn + BCL — no Unity API calls — so is safe to run + /// off the main thread. The telemetry writer relies on this and runs it on a background task + /// from a snapshot captured at eval completion. + /// + /// This is a SEPARATE parse from the one EvalCodeCompiler does to actually compile and + /// run the eval, by necessity rather than oversight: that parse is of a generated wrapper + /// source (the raw body embedded inside a class PipelineEval_<id> { ... Execute() { + /// ... } }) under SourceCodeKind.Regular with the project's #if defines, not + /// of the raw body alone as a top-level SourceCodeKind.Script compilation unit the way + /// expects it. Sharing that tree would mean threading it out of + /// RoslynCompilationService (on both the success AND failure path — failures still get + /// recorded) and locating the wrapped Execute() body inside it, coupling this class to + /// the wrapper's exact shape. Not worth it today: the extra parse already runs off the eval + /// response path (see Threading above), so it costs background CPU, not eval latency. + /// + static class EvalUsageFingerprinter + { + /// + /// Upper bound on fingerprints kept per record, so a pathological body can't bloat the log. + /// Truncation keeps the FIRST N access sites in tree (source) order, not the most frequent — + /// acceptable because bodies with more than 32 access sites are rare outliers. + /// + public const int MaxFingerprints = 32; + + /// + /// Neutral stand-in for any expression not on the rendering whitelist (literals, interpolated + /// strings, arithmetic, lambdas, …). Guarantees no raw source text leaks into a fingerprint. + /// + public const string Placeholder = ""; + +#if UNITY_EDITOR || (UNITY_STANDALONE && DEBUG) + + private static readonly CSharpParseOptions m_ScriptOptions = + new CSharpParseOptions(kind: SourceCodeKind.Script); + + /// + /// Analyse an eval body: classify it and extract its API fingerprints. Never throws — a body + /// that fails to parse yields an empty fingerprint list and a best-effort classification. + /// + public static EvalUsageAnalysis Analyze(string code) + { + if (string.IsNullOrWhiteSpace(code)) + return new EvalUsageAnalysis { Classification = EvalClassification.Statements, Fingerprints = new List() }; + + CompilationUnitSyntax root; + try + { + root = CSharpSyntaxTree.ParseText(code, m_ScriptOptions).GetCompilationUnitRoot(); + } + catch + { + return new EvalUsageAnalysis { Classification = EvalClassification.Statements, Fingerprints = new List() }; + } + + return new EvalUsageAnalysis + { + Classification = Classify(root), + Fingerprints = ExtractFingerprints(root) + }; + } + + /// Convenience overload used by tests: fingerprints only. + public static IReadOnlyList ExtractFingerprints(string code) => Analyze(code).Fingerprints; + + /// Convenience overload used by tests: classification only. + public static string Classify(string code) => Analyze(code).Classification; + + /// + /// One-liner iff the body is exactly one statement that is an expression or a value-returning + /// return. A lone loop/if/block (e.g. a polling loop) is a statement body, not a one-liner. + /// + private static string Classify(CompilationUnitSyntax root) + { + var statements = root.Members + .OfType() + .Select(m => m.Statement) + .ToList(); + + if (statements.Count == 1) + { + var only = statements[0]; + if (only is ExpressionStatementSyntax || + (only is ReturnStatementSyntax ret && ret.Expression != null)) + { + return EvalClassification.SingleExpression; + } + } + + return EvalClassification.Statements; + } + + private static IReadOnlyList ExtractFingerprints(CompilationUnitSyntax root) + { + var walker = new FingerprintWalker(); + walker.Visit(root); + // Take() keeps the first MaxFingerprints access sites in tree (source) order — see the + // MaxFingerprints doc for why that truncation policy is acceptable. + return walker.Fingerprints.Count > MaxFingerprints + ? walker.Fingerprints.Take(MaxFingerprints).ToList() + : walker.Fingerprints; + } + + /// + /// Walks the syntax tree collecting one fingerprint per top-level access site: an invocation's + /// callee (A.B.C(...) → A.B.C) or a member-access chain that is not itself the + /// head of an enclosing call/access (A.Instance.State). Nested access sites inside call + /// arguments are still collected (they are their own sites); the callee chain is not re-counted. + /// A depth counter abandons subtrees nested past so a pathological body + /// (machine-generated nesting) can't blow the stack — fingerprinting is best-effort. + /// + private sealed class FingerprintWalker : CSharpSyntaxWalker + { + /// Maximum syntax depth walked; deeper subtrees are abandoned. + private const int MaxDepth = 64; + + public readonly List Fingerprints = new List(); + private int m_Depth; + + public override void Visit(SyntaxNode node) + { + if (m_Depth >= MaxDepth) + return; // Abandon this subtree — best-effort telemetry, never a liability. + + m_Depth++; + try + { + base.Visit(node); + } + finally + { + m_Depth--; + } + } + + public override void VisitInvocationExpression(InvocationExpressionSyntax node) + { + AddChainHeadFingerprint(node, node.Expression, () => RenderPath(node.Expression)); + + // Deliberately do NOT recurse into the callee chain (already captured above), but do + // walk the arguments so nested calls/reads passed as arguments are captured too. + VisitArgumentsIfPresent(node.ArgumentList); + } + + public override void VisitMemberAccessExpression(MemberAccessExpressionSyntax node) + { + if (IsChainHead(node)) + Add(RenderPath(node)); + + // Continue into the expression side so nested access sites are still discovered; + // inner chain members are guarded by IsChainHead and won't be double-counted. + base.VisitMemberAccessExpression(node); + } + + public override void VisitElementAccessExpression(ElementAccessExpressionSyntax node) + { + // A bare element-access chain head (cache[key]) previously produced NO fingerprint + // at all — no member access for the walker to see — while the conditional form + // (cache?[key]) records "cache[]": the two must rank together, so bare element + // access on a member/name receiver is fingerprinted the same way. + AddChainHeadFingerprint(node, node.Expression, () => RenderPath(node)); + + // Walk the bracket arguments so nested reads/calls inside the indexer are captured. + VisitArgumentsIfPresent(node.ArgumentList); + } + + public override void VisitConditionalAccessExpression(ConditionalAccessExpressionSyntax node) + { + // The whole ?. chain is ONE fingerprint (RenderPath normalizes '?.' to '.'): + // descending into its parts would record the receiver and the bound members as + // separate (and misleading) entries. + if (IsChainHead(node)) + Add(RenderPath(node)); + + // Parity with VisitInvocationExpression/VisitElementAccessExpression: only the head + // access's OWN argument list is walked, scoped to WhenNotNull (not the receiver + // before '?.') — the receiver's nested-call arguments are the same documented + // blind spot the unconditional forms accept, not something '?.' should uncover. + // Only the outermost argument lists are visited — the walker recurses within. + // Covers both parenthesized (ArgumentListSyntax) and bracketed + // (BracketedArgumentListSyntax) forms, so an indexer inside a conditional chain + // (a?.b[SomeCall()]) is captured too — a bracketed list was previously invisible + // to this sweep, silently dropping SomeCall. + if (node.WhenNotNull != null) + { + foreach (var argumentList in node.WhenNotNull + .DescendantNodes(n => !(n is ArgumentListSyntax) && !(n is BracketedArgumentListSyntax)) + .Where(n => n is ArgumentListSyntax || n is BracketedArgumentListSyntax)) + Visit(argumentList); + } + } + + // Shared shape between VisitInvocationExpression and VisitElementAccessExpression: add + // the rendered path only for a chain head whose receiver is renderable, computing the + // path lazily so non-chain-head nodes (the overwhelming majority visited) skip RenderPath + // entirely instead of just discarding its result. + private void AddChainHeadFingerprint(SyntaxNode node, ExpressionSyntax receiver, System.Func render) + { + if (IsChainHead(node) && IsMemberOrName(receiver)) + Add(render()); + } + + private void VisitArgumentsIfPresent(BaseArgumentListSyntax argumentList) + { + if (argumentList != null) + Visit(argumentList); + } + + private void Add(string path) + { + // A path that is nothing but the neutral placeholder carries no API information — + // drop the fingerprint rather than pollute the ranking with "" noise. + if (string.IsNullOrEmpty(path) || path == Placeholder) + return; + Fingerprints.Add(path); + } + + // A node is the head of its access/call chain when its parent is not another link of the + // same chain (member access, invocation, or element access). + private static bool IsChainHead(SyntaxNode node) + { + var parent = node.Parent; + // See through parentheses: in (a?.b).c the conditional is part of the enclosing + // chain, not a head of its own. + while (parent is ParenthesizedExpressionSyntax paren) + parent = paren.Parent; + return !(parent is MemberAccessExpressionSyntax) + && !(parent is InvocationExpressionSyntax) + && !(parent is ElementAccessExpressionSyntax); + } + + // Also accepts a call or parenthesized expression as the receiver: RenderPath already + // knows how to render both (GetHandler()() -> "GetHandler()", (A.B)() -> "A.B"), so + // gating them out here was dropping the whole access site instead of rendering it — + // not even the placeholder, since Add() was never reached. + private static bool IsMemberOrName(ExpressionSyntax expr) => + expr is MemberAccessExpressionSyntax || expr is IdentifierNameSyntax || expr is GenericNameSyntax + || expr is InvocationExpressionSyntax || expr is ParenthesizedExpressionSyntax; + } + + /// + /// Render an expression to its fingerprint path: dotted identifiers, with generic method type + /// arguments normalised to arity placeholders (<T>, <T1, T2>) so + /// FindFirstObjectByType<Foo> and <Bar> rank as one API. + /// + /// STRICT WHITELIST (the privacy contract of the class doc): only the expression forms listed + /// below render source text, and each renders identifiers/type/member names exclusively. + /// Everything else — literals, interpolated strings, arithmetic, lambdas, conditionals, … — + /// falls through to the neutral so no raw source can ever leak into + /// a fingerprint. Casts unwrap to the inner expression; object creations render as + /// new TypeName. Rendering recursion is bounded by as a second + /// layer of defence against pathological nesting (chains hang below their head, so they are + /// not covered by the walker's descent guard). + /// + private static string RenderPath(ExpressionSyntax expr) => RenderPath(expr, 0); + + private const int MaxRenderDepth = 64; + + private static string RenderPath(ExpressionSyntax expr, int depth) + { + if (depth >= MaxRenderDepth) + return Placeholder; + depth++; + + switch (expr) + { + case IdentifierNameSyntax id: + return id.Identifier.Text; + case GenericNameSyntax gn: + return gn.Identifier.Text + RenderArity(gn.TypeArgumentList.Arguments.Count); + case QualifiedNameSyntax qn: // Namespace-qualified type in type position, e.g. new UnityEngine.GameObject + return RenderPath(qn.Left, depth) + "." + RenderSimpleName(qn.Right); + case AliasQualifiedNameSyntax aq: // global::UnityEngine → keep the name, drop the alias + return RenderSimpleName(aq.Name); + case MemberAccessExpressionSyntax ma: + return RenderPath(ma.Expression, depth) + "." + RenderSimpleName(ma.Name); + case InvocationExpressionSyntax inv: + return RenderPath(inv.Expression, depth) + "()"; + case ElementAccessExpressionSyntax ea: + return RenderPath(ea.Expression, depth) + "[]"; + case ParenthesizedExpressionSyntax pe: + return RenderPath(pe.Expression, depth); + case CastExpressionSyntax ce: // ((Foo)o).Bar → o.Bar: unwrap to the casted expression + return RenderPath(ce.Expression, depth); + case ObjectCreationExpressionSyntax oc: // new GameObject("x").AddComponent → new GameObject.AddComponent + return "new " + RenderPath(oc.Type, depth); + case PredefinedTypeSyntax pt: + return pt.Keyword.Text; + case ThisExpressionSyntax _: + return "this"; + case BaseExpressionSyntax _: + return "base"; + case ConditionalAccessExpressionSyntax cond: + // a?.B.C renders as a.B.C: '?.' is null-propagation noise for ranking + // purposes. Rendering only the bound member (the old fall-through via the bare + // MemberBinding) silently dropped the receiver, producing a colliding entry + // ("State.Value" for MatchManager.Instance?.State.Value). When the chain ends + // in a call, fingerprint the CALLEE (a?.B() -> a.B) so it ranks together with + // its unconditional form — the walker uses the same callee convention for + // plain invocation heads. + var conditionalTail = cond.WhenNotNull is InvocationExpressionSyntax topCall + ? topCall.Expression + : cond.WhenNotNull; + var tailRendered = RenderPath(conditionalTail, depth); + // An element-binding tail (cache?[key] -> "[]") concatenates WITHOUT a dot so + // the fingerprint matches the unconditional cache[key] form ("cache[]"). + return tailRendered.Length > 0 && tailRendered[0] == '[' + ? RenderPath(cond.Expression, depth) + tailRendered + : RenderPath(cond.Expression, depth) + "." + tailRendered; + case MemberBindingExpressionSyntax mb: + return RenderSimpleName(mb.Name); + case ElementBindingExpressionSyntax _: // the ?[...] binding of a conditional chain + return "[]"; + default: + // NOT a raw ToString(): anything off the whitelist (string/char/numeric literals, + // interpolated strings, lambdas, arithmetic, …) is reduced to the neutral + // placeholder so source text can never leak into the telemetry log (AUTHAPI-29). + return Placeholder; + } + } + + private static string RenderSimpleName(SimpleNameSyntax name) + { + if (name is GenericNameSyntax gn) + return gn.Identifier.Text + RenderArity(gn.TypeArgumentList.Arguments.Count); + return name.Identifier.Text; + } + + private static string RenderArity(int count) + { + if (count <= 0) + return string.Empty; + if (count == 1) + return ""; + + var sb = new StringBuilder("<"); + for (var i = 1; i <= count; i++) + { + if (i > 1) + sb.Append(", "); + sb.Append("T").Append(i); + } + sb.Append(">"); + return sb.ToString(); + } + +#else + /// Runtime compilation (and therefore eval) is unavailable on this platform. + public static EvalUsageAnalysis Analyze(string code) => + new EvalUsageAnalysis { Classification = EvalClassification.Statements, Fingerprints = new List() }; + + public static IReadOnlyList ExtractFingerprints(string code) => new List(); + + public static string Classify(string code) => EvalClassification.Statements; +#endif + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Telemetry/EvalUsageFingerprinter.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Telemetry/EvalUsageFingerprinter.cs.meta new file mode 100644 index 0000000..9126cc0 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Telemetry/EvalUsageFingerprinter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a08e235068524a4aa303c035a80f9008 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Telemetry/EvalUsageReport.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Telemetry/EvalUsageReport.cs new file mode 100644 index 0000000..9c29f1c --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Telemetry/EvalUsageReport.cs @@ -0,0 +1,266 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Newtonsoft.Json; + +namespace Unity.Pipeline.Telemetry +{ + /// A ranked API fingerprint with its occurrence count across all recorded evals. + [Serializable] + class FingerprintCount + { + [JsonProperty("member")] + public string Member { get; set; } + + [JsonProperty("count")] + public int Count { get; set; } + } + + /// An eval pattern already served by an existing catalog command — a "stop using eval" hit. + [Serializable] + class CoverageHit + { + [JsonProperty("member")] + public string Member { get; set; } + + [JsonProperty("count")] + public int Count { get; set; } + + /// The existing command that already covers this pattern. + [JsonProperty("command")] + public string Command { get; set; } + } + + /// A frequently-eval'd pattern with no covering command — a candidate for a new typed command. + [Serializable] + class CoverageGap + { + [JsonProperty("member")] + public string Member { get; set; } + + [JsonProperty("count")] + public int Count { get; set; } + + /// A proposed command name from the coverage map, when one exists but is not yet built. + [JsonProperty("suggestedCommand", NullValueHandling = NullValueHandling.Ignore)] + public string SuggestedCommand { get; set; } + } + + /// + /// Coverage cross-reference between recorded eval fingerprints and the live command catalog: + /// which patterns are already coverable (habit/eval-avoidable) and which high-frequency patterns + /// are still uncovered (the next commands to build — feeds AUTHAPI-17 / AUTHAPI-24). + /// + [Serializable] + class EvalCoverageSuggestions + { + [JsonProperty("covered")] + public List Covered { get; set; } = new List(); + + [JsonProperty("topUncovered")] + public List TopUncovered { get; set; } = new List(); + } + + /// + /// Aggregated eval-usage report: ranked API fingerprints, one-liner vs multi-statement split, + /// error rate, and coverage suggestions. This is the artifact that turns eval-displacement backlog + /// triage into a lookup (AUTHAPI-24 / AUTHAPI-29). + /// + [Serializable] + class EvalUsageReport + { + [JsonProperty("totalCount")] + public int TotalCount { get; set; } + + [JsonProperty("successCount")] + public int SuccessCount { get; set; } + + [JsonProperty("errorCount")] + public int ErrorCount { get; set; } + + /// Fraction of recorded evals that failed, 0..1. + [JsonProperty("errorRate")] + public double ErrorRate { get; set; } + + [JsonProperty("singleExpressionCount")] + public int SingleExpressionCount { get; set; } + + [JsonProperty("statementsCount")] + public int StatementsCount { get; set; } + + /// Percentage of evals classified as one-liners (single-expression), 0..100. + [JsonProperty("oneLinerPercentage")] + public double OneLinerPercentage { get; set; } + + /// + /// Total number of DISTINCT fingerprints observed across all records, before the ranked + /// list is capped — so truncation is visible + /// (distinctFingerprints > fingerprints.Count means the tail was cut). + /// + [JsonProperty("distinctFingerprints")] + public int DistinctFingerprints { get; set; } + + /// + /// API fingerprints ranked by descending occurrence count. Capped (see + /// ); carries the + /// uncapped total. + /// + [JsonProperty("fingerprints")] + public List Fingerprints { get; set; } = new List(); + + [JsonProperty("coverageSuggestions")] + public EvalCoverageSuggestions CoverageSuggestions { get; set; } = new EvalCoverageSuggestions(); + } + + /// + /// Curated, heuristic map from an API fingerprint to the command name that would cover it. Truth + /// about whether that command actually exists comes from the live catalog at report time, so a + /// mapped-but-absent command surfaces as a concrete gap ("build refresh_assets"). Kept + /// deliberately small and extensible — this is a hint layer, not an exhaustive registry. + /// + static class EvalCoverageMap + { + public static readonly IReadOnlyDictionary Default = new Dictionary + { + // The habit case: a command already exists, so these should stop using eval. + { "PlayerSettings.SetScriptingBackend", "set_player_settings" }, + { "PlayerSettings.GetScriptingBackend", "get_player_settings" }, + // Known gaps from the WizardDuelVR evidence: no command yet (feeds AUTHAPI-17). + // NOTE: save_all is NOT a cover for AssetDatabase.SaveAssets — it saves open scenes + // (EditorSceneManager.SaveOpenScenes + AssetDatabase.Refresh) and never persists dirty + // non-scene assets; steering agents off that eval to save_all would silently drop those + // writes. Mapped to a proposed save_assets command so the report surfaces it as a gap. + { "AssetDatabase.SaveAssets", "save_assets" }, + { "AssetDatabase.Refresh", "refresh_assets" }, + }; + } + + /// + /// Builds an from recorded eval telemetry, cross-referencing the API + /// fingerprints against the set of available command names. + /// + static class EvalUsageAggregator + { + /// Default cap on the suggested-gaps (topUncovered) list. + public const int DefaultTopUncoveredLimit = 20; + + /// Default cap on the ranked list. + public const int DefaultFingerprintLimit = 50; + + /// + /// Aggregate into a report. is + /// the set of command names in the live catalog; defaults to + /// . caps the + /// suggested-gaps list and caps the ranked fingerprint + /// list ( makes any truncation visible; + /// coverage is computed from the FULL ranking, so the fingerprint cap never skews it). + /// Accepted range for both limits: 0 or greater — negative values fall back to the defaults + /// (0 legitimately empties the list). + /// + public static EvalUsageReport Build( + IReadOnlyList records, + ISet availableCommands, + IReadOnlyDictionary coverageMap = null, + int topUncoveredLimit = DefaultTopUncoveredLimit, + int fingerprintLimit = DefaultFingerprintLimit) + { + records = records ?? new List(); + availableCommands = availableCommands ?? new HashSet(); + coverageMap = coverageMap ?? EvalCoverageMap.Default; + if (topUncoveredLimit < 0) + topUncoveredLimit = DefaultTopUncoveredLimit; + if (fingerprintLimit < 0) + fingerprintLimit = DefaultFingerprintLimit; + + var report = new EvalUsageReport { TotalCount = records.Count }; + + var counts = new Dictionary(); + foreach (var record in records) + { + if (record.Success) + report.SuccessCount++; + else + report.ErrorCount++; + + if (record.Classification == EvalClassification.SingleExpression) + report.SingleExpressionCount++; + else + report.StatementsCount++; + + if (record.Fingerprints == null) + continue; + foreach (var fingerprint in record.Fingerprints) + { + if (string.IsNullOrEmpty(fingerprint)) + continue; + counts.TryGetValue(fingerprint, out var current); + counts[fingerprint] = current + 1; + } + } + + if (report.TotalCount > 0) + { + report.ErrorRate = (double)report.ErrorCount / report.TotalCount; + report.OneLinerPercentage = 100.0 * report.SingleExpressionCount / report.TotalCount; + } + + // Deterministic ranking: count desc, then member name asc as a tiebreak. + var ranked = counts + .Select(kv => new FingerprintCount { Member = kv.Key, Count = kv.Value }) + .OrderByDescending(f => f.Count) + .ThenBy(f => f.Member, StringComparer.Ordinal) + .ToList(); + + // Cap the reported ranking (an accumulated log can hold thousands of distinct + // fingerprints); DistinctFingerprints preserves the uncapped total so truncation shows. + report.DistinctFingerprints = ranked.Count; + report.Fingerprints = ranked.Count > fingerprintLimit ? ranked.Take(fingerprintLimit).ToList() : ranked; + + // Coverage cross-references the FULL ranking, so a tight fingerprint cap cannot hide a + // covered pattern or demote an uncovered one; topUncovered has its own cap. + report.CoverageSuggestions = BuildCoverage(ranked, availableCommands, coverageMap, topUncoveredLimit); + return report; + } + + private static EvalCoverageSuggestions BuildCoverage( + List ranked, + ISet availableCommands, + IReadOnlyDictionary coverageMap, + int topUncoveredLimit) + { + var suggestions = new EvalCoverageSuggestions(); + + foreach (var entry in ranked) + { + coverageMap.TryGetValue(entry.Member, out var mappedCommand); + var covered = mappedCommand != null && availableCommands.Contains(mappedCommand); + + if (covered) + { + suggestions.Covered.Add(new CoverageHit + { + Member = entry.Member, + Count = entry.Count, + Command = mappedCommand + }); + } + else + { + suggestions.TopUncovered.Add(new CoverageGap + { + Member = entry.Member, + Count = entry.Count, + // A mapped-but-absent command is a concrete proposal; no mapping leaves it null. + SuggestedCommand = mappedCommand + }); + } + } + + // Negative limits were normalised to the default in Build, so a plain cap suffices. + if (suggestions.TopUncovered.Count > topUncoveredLimit) + suggestions.TopUncovered = suggestions.TopUncovered.Take(topUncoveredLimit).ToList(); + + return suggestions; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Telemetry/EvalUsageReport.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Telemetry/EvalUsageReport.cs.meta new file mode 100644 index 0000000..5a38353 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Telemetry/EvalUsageReport.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ffdbe00cca0b4defb784b5c92af3bdf2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Telemetry/EvalUsageTelemetry.cs b/AIClient/Packages/com.unity.pipeline/Runtime/Telemetry/EvalUsageTelemetry.cs new file mode 100644 index 0000000..a382f2d --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Telemetry/EvalUsageTelemetry.cs @@ -0,0 +1,481 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using Newtonsoft.Json; +using UnityEngine; + +#if UNITY_EDITOR +using System.Threading.Tasks; +#endif + +namespace Unity.Pipeline.Telemetry +{ + /// + /// One appended line of eval-usage telemetry. Serialized as a single compact JSON object per line + /// (JSONL). The raw is omitted unless the local + /// opt-in is set, so by default only shape/fingerprint data is persisted (AUTHAPI-29). + /// + [Serializable] + class EvalUsageRecord + { + [JsonProperty("time")] + public string Time { get; set; } + + /// The command that ran the source: "eval" or "eval_file". + [JsonProperty("command")] + public string Command { get; set; } + + [JsonProperty("success")] + public bool Success { get; set; } + + /// Short error category on failure (e.g. "Compilation Failed"); omitted on success. + [JsonProperty("error", NullValueHandling = NullValueHandling.Ignore)] + public string Error { get; set; } + + /// Character length of the eval body. + [JsonProperty("payloadLength")] + public int PayloadLength { get; set; } + + /// Newline-delimited line count of the eval body. + [JsonProperty("lineCount")] + public int LineCount { get; set; } + + [JsonProperty("executionTimeMs")] + public long ExecutionTimeMs { get; set; } + + /// "single-expression" | "statements" — see . + [JsonProperty("classification")] + public string Classification { get; set; } + + /// Top-level API member-access paths extracted from the syntax tree. + [JsonProperty("fingerprints")] + public List Fingerprints { get; set; } = new List(); + + /// Raw eval source. Present ONLY when the explicit opt-in is set; omitted otherwise. + [JsonProperty("source", NullValueHandling = NullValueHandling.Ignore)] + public string Source { get; set; } + } + + /// + /// Local-first, privacy-first instrumentation of eval/eval_file (AUTHAPI-29). Per + /// invocation it appends one to + /// <project>/Library/Pipeline/eval-usage.jsonl. There is NO off-machine transmission: + /// disabling stops even local recording, which satisfies "analytics opt-out + /// fully disables any off-machine transmission" trivially — nothing ever leaves the machine. + /// + /// RECORDING IS EDITOR-ONLY. Eval telemetry exists to steer the editor command-surface migration, + /// so / compile to no-ops outside the editor + /// (#if UNITY_EDITOR). This also keeps player builds from writing a "Library/Pipeline" + /// folder next to Application.dataPath (the APK path on Android, inside the .app bundle on + /// macOS) — a location players may not even be able to write. Release players cannot eval at all + /// (the compiler stub blocks it); development players can, but are deliberately not instrumented. + /// The class itself stays compiled in players so shared code links, and the read side returns + /// empty results there. + /// + /// The production hook is fire-and-forget: snapshots the eval + /// outcome plus the current configuration on the calling (main) thread and runs the Roslyn parse, + /// fingerprint extraction, and file append on a thread-pool task, so recording adds no latency to + /// the eval response. + /// + /// Modelled on PipelineTransactionLog: a lock serialises the append (evals can overlap on + /// the /api/progress path) and the reader takes the same lock, all I/O is best-effort and swallows + /// errors so telemetry never breaks a command, and a directory-parameterised seam makes it + /// hermetically testable. Unlike the debug transaction log, the JSONL is meant to ACCUMULATE + /// across sessions so the ranked report has data, so it is bounded by a byte-size cap with + /// rotation rather than reset per session; merges the rotated ".old" + /// file back in, bounding readable history to roughly 2× . + /// + static class EvalUsageTelemetry + { + /// + /// Byte-size cap for the active JSONL before it rotates to the ".old" file (default 5 MB). + /// A settable field (not a const) so tests can force the size-cap rotation path cheaply. + /// + public static long MaxFileBytes = 5L * 1024 * 1024; + + /// + /// Upper bound, in characters, on the raw source persisted per record when the + /// opt-in is set (64 K). Longer bodies are cut at this bound and + /// is appended so truncation is explicit; + /// still reports the full original length. + /// + public const int MaxStoredSourceChars = 64 * 1024; + + /// Marker appended to a stored that was truncated. + public const string SourceTruncationMarker = "…[truncated]"; + + private const string FileName = "eval-usage.jsonl"; + private const string OldFileName = "eval-usage.old.jsonl"; + + /// Master switch. When false, is a no-op (no local write, no transmission). + public static bool Enabled = true; + + /// Opt-in: persist the raw eval source in each record. Off by default (privacy-first). + public static bool StoreSource = false; + + /// + /// Overrides the storage directory. Null uses <project>/Library/Pipeline. Tests set + /// this to a temp directory so they never touch the real project telemetry file. + /// + public static string OverrideDirectory; + + private static readonly object s_AppendGate = new object(); + + /// + /// Number of background records queued by and not yet + /// flushed. Explicitly initialised: in player builds the recording path compiles away and the + /// field is only ever read (by ), which would otherwise + /// raise CS0649. + /// + private static int s_PendingRecords = 0; + +#if UNITY_EDITOR + /// Serialises background writes in submission order (see ). + /// Editor-only like the recording path itself: Task is not even imported in player builds. + private static readonly object s_WriteChainGate = new object(); + private static Task s_WriteChain = Task.CompletedTask; +#endif + + /// Main-thread-resolved cache of the default (dataPath-derived) storage directory. + private static string s_CachedDefaultDirectory; + + /// + /// Record one eval invocation synchronously on the calling thread. Editor-only: compiles to a + /// no-op in player builds (see class doc). Best-effort: any failure (parse, I/O) is swallowed + /// with a warning so instrumentation can never break the eval it is measuring. The production + /// eval hook uses so the eval response is never delayed; this + /// synchronous seam remains for tests and direct callers that need the write completed on + /// return. + /// + public static void Record(string command, string code, bool success, string error, long executionTimeMs) + { +#if UNITY_EDITOR + if (!Enabled) + return; + + TryWriteRecord(ResolveDirectory(), DateTime.UtcNow, command, code, success, error, executionTimeMs, StoreSource); +#endif + } + + /// + /// Record one eval invocation without blocking the calling thread. Editor-only: compiles to a + /// no-op in player builds (see class doc). Everything the write needs — the eval primitives + /// plus a snapshot of the current / configuration + /// and the resolved directory (which touches Unity API and must be read on the main thread) — + /// is captured here on the calling thread; the Roslyn parse, fingerprint extraction, and + /// lock-serialised append then run on a thread-pool task, so telemetry adds zero latency to + /// the eval response. Failures on the background task are swallowed with a warning + /// (Debug.LogWarning is thread-safe). A domain reload can at worst abandon one in-flight + /// record; its partial trailing line is skipped by . + /// + public static void RecordInBackground(string command, string code, bool success, string error, long executionTimeMs) + { +#if UNITY_EDITOR + if (!Enabled) + return; + + // Snapshot on the calling thread: config statics can be flipped live by the inspector, + // and ResolveDirectory may touch Application.dataPath (main-thread-only Unity API). + var directory = ResolveDirectory(); + var storeSource = StoreSource; + var timeUtc = DateTime.UtcNow; + + Interlocked.Increment(ref s_PendingRecords); + // Chain onto the previous write instead of racing independent Task.Runs: back-to-back + // evals (batch, tight agent loops) must land in submission order — ReadRecords + // documents the log as chronological — and the chain also means at most one telemetry + // write competes with the pool at a time. + lock (s_WriteChainGate) + { + s_WriteChain = s_WriteChain.ContinueWith(_ => + { + try + { + TryWriteRecord(directory, timeUtc, command, code, success, error, executionTimeMs, storeSource); + } + finally + { + Interlocked.Decrement(ref s_PendingRecords); + } + }, System.Threading.CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.Default); + } +#endif + } + + /// + /// Block until every background record queued by has been + /// flushed, or elapses (returns false on timeout). Recording is + /// fire-and-forget, so tests (and teardown paths that delete the storage directory) drain the + /// queue with this before asserting on / removing the JSONL. + /// + public static bool WaitForPendingRecords(int timeoutMs = 5000) + { + var stopwatch = System.Diagnostics.Stopwatch.StartNew(); + while (Volatile.Read(ref s_PendingRecords) > 0) + { + if (stopwatch.ElapsedMilliseconds >= timeoutMs) + return false; + Thread.Sleep(1); + } + return true; + } + +#if UNITY_EDITOR + /// + /// , with the shared best-effort guard: telemetry must never affect + /// eval behavior (or crash a background task), so any failure (parse, I/O) is swallowed with + /// a warning instead of propagating. Shared by 's synchronous call and + /// 's queued continuation. + /// + private static void TryWriteRecord( + string directory, + DateTime timeUtc, + string command, + string code, + bool success, + string error, + long executionTimeMs, + bool storeSource) + { + try + { + WriteRecord(directory, timeUtc, command, code, success, error, executionTimeMs, storeSource); + } + catch (Exception ex) + { + Debug.LogWarning($"Pipeline eval telemetry write failed: {ex.Message}"); + } + } + + /// + /// Build and append one record from an already-captured snapshot. Runs on whichever thread the + /// caller chose; deliberately touches no Unity API (the fingerprinter is pure Roslyn and the + /// directory was resolved by the caller), so it is safe on a thread-pool task. + /// + private static void WriteRecord( + string directory, + DateTime timeUtc, + string command, + string code, + bool success, + string error, + long executionTimeMs, + bool storeSource) + { + var analysis = EvalUsageFingerprinter.Analyze(code); + var record = new EvalUsageRecord + { + Time = timeUtc.ToString("o"), + Command = command, + Success = success, + Error = success ? null : error, + PayloadLength = code?.Length ?? 0, + LineCount = CountLines(code), + ExecutionTimeMs = executionTimeMs, + Classification = analysis.Classification, + Fingerprints = new List(analysis.Fingerprints), + Source = storeSource ? BoundStoredSource(code) : null + }; + + Append(directory, record); + } + + /// + /// Bound the opt-in raw source at , appending + /// when cut, so one giant eval_file body can't balloon + /// a single record (the JSONL size cap only rotates between appends). + /// + private static string BoundStoredSource(string code) + { + if (string.IsNullOrEmpty(code) || code.Length <= MaxStoredSourceChars) + return code; + return code.Substring(0, MaxStoredSourceChars) + SourceTruncationMarker; + } +#endif + + /// + /// Append one record to the JSONL in an explicit directory. Testable seam behind + /// . Rotates first if the active file has reached the size cap, so each + /// file stays bounded to roughly plus one record. + /// + public static void Append(string directory, EvalUsageRecord record) + { + lock (s_AppendGate) + { + var root = Path.GetFullPath(directory); + Directory.CreateDirectory(root); + var path = DataFilePath(root, FileName); + + if (File.Exists(path) && new FileInfo(path).Length >= MaxFileBytes) + Rotate(root); + + File.AppendAllText(path, JsonConvert.SerializeObject(record, Formatting.None) + "\n"); + } + } + + /// + /// Canonical absolute path of one of this class's fixed data files inside the telemetry + /// directory, with containment re-checked after normalization. The directory is the only + /// dynamic path segment (a local editor setting or the test override — never protocol + /// input) and the file names are compile-time constants, so this is an explicit invariant + /// at the IO boundary: any input that would resolve outside its canonical directory is + /// rejected instead of opened. + /// + private static string DataFilePath(string directory, string fileName) + { + if (!TryResolveDataFilePath(directory, fileName, out var full)) + throw new InvalidOperationException( + $"Telemetry data file path '{full}' escapes its directory '{directory}'."); + return full; + } + + /// + /// The single canonicalize-and-contain implementation behind both the throwing + /// (writer sites) and the silently-skipping reader — one place + /// to fix normalization, per review. + /// + private static bool TryResolveDataFilePath(string directory, string fileName, out string fullPath) + { + var root = Path.GetFullPath(directory); + fullPath = Path.GetFullPath(Path.Combine(root, fileName)); + var rootWithSeparator = root.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal) + ? root + : root + Path.DirectorySeparatorChar; + return fullPath.StartsWith(rootWithSeparator, StringComparison.Ordinal); + } + + /// + /// Move the active JSONL to the ".old" backup, replacing any prior backup, so the active file + /// starts fresh. No-op when there is no active file. Exposed as the testable rotation seam. + /// Takes the append gate so a rotation can never interleave with a concurrent append or read + /// (the lock is re-entrant, so the rotate-inside- path is unaffected). + /// + public static void Rotate(string directory) + { + lock (s_AppendGate) + { + var root = Path.GetFullPath(directory); + Directory.CreateDirectory(root); + var path = DataFilePath(root, FileName); + var oldPath = DataFilePath(root, OldFileName); + RotatingFileBackup.RotateToBackup(path, oldPath); + } + } + + /// + /// Read back every record from : the rotated + /// eval-usage.old.jsonl first (when present), then the active file, so the report sees + /// the full retained history — bounded to roughly 2× — in + /// chronological order. Malformed lines are skipped so a partial trailing write can never + /// break the report. + /// + /// Concurrency: takes the same gate as / (this class + /// is the only writer, and appends now happen on background tasks), and additionally opens + /// each file tolerantly — FileShare.ReadWrite, with I/O errors caught — so a reader + /// racing an out-of-process writer, or a file swapped away between the existence check and the + /// open (the rotation TOCTOU), degrades to "return what parsed" instead of throwing. + /// + public static IReadOnlyList ReadRecords(string directory) + { + var records = new List(); + lock (s_AppendGate) + { + ReadFileInto(directory, OldFileName, records); + ReadFileInto(directory, FileName, records); + } + return records; + } + + /// + /// Best-effort JSONL parse of one fixed-name data file into ; see + /// . The canonicalize-and-contain check is repeated inline here (not + /// only in ) so the validated path and the open are in the same + /// method — the same invariant, kept visible at the IO site. + /// + private static void ReadFileInto(string directory, string fileName, List records) + { + // Same canonicalize-and-contain invariant as the writer sites, via the one shared + // implementation; a reader skips silently where a writer throws. + if (!TryResolveDataFilePath(directory, fileName, out var path)) + return; // outside the telemetry directory — unreachable for the constant file names + + try + { + using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete)) + using (var reader = new StreamReader(stream)) + { + string line; + while ((line = reader.ReadLine()) != null) + { + if (string.IsNullOrWhiteSpace(line)) + continue; + try + { + var record = JsonConvert.DeserializeObject(line); + if (record != null) + records.Add(record); + } + catch (JsonException) + { + // Skip a malformed / partially written line; keep the rest of the log usable. + } + } + } + } + catch (Exception ex) when (ex is IOException || ex is UnauthorizedAccessException) + { + // Covers FileNotFound/DirectoryNotFound (nothing recorded yet, or the file was rotated + // away mid-read), sharing violations from external processes, and ACL/AV denials + // (UnauthorizedAccessException does NOT derive from IOException): telemetry read-back + // is best-effort, so return whatever parsed instead of throwing. + } + } + + /// + /// Resolve the storage directory: the override if set, else <project>/Library/Pipeline. + /// The default derives from Application.dataPath (a main-thread Unity API), so the + /// first non-overridden call must happen on the main thread — the editor startup path primes + /// it — after which the cached value is safe from any thread (e.g. the off-main-thread + /// report_evals command). + /// + public static string ResolveDirectory() + { + if (!string.IsNullOrEmpty(OverrideDirectory)) + return OverrideDirectory; + + if (s_CachedDefaultDirectory == null) + { +#if UNITY_EDITOR + var projectRoot = Path.GetDirectoryName(Application.dataPath); + s_CachedDefaultDirectory = Path.Combine(projectRoot, "Library", "Pipeline"); +#else + // Player builds: recording is compiled out and nothing is ever written, but + // report_evals (MainThreadRequired=false) can reach this off the main thread + // before any main-thread code primed the cache — and Application.dataPath is + // main-thread-only. A stable process-temp location keeps the read path safe and + // empty, so the command returns the documented zeroed report instead of throwing. + s_CachedDefaultDirectory = Path.Combine(Path.GetTempPath(), "UnityPipelineEvalUsage"); +#endif + } + return s_CachedDefaultDirectory; + } + + private static int CountLines(string code) + { + if (string.IsNullOrEmpty(code)) + return 0; + + var lines = 1; + for (var i = 0; i < code.Length; i++) + { + var c = code[i]; + if (c == '\n') + lines++; + else if (c == '\r' && (i + 1 >= code.Length || code[i + 1] != '\n')) + lines++; // lone \r (classic Mac) is a line break; \r\n already counts via \n + } + return lines; + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Telemetry/EvalUsageTelemetry.cs.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Telemetry/EvalUsageTelemetry.cs.meta new file mode 100644 index 0000000..35614d6 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Telemetry/EvalUsageTelemetry.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ae2e135fbc1d424592da87027c687d94 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Unity.Pipeline.asmdef b/AIClient/Packages/com.unity.pipeline/Runtime/Unity.Pipeline.asmdef new file mode 100644 index 0000000..7727b8d --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Unity.Pipeline.asmdef @@ -0,0 +1,33 @@ +{ + "name": "Unity.Pipeline", + "rootNamespace": "Unity.Pipeline", + "references": [ + "Unity.InputSystem", + "Unity.Pipeline.Attributes", + "Unity.Pipeline.IlInterpreter" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": true, + "precompiledReferences": [ + "UnityPipeline.Microsoft.CodeAnalysis.dll", + "UnityPipeline.Microsoft.CodeAnalysis.CSharp.dll", + "UnityPipeline.System.Collections.Immutable.dll", + "UnityPipeline.System.Runtime.CompilerServices.Unsafe.dll", + "UnityPipeline.System.Reflection.Metadata.dll", + "Newtonsoft.Json.dll" + ], + "autoReferenced": true, + "defineConstraints": [ + "UNITY_EDITOR || DEVELOPMENT_BUILD || ENABLE_RUNTIME_PIPELINE" + ], + "versionDefines": [ + { + "name": "com.unity.modules.unitywebrequest", + "expression": "1.0.0", + "define": "UNITY_2022_3_OR_NEWER" + } + ], + "noEngineReferences": false +} diff --git a/AIClient/Packages/com.unity.pipeline/Runtime/Unity.Pipeline.asmdef.meta b/AIClient/Packages/com.unity.pipeline/Runtime/Unity.Pipeline.asmdef.meta new file mode 100644 index 0000000..023d6c2 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Runtime/Unity.Pipeline.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 71e9815631ba2574b92564e93b8efc9c +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload.meta b/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload.meta new file mode 100644 index 0000000..370c8e5 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7a0ab883fda51549426c60701bd05576 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_InPlace.meta b/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_InPlace.meta new file mode 100644 index 0000000..0846c6d --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_InPlace.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4f40406811f5efe4eb95440aebf17388 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_InPlace/CodeReload_InPlace.unity b/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_InPlace/CodeReload_InPlace.unity new file mode 100644 index 0000000..6fe55e9 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_InPlace/CodeReload_InPlace.unity @@ -0,0 +1,447 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 10 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_BakeOnSceneLoad: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 2 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 1 + m_PVRFilteringGaussRadiusAO: 1 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &701989028 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 701989030} + - component: {fileID: 701989029} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &701989029 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 701989028} + m_Enabled: 1 + serializedVersion: 13 + m_Type: 1 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize2D: {x: 0.5, y: 0.5} + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ForceVisible: 0 + m_ShapeRadius: 0.025 + m_ShadowAngle: 0 + m_LightUnit: 1 + m_LuxAtDistance: 1 + m_EnableSpotReflector: 1 +--- !u!4 &701989030 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 701989028} + serializedVersion: 2 + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &890368703 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 890368707} + - component: {fileID: 890368706} + - component: {fileID: 890368705} + - component: {fileID: 890368704} + - component: {fileID: 890368708} + m_Layer: 0 + m_Name: Player + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!65 &890368704 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 890368703} + m_Material: {fileID: 0} + m_IncludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_ExcludeLayers: + serializedVersion: 2 + m_Bits: 0 + m_LayerOverridePriority: 0 + m_IsTrigger: 0 + m_ProvidesContacts: 0 + m_Enabled: 1 + serializedVersion: 3 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!23 &890368705 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 890368703} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_StaticShadowCaster: 0 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RayTraceProcedural: 0 + m_RayTracingAccelStructBuildFlagsOverride: 0 + m_RayTracingAccelStructBuildFlags: 1 + m_SmallMeshCulling: 1 + m_ForceMeshLod: -1 + m_MeshLodSelectionBias: 0 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_GlobalIlluminationMeshLod: 0 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 + m_MaskInteraction: 0 + m_AdditionalVertexStreams: {fileID: 0} +--- !u!33 &890368706 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 890368703} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &890368707 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 890368703} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0.5, y: 0.35, z: 0.5} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &890368708 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 890368703} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f2e2dbbd2e928074d83ba49a57cb9cfa, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.Pipeline.Samples::Unity.Pipeline.Samples.CodeReload.InPlaceCodeReloadExample + rotationSpeed: 90 + enableRotation: 1 + rotationAxis: {x: 0, y: 1, z: 0} + moveSpeed: 2 + enableMovement: 1 +--- !u!1 &1185268903 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1185268906} + - component: {fileID: 1185268905} + - component: {fileID: 1185268904} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &1185268904 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1185268903} + m_Enabled: 1 +--- !u!20 &1185268905 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1185268903} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &1185268906 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1185268903} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 1185268906} + - {fileID: 701989030} + - {fileID: 890368707} diff --git a/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_InPlace/CodeReload_InPlace.unity.meta b/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_InPlace/CodeReload_InPlace.unity.meta new file mode 100644 index 0000000..0446187 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_InPlace/CodeReload_InPlace.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1a4fb3f52f24e174d9e515c8b77ceb71 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_InPlace/InPlaceCodeReloadExample.cs b/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_InPlace/InPlaceCodeReloadExample.cs new file mode 100644 index 0000000..65da083 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_InPlace/InPlaceCodeReloadExample.cs @@ -0,0 +1,83 @@ +using UnityEngine; +using Unity.Pipeline.CodeReload; + +namespace Unity.Pipeline.Samples.CodeReload +{ + /// + /// Example demonstrating in-place code reload editing workflow. + /// + /// Usage: + /// 1. Add this component to a GameObject in the scene + /// 2. Play the scene - you'll see the object rotating + /// 3. Modify the Update() method below (try changing Vector3.up to Vector3.forward) + /// 4. Run: reload_file Assets/Samples/CodeReload_InPlace/InPlaceCodeReloadExample.cs + /// 5. See the changes take effect immediately without stopping play mode! + /// + /// Requirements: + /// - Only use PUBLIC fields, properties, and methods + /// - Private/internal members will cause validation errors + /// + public class InPlaceCodeReloadExample : MonoBehaviour + { + [Header("Code Reload Configuration")] + public float rotationSpeed = 90f; + public bool enableRotation = true; + public Vector3 rotationAxis = Vector3.up; + + [Header("Movement Configuration")] + public float moveSpeed = 2f; + public bool enableMovement = false; + + [CodeReload] + void Update() + { + // Edit this body live, then run: reload_file + // Try changing rotationAxis (e.g. Vector3.up -> Vector3.forward) or the speed. + if (enableRotation) + { + transform.Rotate(rotationAxis, rotationSpeed * Time.deltaTime); + } + + if (enableMovement) + { + var movement = Mathf.Sin(Time.time) * moveSpeed; + transform.position = new Vector3(movement, transform.position.y, transform.position.z); + } + } + + [CodeReload] + public void ResetTransform() + { + // Another method you can code reload + transform.position = Vector3.zero; + transform.rotation = Quaternion.identity; + Debug.Log("Transform reset via code reload!"); + } + + // Note: value-returning methods are not yet supported by in-place reload (void methods only), + // so this one is a normal method. + public float CalculateDistance(Vector3 targetPosition) + { + return Vector3.Distance(transform.position, targetPosition); + } + + void Awake() + { + // Run the sample in a 640x480 window instead of fullscreen. + Screen.SetResolution(640, 480, FullScreenMode.Windowed); + } + + // Regular methods (not reloadable) - these work normally + void Start() + { + Debug.Log($"InPlaceCodeReloadExample started. Try code reloading the Update method!"); + Debug.Log($"Command: reload_file {GetType().Name}.cs"); + } + + public void TriggerResetFromUI() + { + // This calls the reloadable method + ResetTransform(); + } + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_InPlace/InPlaceCodeReloadExample.cs.meta b/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_InPlace/InPlaceCodeReloadExample.cs.meta new file mode 100644 index 0000000..8db378d --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_InPlace/InPlaceCodeReloadExample.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f2e2dbbd2e928074d83ba49a57cb9cfa \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_Minics/PongScene.unity b/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_Minics/PongScene.unity new file mode 100644 index 0000000..a5a7436 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_Minics/PongScene.unity @@ -0,0 +1,437 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 10 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 13 + m_BakeOnSceneLoad: 0 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 2 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 2 + m_PVRDenoiserTypeIndirect: 2 + m_PVRDenoiserTypeAO: 2 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 1 + m_PVRFilteringGaussRadiusAO: 1 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 20201, guid: 0000000000000000f000000000000000, type: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 3 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + buildHeightMesh: 0 + maxJobWorkers: 0 + preserveTilesOutsideBounds: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &201913770 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 201913773} + - component: {fileID: 201913772} + - component: {fileID: 201913771} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &201913771 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 201913770} + m_Enabled: 1 +--- !u!20 &201913772 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 201913770} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_Iso: 200 + m_ShutterSpeed: 0.005 + m_Aperture: 16 + m_FocusDistance: 10 + m_FocalLength: 50 + m_BladeCount: 5 + m_Curvature: {x: 2, y: 11} + m_BarrelClipping: 0.25 + m_Anamorphism: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &201913773 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 201913770} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &453203916 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 453203918} + - component: {fileID: 453203917} + m_Layer: 0 + m_Name: Pong + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &453203917 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 453203916} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8ba7fa42014981348997afa11a492f9c, type: 3} + m_Name: + m_EditorClassIdentifier: Assembly-CSharp::PongScript + leftPaddle: {fileID: 0} + rightPaddle: {fileID: 0} + ball: {fileID: 0} + leftScoreGO: {fileID: 0} + rightScoreGO: {fileID: 0} + arenaGO: {fileID: 0} + arena: {fileID: 0} + leftScoreText: {fileID: 0} + rightScoreText: {fileID: 0} + mat: {fileID: 0} + ballRenderer: {fileID: 0} + leftPaddleAngle: 180 + rightPaddleAngle: 0 + ballVelocity: {x: 0, y: 0, z: 0} + ballIsLeftPaddleColor: 0 + leftLives: 3 + rightLives: 3 + gameOver: 0 + ballSpeed: 5 + circleRadius: 6 + paddleAngularSpeed: 180 + gravity: 3 + updateTicks: 0 + marker: none +--- !u!4 &453203918 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 453203916} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1639109660 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1639109662} + - component: {fileID: 1639109661} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &1639109661 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1639109660} + m_Enabled: 1 + serializedVersion: 12 + m_Type: 1 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize2D: {x: 0.5, y: 0.5} + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 4 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_UseViewFrustumForShadowCasterCull: 1 + m_ForceVisible: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 + m_LightUnit: 1 + m_LuxAtDistance: 1 + m_EnableSpotReflector: 1 +--- !u!4 &1639109662 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1639109660} + serializedVersion: 2 + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &1769366718 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1769366720} + - component: {fileID: 1769366719} + m_Layer: 0 + m_Name: PipelineManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1769366719 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1769366718} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: dd4ab1c9091e0194196b5f5d51cb932f, type: 3} + m_Name: + m_EditorClassIdentifier: Unity.Pipeline::Unity.Pipeline.RuntimePipelineManager + enableInBuilds: 0 + port: 0 + requestTimeoutMs: 30000 + enableAuditLogging: 1 + autoStart: 1 + maxWorkItemsPerFrame: 10 + m_AllowedReloadRoots: [] +--- !u!4 &1769366720 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1769366718} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1660057539 &9223372036854775807 +SceneRoots: + m_ObjectHideFlags: 0 + m_Roots: + - {fileID: 201913773} + - {fileID: 1639109662} + - {fileID: 453203918} + - {fileID: 1769366720} diff --git a/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_Minics/PongScene.unity.meta b/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_Minics/PongScene.unity.meta new file mode 100644 index 0000000..88e54a5 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_Minics/PongScene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: aade730046d453349bd366dcebbce674 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_Minics/README.md b/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_Minics/README.md new file mode 100644 index 0000000..6f14b41 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_Minics/README.md @@ -0,0 +1,42 @@ +# Code Reload - Minics + +Demonstrates code reloading with the minics vm. This allows code reloading cs +scripts on all platforms (even on il2cpp players) with the constraint the the +script must only contain a subset of csharp. + +## What's in this sample + +| File | Purpose | +|------|---------| +| `pong.cs` | `PongScript`, a self-playing Pong game that can be reloaded. | +| `SampleScene.unity` | Scene with a GameObject carrying `PongScript`. | + +`PongScript` is a self-playing arena Pong: two paddles orbit a circle and rally a +ball that switches colour on each hit. + +## Try it + +1. Import this sample and add `PongScene` to the built scene list. +2. Enable **developement build** and **autoconnect profiler** in the build settings (minics uses the profiler connection to reload the scripts.) +2. You may also want to enable run in background in the player settings if you are building for web. +3. Build and run the player. The paddles start rallying the ball automatically, and the profiler begins collecting data. +3. Make a change to pong.cs and push it with `unity command reload_file_player_interpreter "Assets/Samples/Unity Pipeline/0.2.0-exp.2/Code Reload Examples/CodeReload_Minics/pong.cs"` to see the reload live. (For automatic re-push on every save, use the Code Reload Interpreter Watch section of the Pipeline Settings inspector.) + +## How the code reload works + +- **`[CodeReload]` on the class** opts every eligible method (`Start`, `Update`, + `PlacePaddle`, `OnDisable`, …) into in-place reload. Editing any of them takes effect on the next `reload_file`. +- **`[OnCodeReload]` on `OnReloaded()`** runs once after each reload, on every + live instance. Here it tears down and rebuilds the scene (`OnDisable()` + `Start()`) + so edits to setup code apply immediately. +- **Verification markers** `updateTicks` and `marker` are public fields you can read + back over eval to confirm the freshly reloaded `Update` body is actually running. + +Because in-place reloaded bodies may only touch **public** members of the target type, +every field and helper on `PongScript` is public. + +## Minics + +Minics is a subset of all C# features. This means that not all scripts will be able to +be reloaded. Consult the package documentation for more information on which +features are supported. diff --git a/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_Minics/pong.cs b/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_Minics/pong.cs new file mode 100644 index 0000000..dde364a --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_Minics/pong.cs @@ -0,0 +1,248 @@ +using UnityEngine; +using Unity.Pipeline.CodeReload; + +// Pong sample for com.unity.pipeline in-place code reload: +// - Self-playing AI instead of the Input System (project has no com.unity.inputsystem). +// - Material created in code (project has no Resources/DefaultMaterial; built-in RP). +// - All members public: in-place [CodeReload] method bodies may only touch public members. +// - [CodeReload] on each editable method (Start/Update/PlacePaddle/OnDisable), so editing a helper +// like PlacePaddle takes effect too. `reload_file Assets/pong.cs`. +public class PongScript : MonoBehaviour +{ + public GameObject leftPaddle, rightPaddle, ball; + public GameObject leftScoreGO, rightScoreGO, arenaGO; + public LineRenderer arena; + public TextMesh leftScoreText, rightScoreText; + public Material mat; + public Renderer ballRenderer; + + public float leftPaddleAngle = 180f; + public float rightPaddleAngle = 0f; + public Vector3 ballVelocity; + public bool ballIsLeftPaddleColor = false; + public int leftLives = 3; + public int rightLives = 3; + public bool gameOver = false; + + public float ballSpeed = 5f; + public float circleRadius = 2f; + public float paddleAngularSpeed = 180f; + public float gravity = 3f; + + // Code-reload verification markers (read back via eval to confirm the live body ran). + public int updateTicks = 0; + public string marker = "none"; + private Color leftColor ; + private Color rightColor; + + [OnCodeReload] + public void OnReloaded() + { + Debug.Log($"Pong CodeReloaded"); + OnDisable(); + Start(); + } + + [CodeReload] + public void Start() + { + leftColor = new Color(0.678f, 1f, 0.184f); // green-yellow (Color.greenYellow needs 6000.2+) + rightColor = Color.magenta; + + mat = new Material(Shader.Find("Sprites/Default")); + Camera cam = Camera.main; + cam.orthographic = true; + cam.orthographicSize = 12.5f; + cam.clearFlags = CameraClearFlags.SolidColor; + cam.backgroundColor = Color.grey; + cam.transform.position = new Vector3(0.0f, 0.0f, -10.0f); + + + leftScoreGO = new GameObject("LeftScore"); + leftScoreGO.transform.position = new Vector3(-6f, 6f, 0f); + leftScoreText = leftScoreGO.AddComponent(); + leftScoreText.anchor = TextAnchor.MiddleCenter; + leftScoreText.alignment = TextAlignment.Center; + leftScoreText.text = "Cyan: " + leftLives.ToString(); + leftScoreText.characterSize = 0.5f; + leftScoreText.color = leftColor; + + rightScoreGO = new GameObject("RightScore"); + rightScoreGO.transform.position = new Vector3(6f, 6f, 0f); + rightScoreText = rightScoreGO.AddComponent(); + rightScoreText.anchor = TextAnchor.MiddleCenter; + rightScoreText.alignment = TextAlignment.Center; + rightScoreText.text = "Magenta: " + rightLives.ToString(); + rightScoreText.characterSize = 0.5f; + rightScoreText.color = rightColor; + + arenaGO = new GameObject("CircleIndicator"); + arenaGO.transform.position = new Vector3(0f, 0f, 0.5f); + arena = arenaGO.AddComponent(); + arena.useWorldSpace = false; + arena.loop = true; + arena.startWidth = 0.1f; + arena.endWidth = 0.1f; + arena.material = mat; + arena.material.color = new Color(0.15f, 0.15f, 0.15f, 1f); + arena.positionCount = 64; + int i = 0; + while (i < 64) + { + float a = i * Mathf.PI * 2f / 64f; + arena.SetPosition(i, new Vector3(Mathf.Cos(a) * circleRadius, Mathf.Sin(a) * circleRadius, 0f)); + i = i + 1; + } + + leftPaddle = GameObject.CreatePrimitive(PrimitiveType.Quad); + leftPaddle.transform.localScale = new Vector3(0.3f, 1.5f, 1f); + Renderer lr = leftPaddle.GetComponent(); + lr.material = mat; + lr.material.color = leftColor; + + rightPaddle = GameObject.CreatePrimitive(PrimitiveType.Quad); + rightPaddle.transform.localScale = new Vector3(0.3f, 1.5f, 1f); + Renderer rr = rightPaddle.GetComponent(); + rr.material = mat; + rr.material.color = rightColor; + + PlacePaddle(leftPaddle, leftPaddleAngle); + PlacePaddle(rightPaddle, rightPaddleAngle); + + ball = GameObject.CreatePrimitive(PrimitiveType.Sphere); + ball.transform.localScale = new Vector3(0.4f, 0.4f, 0.4f); + ballRenderer = ball.GetComponent(); + ballRenderer.material = mat; + ballRenderer.material.color = rightColor; + + ballVelocity = new Vector3(ballSpeed, ballSpeed * 0.5f, 0f); + } + + [CodeReload] + public void PlacePaddle(GameObject paddle, float angleDeg) + { + float rad = angleDeg * Mathf.Deg2Rad; + paddle.transform.localScale = new Vector3(.5f,2,1); + paddle.transform.position = new Vector3(Mathf.Cos(rad) * circleRadius, Mathf.Sin(rad) * circleRadius, 0f); + paddle.transform.rotation = Quaternion.Euler(0f, 0f, angleDeg); + } + + [CodeReload] + public void Update() + { + updateTicks++; + marker = "live"; + + if (gameOver) + { + this.OnDisable(); + gameOver = false; + this.Start(); + return; + } + + + float dt = Time.deltaTime; + + // Self-playing AI: each paddle tracks the ball while the ball wears its colour. + float ballAng = Mathf.Atan2(ball.transform.position.y, ball.transform.position.x) * Mathf.Rad2Deg; + if (ballIsLeftPaddleColor) + { + float diff = Mathf.DeltaAngle(leftPaddleAngle, ballAng); + if (diff > 5f) leftPaddleAngle += paddleAngularSpeed * dt; + if (diff < -5f) leftPaddleAngle -= paddleAngularSpeed * dt; + } + else + { + float diff = Mathf.DeltaAngle(rightPaddleAngle, ballAng); + if (diff > 5f) rightPaddleAngle += paddleAngularSpeed * dt; + if (diff < -5f) rightPaddleAngle -= paddleAngularSpeed * dt; + } + + PlacePaddle(leftPaddle, leftPaddleAngle); + PlacePaddle(rightPaddle, rightPaddleAngle); + + ballVelocity = ballVelocity + Vector3.down * gravity * dt * 1.2f; + ball.transform.position = ball.transform.position + ballVelocity * dt ; + Vector3 bPos = ball.transform.position; + float bDist = bPos.magnitude; + float bAng = Mathf.Atan2(bPos.y, bPos.x) * Mathf.Rad2Deg; + + if (bDist > circleRadius - 0.3f && bDist < circleRadius + 0.2f) + { + Vector3 normal = bPos.normalized; + if (Vector3.Dot(ballVelocity, normal) > 0f) + { + if (ballIsLeftPaddleColor) + { + float diff = Mathf.DeltaAngle(bAng, leftPaddleAngle); + if (diff > -12f && diff < 12f) + { + ballVelocity = Vector3.Reflect(ballVelocity, -normal); + ball.transform.position = ball.transform.position - normal * 0.1f; + ballIsLeftPaddleColor = false; + ballRenderer.material.color = rightColor; + } + } + else + { + float diff = Mathf.DeltaAngle(bAng, rightPaddleAngle); + if (diff > -12f && diff < 12f) + { + ballVelocity = Vector3.Reflect(ballVelocity, -normal); + ball.transform.position = ball.transform.position - normal * 0.1f; + ballIsLeftPaddleColor = true; + ballRenderer.material.color = leftColor; + } + } + } + } + + if (bDist > 8f) + { + if (ballIsLeftPaddleColor) + { + leftLives -= 1; + leftScoreText.text = "Cyan: " + leftLives.ToString(); + } + else + { + rightLives -= 1; + rightScoreText.text = "Magenta: " + rightLives.ToString(); + } + + if (leftLives <= 0 || rightLives <= 0) + { + gameOver = true; + } + else + { + ball.transform.position = new Vector3(0f, 0f, 0f); + ballVelocity = new Vector3(ballSpeed, ballSpeed * 0.5f, 0f); + ballIsLeftPaddleColor = rightLives < leftLives; + if (ballIsLeftPaddleColor) + { + ballRenderer.material.color = leftColor; + } + else + { + ballRenderer.material.color = rightColor; + } + } + } + } + + [CodeReload] + public void OnDisable() + { + if (leftPaddle) GameObject.Destroy(leftPaddle); + if (rightPaddle) GameObject.Destroy(rightPaddle); + if (ball) GameObject.Destroy(ball); + if (leftScoreGO) GameObject.Destroy(leftScoreGO); + if (rightScoreGO) GameObject.Destroy(rightScoreGO); + if (arenaGO) GameObject.Destroy(arenaGO); + Camera.main.orthographicSize = 5.0f; + Camera.main.clearFlags = CameraClearFlags.Skybox; + Camera.main.orthographic = false; + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_Minics/pong.cs.meta b/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_Minics/pong.cs.meta new file mode 100644 index 0000000..7f65242 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/CodeReload_Minics/pong.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 8ba7fa42014981348997afa11a492f9c \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/Unity.Pipeline.Samples.asmdef b/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/Unity.Pipeline.Samples.asmdef new file mode 100644 index 0000000..6d6de50 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/Unity.Pipeline.Samples.asmdef @@ -0,0 +1,17 @@ +{ + "name": "Unity.Pipeline.Samples", + "rootNamespace": "Unity.Pipeline.Samples.CodeReload", + "references": [ + "Unity.Pipeline", + "Unity.Pipeline.Attributes" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} diff --git a/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/Unity.Pipeline.Samples.asmdef.meta b/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/Unity.Pipeline.Samples.asmdef.meta new file mode 100644 index 0000000..abc3ce1 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Samples~/CodeReload/Unity.Pipeline.Samples.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: fadfe42d23f96db47a2c41e046892acb +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Tests~.meta b/AIClient/Packages/com.unity.pipeline/Tests~.meta new file mode 100644 index 0000000..4f2196a --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 005114723dbbd384bb5fe02db11a3b99 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor.meta new file mode 100644 index 0000000..6b4fea2 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3ffa6a16c12a1a248884139af2530848 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation.meta new file mode 100644 index 0000000..1365e8e --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: de3774b0893944d8ac6871cbcaa631ab +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation/AnimationClipCommandsTests.cs b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation/AnimationClipCommandsTests.cs new file mode 100644 index 0000000..f163821 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation/AnimationClipCommandsTests.cs @@ -0,0 +1,211 @@ +using System.Linq; +using NUnit.Framework; +using Newtonsoft.Json.Linq; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Editor.Commands.Animation; +using Unity.Pipeline.Models; +using UnityEditor; +using UnityEngine; + +namespace Unity.Pipeline.Tests.Editor.Animation +{ + /// + /// Tests for CLI-214 Group A (animation clips): create clip with frame rate + loop, set/get/remove + /// float curves, the overwrite-not-duplicate behaviour, the destructive remove guard, dry_run, and + /// the sandbox guard. Assets are generated in-test under a throwaway root and cleaned up. + /// + class AnimationClipCommandsTests + { + private const string Root = "Assets/__CLI214AnimTest"; + + [TearDown] + public void TearDown() + { + ProjectPaths.ResetAuthoringRoot(); + if (AssetDatabase.IsValidFolder(Root)) + { + AssetDatabase.DeleteAsset(Root); + AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport); + } + } + + private static ObjectRef PathRef(string path) => new ObjectRef { Path = path }; + + private static JArray TwoKeys() => new JArray + { + new JObject { ["time"] = 0f, ["value"] = 0f }, + new JObject { ["time"] = 1f, ["value"] = 5f } + }; + + [Test] + public void CreateAnimationClip_SetsFrameRateAndLoop() + { + var path = Root + "/Clips/Walk.anim"; + var result = AnimationClipCommands.CreateAnimationClip(path, frameRate: 30f, loop: true); + + Assert.AreEqual(path, result.AssetPath); + + var loaded = AssetDatabase.LoadAssetAtPath(path); + Assert.IsNotNull(loaded, "Clip should exist on disk"); + Assert.AreEqual(30f, loaded.frameRate, 0.001f); + + var info = AnimationClipCommands.GetAnimationClip(PathRef(path)); + Assert.AreEqual(30f, info.FrameRate, 0.001f); + Assert.IsTrue(info.Loop, "loop should be reflected by get_animation_clip"); + } + + [Test] + public void CreateAnimationClip_OverwriteWithoutConfirm_Throws() + { + var path = Root + "/Clips/Dup.anim"; + AnimationClipCommands.CreateAnimationClip(path); + + Assert.Throws(() => AnimationClipCommands.CreateAnimationClip(path)); + Assert.DoesNotThrow(() => AnimationClipCommands.CreateAnimationClip(path, confirm: true)); + } + + [Test] + public void CreateAnimationClip_OutOfProject_Throws() + { + Assert.Throws(() => AnimationClipCommands.CreateAnimationClip("../Outside.anim")); + Assert.Throws(() => AnimationClipCommands.CreateAnimationClip("Assets/../Outside.anim")); + } + + [Test] + public void CreateAnimationClip_DryRun_WritesNothing() + { + var path = Root + "/Clips/DryRun.anim"; + var result = AnimationClipCommands.CreateAnimationClip(path, dryRun: true); + + Assert.AreEqual(path, result.AssetPath); + Assert.IsNull(AssetDatabase.LoadMainAssetAtPath(path), "dry_run must not write a clip"); + } + + [Test] + public void SetAnimationCurve_AddsCurveWithKeys() + { + var path = Root + "/Clips/Curve.anim"; + AnimationClipCommands.CreateAnimationClip(path); + + var result = AnimationClipCommands.SetAnimationCurve( + PathRef(path), path: "", type: "Transform", property: "m_LocalPosition.x", keys: TwoKeys()); + + Assert.AreEqual(2, result.KeyCount); + Assert.AreEqual("m_LocalPosition.x", result.Binding.Property); + + var info = AnimationClipCommands.GetAnimationClip(PathRef(path), includeKeys: true); + Assert.AreEqual(1, info.Bindings.Count); + var binding = info.Bindings[0]; + Assert.AreEqual("Transform", binding.Type); + Assert.AreEqual("m_LocalPosition.x", binding.Property); + Assert.AreEqual(2, binding.KeyCount); + Assert.IsNotNull(binding.Keys); + Assert.AreEqual(2, binding.Keys.Count); + Assert.AreEqual(0f, binding.Keys[0].Value, 0.001f); + Assert.AreEqual(5f, binding.Keys[1].Value, 0.001f); + } + + [Test] + public void SetAnimationCurve_ReplaceExisting_Overwrites() + { + var path = Root + "/Clips/Replace.anim"; + AnimationClipCommands.CreateAnimationClip(path); + + AnimationClipCommands.SetAnimationCurve(PathRef(path), "", "Transform", "m_LocalPosition.x", TwoKeys()); + + var threeKeys = new JArray + { + new JObject { ["time"] = 0f, ["value"] = 0f }, + new JObject { ["time"] = 0.5f, ["value"] = 2f }, + new JObject { ["time"] = 1f, ["value"] = 4f } + }; + var result = AnimationClipCommands.SetAnimationCurve(PathRef(path), "", "Transform", "m_LocalPosition.x", threeKeys); + Assert.AreEqual(3, result.KeyCount); + + var info = AnimationClipCommands.GetAnimationClip(PathRef(path)); + // Same binding => not duplicated; the single binding now has 3 keys. + Assert.AreEqual(1, info.Bindings.Count, "Replacing a binding must not duplicate it"); + Assert.AreEqual(3, info.Bindings[0].KeyCount); + } + + [Test] + public void SetAnimationCurve_DryRun_WritesNothing() + { + var path = Root + "/Clips/DryCurve.anim"; + AnimationClipCommands.CreateAnimationClip(path); + + var result = AnimationClipCommands.SetAnimationCurve( + PathRef(path), "", "Transform", "m_LocalPosition.x", TwoKeys(), dryRun: true); + Assert.AreEqual(2, result.KeyCount); + + var info = AnimationClipCommands.GetAnimationClip(PathRef(path)); + Assert.AreEqual(0, info.Bindings.Count, "dry_run must not write a curve"); + } + + [Test] + public void RemoveAnimationCurve_WithoutConfirm_Throws() + { + var path = Root + "/Clips/Remove.anim"; + AnimationClipCommands.CreateAnimationClip(path); + AnimationClipCommands.SetAnimationCurve(PathRef(path), "", "Transform", "m_LocalPosition.x", TwoKeys()); + + Assert.Throws( + () => AnimationClipCommands.RemoveAnimationCurve(PathRef(path), "", "Transform", "m_LocalPosition.x"), + "remove without confirm should be rejected"); + + var info = AnimationClipCommands.GetAnimationClip(PathRef(path)); + Assert.AreEqual(1, info.Bindings.Count, "binding should survive a refused remove"); + } + + [Test] + public void RemoveAnimationCurve_WithConfirm_Removes() + { + var path = Root + "/Clips/Remove2.anim"; + AnimationClipCommands.CreateAnimationClip(path); + AnimationClipCommands.SetAnimationCurve(PathRef(path), "", "Transform", "m_LocalPosition.x", TwoKeys()); + + AnimationClipCommands.RemoveAnimationCurve(PathRef(path), "", "Transform", "m_LocalPosition.x", confirm: true); + + var info = AnimationClipCommands.GetAnimationClip(PathRef(path)); + Assert.AreEqual(0, info.Bindings.Count, "binding should be gone after a confirmed remove"); + } + + [Test] + public void SetAnimationCurve_UnknownType_Throws() + { + var path = Root + "/Clips/BadType.anim"; + AnimationClipCommands.CreateAnimationClip(path); + + Assert.Throws( + () => AnimationClipCommands.SetAnimationCurve(PathRef(path), "", "NotARealComponent__CLI214", "m_X", TwoKeys())); + } + + [Test] + public void SetAnimationCurve_ViaClient_Succeeds() + { + var path = Root + "/ViaClient/Curve.anim"; + AnimationClipCommands.CreateAnimationClip(path); + + using (var server = new PipelineTestServer()) + { + var response = server.Execute("set_animation_curve", new + { + clip = new { path }, + type = "Transform", + property = "m_LocalPosition.x", + keys = new object[] + { + new { time = 0f, value = 0f }, + new { time = 1f, value = 5f } + } + }); + + Assert.IsTrue(response.IsSuccess, $"set_animation_curve should succeed: {response.Error}"); + } + + var info = AnimationClipCommands.GetAnimationClip(PathRef(path)); + Assert.AreEqual(1, info.Bindings.Count); + Assert.AreEqual(2, info.Bindings[0].KeyCount); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation/AnimationClipCommandsTests.cs.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation/AnimationClipCommandsTests.cs.meta new file mode 100644 index 0000000..3af6f9b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation/AnimationClipCommandsTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 613a4bb343db4a4cb96ae6fef8195425 diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation/AnimatorControllerCommandsTests.cs b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation/AnimatorControllerCommandsTests.cs new file mode 100644 index 0000000..36cbcc7 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation/AnimatorControllerCommandsTests.cs @@ -0,0 +1,261 @@ +using NUnit.Framework; +using Newtonsoft.Json.Linq; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Editor.Commands.Animation; +using Unity.Pipeline.Models; +using UnityEditor; +using UnityEngine; + +namespace Unity.Pipeline.Tests.Editor.Animation +{ + /// + /// Tests for CLI-214 Group B (animator controllers): create controller (Base Layer, no states), + /// add parameter (and duplicate => duplicate_parameter), add layer, add state (with motion + as + /// default), add transition (with a matching condition), and the validation failures (missing + /// parameter, mode/type mismatch). Assets are generated in-test and cleaned up. + /// + class AnimatorControllerCommandsTests + { + private const string Root = "Assets/__CLI214CtrlTest"; + + [TearDown] + public void TearDown() + { + ProjectPaths.ResetAuthoringRoot(); + if (AssetDatabase.IsValidFolder(Root)) + { + AssetDatabase.DeleteAsset(Root); + AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport); + } + } + + private static ObjectRef PathRef(string path) => new ObjectRef { Path = path }; + + private string CreateController(string name) + { + var path = $"{Root}/{name}.controller"; + AnimatorControllerCommands.CreateAnimatorController(path); + return path; + } + + [Test] + public void CreateController_HasOneBaseLayerNoStates() + { + var path = CreateController("Empty"); + + var info = AnimatorControllerCommands.GetAnimatorController(PathRef(path)); + Assert.AreEqual(1, info.Layers.Count, "A new controller should have exactly one (Base) layer"); + Assert.AreEqual(0, info.Layers[0].States.Count, "Base Layer should start with no states"); + Assert.AreEqual(0, info.Parameters.Count); + } + + [Test] + public void AddParameter_Float_AndDuplicate() + { + var path = CreateController("Params"); + + var added = AnimatorControllerCommands.AddAnimatorParameter(PathRef(path), "Speed", "Float", new JValue(0f)); + Assert.IsInstanceOf(added); + + var info = AnimatorControllerCommands.GetAnimatorController(PathRef(path)); + Assert.AreEqual(1, info.Parameters.Count); + Assert.AreEqual("Speed", info.Parameters[0].Name); + Assert.AreEqual("Float", info.Parameters[0].ParamType); + + // Duplicate name => structured error, not exception. + var dup = AnimatorControllerCommands.AddAnimatorParameter(PathRef(path), "Speed", "Float"); + Assert.IsInstanceOf(dup); + Assert.AreEqual("duplicate_parameter", ((ErrorResult)dup).Code); + } + + [Test] + public void AddLayer_AppendsLayer() + { + var path = CreateController("Layers"); + + var added = AnimatorControllerCommands.AddAnimatorLayer(PathRef(path), "Upper", weight: 0.5f, blendingMode: "Additive"); + Assert.IsInstanceOf(added); + Assert.AreEqual(1, ((AddLayerResult)added).Layer.Index); + + var info = AnimatorControllerCommands.GetAnimatorController(PathRef(path)); + Assert.AreEqual(2, info.Layers.Count); + Assert.AreEqual("Upper", info.Layers[1].Name); + } + + [Test] + public void AddState_WithMotionAndDefault() + { + var path = CreateController("States"); + + // A clip to use as the state motion. + var clipPath = Root + "/Idle.anim"; + AnimationClipCommands.CreateAnimationClip(clipPath); + + var added = AnimatorControllerCommands.AddAnimatorState( + PathRef(path), layer: null, name: "Idle", motion: PathRef(clipPath), isDefault: true); + Assert.IsInstanceOf(added); + + var info = AnimatorControllerCommands.GetAnimatorController(PathRef(path)); + Assert.AreEqual(1, info.Layers[0].States.Count); + var state = info.Layers[0].States[0]; + Assert.AreEqual("Idle", state.Name); + Assert.IsTrue(state.IsDefault, "Idle should be the layer default"); + Assert.IsNotNull(state.Motion, "Idle should have a non-null motion"); + Assert.AreEqual("Idle", info.Layers[0].DefaultState); + } + + [Test] + public void AddState_UnknownLayerName_ReturnsLayerNotFound() + { + var path = CreateController("BadLayer"); + + var result = AnimatorControllerCommands.AddAnimatorState( + PathRef(path), layer: new JValue("NoSuchLayer"), name: "S"); + Assert.IsInstanceOf(result); + Assert.AreEqual("layer_not_found", ((ErrorResult)result).Code); + } + + [Test] + public void AddTransition_WithCondition() + { + var path = CreateController("Transitions"); + AnimatorControllerCommands.AddAnimatorParameter(PathRef(path), "Speed", "Float", new JValue(0f)); + AnimatorControllerCommands.AddAnimatorState(PathRef(path), null, "Idle"); + AnimatorControllerCommands.AddAnimatorState(PathRef(path), null, "Run"); + + var conditions = new JArray + { + new JObject { ["parameter"] = "Speed", ["mode"] = "Greater", ["threshold"] = 0.1f } + }; + var added = AnimatorControllerCommands.AddAnimatorTransition( + PathRef(path), null, "Idle", "Run", conditions); + Assert.IsInstanceOf(added); + Assert.AreEqual(1, ((AddTransitionResult)added).Transition.ConditionCount); + + var info = AnimatorControllerCommands.GetAnimatorController(PathRef(path)); + var transitions = info.Layers[0].Transitions; + Assert.AreEqual(1, transitions.Count); + Assert.AreEqual("Idle", transitions[0].From); + Assert.AreEqual("Run", transitions[0].To); + Assert.AreEqual(1, transitions[0].Conditions.Count); + Assert.AreEqual("Speed", transitions[0].Conditions[0].Parameter); + Assert.AreEqual("Greater", transitions[0].Conditions[0].Mode); + } + + [Test] + public void AddTransition_UnknownParameter_ThrowsAndWritesNothing() + { + var path = CreateController("BadParam"); + AnimatorControllerCommands.AddAnimatorState(PathRef(path), null, "Idle"); + AnimatorControllerCommands.AddAnimatorState(PathRef(path), null, "Run"); + + var conditions = new JArray + { + new JObject { ["parameter"] = "Ghost", ["mode"] = "Greater", ["threshold"] = 0.1f } + }; + + var ex = Assert.Throws( + () => AnimatorControllerCommands.AddAnimatorTransition(PathRef(path), null, "Idle", "Run", conditions)); + StringAssert.Contains("Ghost", ex.Message, "error should name the offending parameter"); + + var info = AnimatorControllerCommands.GetAnimatorController(PathRef(path)); + Assert.AreEqual(0, info.Layers[0].Transitions.Count, "nothing should be written on a bad condition"); + } + + [Test] + public void AddTransition_ModeTypeMismatch_Throws() + { + var path = CreateController("Mismatch"); + AnimatorControllerCommands.AddAnimatorParameter(PathRef(path), "Speed", "Float", new JValue(0f)); + AnimatorControllerCommands.AddAnimatorState(PathRef(path), null, "Idle"); + AnimatorControllerCommands.AddAnimatorState(PathRef(path), null, "Run"); + + // "If" is only valid for Bool/Trigger, not a Float parameter. + var conditions = new JArray + { + new JObject { ["parameter"] = "Speed", ["mode"] = "If" } + }; + + Assert.Throws( + () => AnimatorControllerCommands.AddAnimatorTransition(PathRef(path), null, "Idle", "Run", conditions)); + } + + [Test] + public void AddState_FractionalLayerIndex_ReturnsLayerNotFound() + { + var path = CreateController("FractionalLayer"); + + // 0.9 must NOT be silently rounded to layer 1; a non-integer index is rejected. + var result = AnimatorControllerCommands.AddAnimatorState( + PathRef(path), layer: new JValue(0.9d), name: "S"); + Assert.IsInstanceOf(result); + Assert.AreEqual("layer_not_found", ((ErrorResult)result).Code); + } + + [Test] + public void AddState_IntegerValuedFloatLayer_Resolves() + { + var path = CreateController("IntFloatLayer"); + + // 0.0 is an integer-valued float and resolves to the Base Layer (index 0). + var added = AnimatorControllerCommands.AddAnimatorState( + PathRef(path), layer: new JValue(0d), name: "Idle"); + Assert.IsInstanceOf(added); + Assert.AreEqual(0, ((AddStateResult)added).State.Layer); + } + + [Test] + public void AddTransition_ExitTimeOutOfRange_Throws() + { + var path = CreateController("BadExitTime"); + AnimatorControllerCommands.AddAnimatorState(PathRef(path), null, "Idle"); + AnimatorControllerCommands.AddAnimatorState(PathRef(path), null, "Run"); + + Assert.Throws( + () => AnimatorControllerCommands.AddAnimatorTransition( + PathRef(path), null, "Idle", "Run", conditions: null, hasExitTime: true, exitTime: 1.5f)); + + var info = AnimatorControllerCommands.GetAnimatorController(PathRef(path)); + Assert.AreEqual(0, info.Layers[0].Transitions.Count, "an out-of-range exitTime must write nothing"); + } + + [Test] + public void AddTransition_NegativeDuration_Throws() + { + var path = CreateController("BadDuration"); + AnimatorControllerCommands.AddAnimatorState(PathRef(path), null, "Idle"); + AnimatorControllerCommands.AddAnimatorState(PathRef(path), null, "Run"); + + Assert.Throws( + () => AnimatorControllerCommands.AddAnimatorTransition( + PathRef(path), null, "Idle", "Run", conditions: null, duration: -1f)); + + var info = AnimatorControllerCommands.GetAnimatorController(PathRef(path)); + Assert.AreEqual(0, info.Layers[0].Transitions.Count, "a negative duration must write nothing"); + } + + [Test] + public void AddParameter_DryRun_WritesNothing() + { + var path = CreateController("DryParam"); + + AnimatorControllerCommands.AddAnimatorParameter(PathRef(path), "Speed", "Float", new JValue(0f), dryRun: true); + + var info = AnimatorControllerCommands.GetAnimatorController(PathRef(path)); + Assert.AreEqual(0, info.Parameters.Count, "dry_run must not write a parameter"); + } + + [Test] + public void CreateController_ViaClient_Succeeds() + { + using (var server = new PipelineTestServer()) + { + var path = Root + "/ViaClient/Made.controller"; + var response = server.Execute("create_animator_controller", new { path }); + + Assert.IsTrue(response.IsSuccess, $"create_animator_controller should succeed: {response.Error}"); + Assert.IsNotNull(AssetDatabase.LoadMainAssetAtPath(path), "Controller should exist on disk"); + } + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation/AnimatorControllerCommandsTests.cs.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation/AnimatorControllerCommandsTests.cs.meta new file mode 100644 index 0000000..6655cd6 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation/AnimatorControllerCommandsTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c1d78b8f19fc48cea840bc62c3204b3e diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation/TimelineCommandsTests.cs b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation/TimelineCommandsTests.cs new file mode 100644 index 0000000..31ddc4a --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation/TimelineCommandsTests.cs @@ -0,0 +1,81 @@ +using NUnit.Framework; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Editor.Commands.Animation; +using Unity.Pipeline.Models; +using UnityEditor; + +namespace Unity.Pipeline.Tests.Editor.Animation +{ + /// + /// Tests for CLI-214 Group C (Timeline). Timeline ships in the OPTIONAL com.unity.timeline package, + /// so this fixture must COMPILE and PASS whether or not the package is installed: + /// - runs only when the package is ABSENT + /// and asserts the structured package_not_found error (no exception). + /// - the create -> add track -> add clip -> get flow runs only when the package is PRESENT and + /// calls Assert.Pass (not Assert.Ignore) when absent, so Yamato strict-mode + /// agents see "Passed" rather than "Not Run" (Inconclusive) for the conditional skip. + /// + /// All commands are reached through the public static methods; the Timeline types themselves are + /// only touched via reflection inside the commands, never referenced by this test assembly. + /// + class TimelineCommandsTests + { + private const string Root = "Assets/__CLI214TimelineTest"; + + [TearDown] + public void TearDown() + { + ProjectPaths.ResetAuthoringRoot(); + if (AssetDatabase.IsValidFolder(Root)) + { + AssetDatabase.DeleteAsset(Root); + AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport); + } + } + + private static ObjectRef PathRef(string path) => new ObjectRef { Path = path }; + + [Test] + public void Timeline_NotInstalled_ReturnsPackageNotFound() + { + if (TimelineGuard.IsInstalled()) + Assert.Pass("com.unity.timeline is installed; the not-installed path is covered only when it is absent."); + + var result = TimelineCommands.CreateTimeline(Root + "/T.playable"); + Assert.IsInstanceOf(result, "Timeline commands must not throw when the package is absent"); + Assert.AreEqual("package_not_found", ((ErrorResult)result).Code); + } + + [Test] + public void Timeline_CreateTrackClipGet_Flow() + { + if (!TimelineGuard.IsInstalled()) + Assert.Pass("com.unity.timeline is not installed; the Timeline authoring flow is validated only when the package is present."); + + // create_timeline + var timelinePath = Root + "/Cutscene.playable"; + var created = TimelineCommands.CreateTimeline(timelinePath, frameRate: 30f); + Assert.IsInstanceOf(created, "create_timeline should return an AuthoringResult when installed"); + + // add an Animation track + var trackResult = TimelineCommands.AddTimelineTrack(PathRef(timelinePath), "Animation", name: "Anim"); + Assert.IsInstanceOf(trackResult); + + // a clip asset for the Animation track + var clipPath = Root + "/Move.anim"; + AnimationClipCommands.CreateAnimationClip(clipPath); + + // add_timeline_clip (start 0, duration 2) + var clipResult = TimelineCommands.AddTimelineClip( + PathRef(timelinePath), track: "Anim", start: 0f, duration: 2f, asset: PathRef(clipPath)); + Assert.IsInstanceOf(clipResult); + + // get_timeline => one Animation track with one 2s clip + var info = (TimelineInfo)TimelineCommands.GetTimeline(PathRef(timelinePath)); + Assert.AreEqual(1, info.Tracks.Count, "expected exactly one track"); + Assert.AreEqual("Animation", info.Tracks[0].TrackType); + Assert.AreEqual(1, info.Tracks[0].Clips.Count, "expected exactly one clip"); + Assert.AreEqual(2d, info.Tracks[0].Clips[0].Duration, 0.001d); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation/TimelineCommandsTests.cs.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation/TimelineCommandsTests.cs.meta new file mode 100644 index 0000000..fd8848b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Animation/TimelineCommandsTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 72d8c657533f4b8b96feb3af780d619a diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/ApiEndpointsTests.cs b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/ApiEndpointsTests.cs new file mode 100644 index 0000000..a1c3533 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/ApiEndpointsTests.cs @@ -0,0 +1,1229 @@ +using System.Linq; +using System.Threading.Tasks; +using NUnit.Framework; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor; +using Unity.Pipeline.Models; +using Newtonsoft.Json.Linq; +using UnityEngine.TestTools; +using System.Text.RegularExpressions; + +namespace Unity.Pipeline.Tests.Editor +{ + /// + /// Tests for HTTP API endpoints that CLI tools will consume. + /// These test the complete server API surface for remote command execution. + /// + class ApiEndpointsTests + { + private EditorPipelineServer m_Server; + private Unity.Pipeline.Tests.Runtime.PipelineClient m_PipelineClient; + + [SetUp] + public void SetUp() + { + // Setup command discovery for tests + CommandRegistry.SetDiscovery(new TypeCacheCommandDiscovery()); + + // Start an ISOLATED test server (ports 7850-7899, writes no descriptor) for endpoint + // testing, so we never bind the live server's port (7800) or clobber its descriptor. + m_Server = new TestEditorPipelineServer(); + m_Server.Start(); + + m_PipelineClient = new Unity.Pipeline.Tests.Runtime.PipelineClient(m_Server); + } + + [TearDown] + public void TearDown() + { + m_PipelineClient?.Dispose(); + m_Server?.Stop(); + } + + [Test] + public async Task ApiCommands_GetEndpoint_ReturnsCommandList() + { + // Act - Call /api/commands endpoint using unified Pipeline client + var httpResponse = await m_PipelineClient.GetHttpAsync("/api/commands"); + var jsonContent = await httpResponse.Content.ReadAsStringAsync(); + + // Assert - Response structure + Assert.IsTrue(httpResponse.IsSuccessStatusCode, + $"Commands endpoint should return success, got: {httpResponse.StatusCode}"); + Assert.AreEqual("application/json", httpResponse.Content.Headers.ContentType.MediaType, + "Commands endpoint should return JSON content type"); + + // Assert - JSON parsing + var responseJson = JObject.Parse(jsonContent); + Assert.IsNotNull(responseJson, "Should be able to parse commands JSON"); + + // Verify response structure + Assert.IsNotNull(responseJson["commands"], "Response should have commands array"); + Assert.IsNotNull(responseJson["count"], "Response should have count field"); + Assert.IsNotNull(responseJson["server"], "Response should have server info"); + + // Verify commands array contains discovered commands + var commands = responseJson["commands"] as JArray; + Assert.Greater(commands.Count, 0, "Should have at least one discovered command"); + + // Verify a specific test command is included + var testCommand = commands.Cast() + .FirstOrDefault(cmd => cmd["name"]?.ToString() == "log_editor"); + Assert.IsNotNull(testCommand, "Should include log_editor test command"); + Assert.AreEqual("Log a message to Unity Editor console", testCommand["description"]?.ToString()); + } + + [Test] + public async Task ApiCommands_OnEditorServer_ExcludesRuntimeOnlyCommands() + { + // Act - List commands from the Editor server + var httpResponse = await m_PipelineClient.GetHttpAsync("/api/commands"); + var jsonContent = await httpResponse.Content.ReadAsStringAsync(); + var responseJson = JObject.Parse(jsonContent); + var commandNames = (responseJson["commands"] as JArray) + .Cast() + .Select(cmd => cmd["name"]?.ToString()) + .ToList(); + + // Assert - editor commands are listed, runtime-only commands are hidden + Assert.Contains("editor_status", commandNames, "Editor command should be listed"); + CollectionAssert.DoesNotContain(commandNames, "runtime_status", "Runtime-only eval should be hidden on the Editor server"); + CollectionAssert.DoesNotContain(commandNames, "set_target_framerate", "Runtime-only commands should be hidden on the Editor server"); + } + + [Test] + public async Task ApiCommands_DefaultDetail_ReturnsFullMetadata() + { + // Act - no detail parameter: full is the default (back-compat with pre-detail clients) + var httpResponse = await m_PipelineClient.GetHttpAsync("/api/commands"); + var jsonContent = await httpResponse.Content.ReadAsStringAsync(); + + // Assert + Assert.IsTrue(httpResponse.IsSuccessStatusCode, + $"Commands endpoint should return success, got: {httpResponse.StatusCode}"); + var responseJson = JObject.Parse(jsonContent); + var commands = responseJson["commands"] as JArray; + Assert.Greater(commands.Count, 0, "Should have at least one discovered command"); + + var logEditor = commands.Cast() + .First(cmd => cmd["name"]?.ToString() == "log_editor"); + Assert.IsNotNull(logEditor["parameters"], "default detail should include parameters"); + Assert.IsNotNull(logEditor["schema"], "default detail should include schema"); + Assert.IsNotNull(logEditor["tags"], "default detail should include tags"); + Assert.IsNotNull(logEditor["package"], "default detail should include package"); + } + + [Test] + public async Task ApiCommands_DetailCompact_ReturnsLightweightIndex() + { + // Act - detail=compact opts into the lightweight browse/discovery projection + var httpResponse = await m_PipelineClient.GetHttpAsync("/api/commands?detail=compact"); + var jsonContent = await httpResponse.Content.ReadAsStringAsync(); + + // Assert + Assert.IsTrue(httpResponse.IsSuccessStatusCode, + $"detail=compact should return success, got: {httpResponse.StatusCode}"); + var commands = JObject.Parse(jsonContent)["commands"] as JArray; + Assert.Greater(commands.Count, 0, "Should have at least one discovered command"); + + foreach (var cmd in commands.Cast()) + { + Assert.IsNotNull(cmd["name"], "compact entry should have name"); + Assert.IsNotNull(cmd["description"], "compact entry should have description"); + Assert.IsNotNull(cmd["tags"], "compact entry should have tags"); + Assert.IsNotNull(cmd["package"], "compact entry should have package"); + Assert.IsNull(cmd["parameters"], $"compact entry '{cmd["name"]}' should omit parameters"); + Assert.IsNull(cmd["schema"], $"compact entry '{cmd["name"]}' should omit schema"); + } + } + + [Test] + public async Task ApiCommands_QueryFilter_MatchesTagCaseInsensitively() + { + // Act - 'REGISTRATION' only appears in test_tagged's 'test/registration' tag + var httpResponse = await m_PipelineClient.GetHttpAsync("/api/commands?detail=compact&query=REGISTRATION"); + var jsonContent = await httpResponse.Content.ReadAsStringAsync(); + + // Assert + Assert.IsTrue(httpResponse.IsSuccessStatusCode, + $"query filter should return success, got: {httpResponse.StatusCode}"); + var responseJson = JObject.Parse(jsonContent); + var names = (responseJson["commands"] as JArray) + .Cast() + .Select(cmd => cmd["name"]?.ToString()) + .ToList(); + Assert.Contains("test_tagged", names, "query should match a command via its tag, case-insensitively"); + CollectionAssert.DoesNotContain(names, "log_editor", "commands matching neither name, description nor tag should be filtered out"); + } + + [Test] + public async Task ApiCommands_QueryFilter_MatchesNameByPrefix() + { + // Act - 'log_edi' is a strict prefix of the 'log_editor' command name + var httpResponse = await m_PipelineClient.GetHttpAsync("/api/commands?detail=compact&query=log_edi"); + var jsonContent = await httpResponse.Content.ReadAsStringAsync(); + + // Assert + Assert.IsTrue(httpResponse.IsSuccessStatusCode, + $"query filter should return success, got: {httpResponse.StatusCode}"); + var names = (JObject.Parse(jsonContent)["commands"] as JArray) + .Cast() + .Select(cmd => cmd["name"]?.ToString()) + .ToList(); + Assert.Contains("log_editor", names, "a query that is a prefix of a command name should match that command"); + } + + [Test] + public async Task ApiCommands_QueryFilter_NoMatch_ReturnsEmptyNotError() + { + // Act + var httpResponse = await m_PipelineClient.GetHttpAsync("/api/commands?query=zzz_definitely_no_match_zzz"); + var jsonContent = await httpResponse.Content.ReadAsStringAsync(); + + // Assert - empty result, not an error + Assert.IsTrue(httpResponse.IsSuccessStatusCode, + $"a no-match query should still return success, got: {httpResponse.StatusCode}"); + var responseJson = JObject.Parse(jsonContent); + Assert.AreEqual(0, (responseJson["commands"] as JArray).Count, "no-match query should return an empty commands array"); + Assert.AreEqual(0, responseJson["total"]?.ToObject(), "no-match query should report total 0"); + Assert.AreEqual(0, responseJson["count"]?.ToObject(), "no-match query should report count 0"); + } + + [Test] + public async Task ApiCommands_TagFilter_MatchesSubtreeBySegmentPrefix() + { + // Act / Assert - 'test' matches the exact 'test' tag and the 'test/registration' subtree + var jsonContent = await (await m_PipelineClient.GetHttpAsync("/api/commands?detail=compact&tag=test")) + .Content.ReadAsStringAsync(); + var names = (JObject.Parse(jsonContent)["commands"] as JArray) + .Cast().Select(cmd => cmd["name"]?.ToString()).ToList(); + Assert.Contains("test_tagged", names, "tag=test should match the tagged test command"); + CollectionAssert.DoesNotContain(names, "log_editor", "untagged commands should be filtered out"); + + // Drilling into a subtag still matches + jsonContent = await (await m_PipelineClient.GetHttpAsync("/api/commands?detail=compact&tag=test/registration")) + .Content.ReadAsStringAsync(); + names = (JObject.Parse(jsonContent)["commands"] as JArray) + .Cast().Select(cmd => cmd["name"]?.ToString()).ToList(); + Assert.Contains("test_tagged", names, "tag=test/registration should match the subtag directly"); + + // Segment-aware: 'tes' is not a whole-segment prefix of 'test' + jsonContent = await (await m_PipelineClient.GetHttpAsync("/api/commands?tag=tes")) + .Content.ReadAsStringAsync(); + Assert.AreEqual(0, JObject.Parse(jsonContent)["total"]?.ToObject(), + "tag matching should respect '/' segment boundaries, not raw string prefixes"); + } + + [Test] + public async Task ApiCommands_CombinedFilters_AreAnded() + { + // Act - log_editor matches the query but carries no tags, so the tag filter excludes it + var httpResponse = await m_PipelineClient.GetHttpAsync("/api/commands?query=log_editor&tag=test"); + var jsonContent = await httpResponse.Content.ReadAsStringAsync(); + + // Assert + Assert.IsTrue(httpResponse.IsSuccessStatusCode, + $"combined filters should return success, got: {httpResponse.StatusCode}"); + Assert.AreEqual(0, JObject.Parse(jsonContent)["total"]?.ToObject(), + "filters should combine with AND"); + } + + [Test] + public async Task ApiCommands_GroupByPackage_GroupsCommandsByOriginatingAssembly() + { + // Act + var httpResponse = await m_PipelineClient.GetHttpAsync("/api/commands?detail=compact&group_by=package&query=log_editor"); + var jsonContent = await httpResponse.Content.ReadAsStringAsync(); + + // Assert - grouped responses carry 'groups' instead of 'commands' + Assert.IsTrue(httpResponse.IsSuccessStatusCode, + $"group_by=package should return success, got: {httpResponse.StatusCode}"); + var responseJson = JObject.Parse(jsonContent); + Assert.IsNull(responseJson["commands"], "grouped response should not have a flat commands array"); + var groups = responseJson["groups"] as JArray; + Assert.IsNotNull(groups, "grouped response should have a groups array"); + + var testGroup = groups.Cast() + .FirstOrDefault(g => g["package"]?.ToString() == "Unity.Pipeline.Tests.Editor"); + Assert.IsNotNull(testGroup, "log_editor's assembly should appear as a package group"); + var groupNames = (testGroup["commands"] as JArray) + .Cast().Select(cmd => cmd["name"]?.ToString()).ToList(); + Assert.Contains("log_editor", groupNames, "the group should contain the matching command"); + } + + [Test] + public async Task ApiCommands_GroupByTag_ReturnsNestedTagTree() + { + // Act + var httpResponse = await m_PipelineClient.GetHttpAsync("/api/commands?detail=compact&group_by=tag&tag=test"); + var jsonContent = await httpResponse.Content.ReadAsStringAsync(); + + // Assert - top-level 'test' node with a nested 'test/registration' child + Assert.IsTrue(httpResponse.IsSuccessStatusCode, + $"group_by=tag should return success, got: {httpResponse.StatusCode}"); + var groups = JObject.Parse(jsonContent)["groups"] as JArray; + Assert.IsNotNull(groups, "grouped response should have a groups array"); + + var testNode = groups.Cast().FirstOrDefault(g => g["tag"]?.ToString() == "test"); + Assert.IsNotNull(testNode, "should have a top-level 'test' tag node"); + var directNames = (testNode["commands"] as JArray) + .Cast().Select(cmd => cmd["name"]?.ToString()).ToList(); + Assert.Contains("test_tagged", directNames, "test_tagged carries the exact 'test' tag"); + + var childNode = (testNode["children"] as JArray)?.Cast() + .FirstOrDefault(g => g["tag"]?.ToString() == "test/registration"); + Assert.IsNotNull(childNode, "'test/registration' should nest under 'test'"); + var childNames = (childNode["commands"] as JArray) + .Cast().Select(cmd => cmd["name"]?.ToString()).ToList(); + Assert.Contains("test_tagged", childNames, "test_tagged also carries the 'test/registration' tag"); + } + + [Test] + public async Task ApiCommands_GroupByInvalid_ReturnsBadRequestListingAcceptedValues() + { + // Act + var httpResponse = await m_PipelineClient.GetHttpAsync("/api/commands?group_by=namespace"); + var jsonContent = await httpResponse.Content.ReadAsStringAsync(); + + // Assert + Assert.AreEqual(400, (int)httpResponse.StatusCode, + $"Invalid group_by value should be rejected with 400. Response: {jsonContent}"); + StringAssert.Contains("flat", jsonContent, "error should list accepted value 'flat'"); + StringAssert.Contains("package", jsonContent, "error should list accepted value 'package'"); + StringAssert.Contains("tag", jsonContent, "error should list accepted value 'tag'"); + } + + [Test] + public async Task ApiCommands_Pagination_SlicesNameSortedListDeterministically() + { + // Arrange - the unpaginated listing (name-sorted for deterministic pages) + var allJson = await (await m_PipelineClient.GetHttpAsync("/api/commands?detail=compact")) + .Content.ReadAsStringAsync(); + var allNames = (JObject.Parse(allJson)["commands"] as JArray) + .Cast().Select(cmd => cmd["name"]?.ToString()).ToList(); + CollectionAssert.AreEqual(allNames.OrderBy(n => n, System.StringComparer.Ordinal).ToList(), allNames, + "commands should be name-sorted so pagination windows are deterministic"); + + // Act + var pageJson = await (await m_PipelineClient.GetHttpAsync("/api/commands?detail=compact&offset=1&limit=2")) + .Content.ReadAsStringAsync(); + var pageResponse = JObject.Parse(pageJson); + var pageNames = (pageResponse["commands"] as JArray) + .Cast().Select(cmd => cmd["name"]?.ToString()).ToList(); + + // Assert + CollectionAssert.AreEqual(allNames.Skip(1).Take(2).ToList(), pageNames, + "offset/limit should slice the same ordering the unpaginated listing uses"); + Assert.AreEqual(2, pageResponse["count"]?.ToObject(), "count should be the returned page size"); + Assert.AreEqual(allNames.Count, pageResponse["total"]?.ToObject(), "total should be the match count before pagination"); + Assert.AreEqual(1, pageResponse["offset"]?.ToObject(), "offset should be echoed"); + Assert.AreEqual(2, pageResponse["limit"]?.ToObject(), "limit should be echoed"); + } + + [Test] + public async Task ApiCommands_PaginationInvalid_ReturnsBadRequest() + { + // Act / Assert - negative offset + var httpResponse = await m_PipelineClient.GetHttpAsync("/api/commands?offset=-1"); + var jsonContent = await httpResponse.Content.ReadAsStringAsync(); + Assert.AreEqual(400, (int)httpResponse.StatusCode, + $"negative offset should be rejected with 400. Response: {jsonContent}"); + StringAssert.Contains("offset", jsonContent, "error should name the offending parameter"); + + // Non-numeric limit + httpResponse = await m_PipelineClient.GetHttpAsync("/api/commands?limit=abc"); + jsonContent = await httpResponse.Content.ReadAsStringAsync(); + Assert.AreEqual(400, (int)httpResponse.StatusCode, + $"non-numeric limit should be rejected with 400. Response: {jsonContent}"); + StringAssert.Contains("limit", jsonContent, "error should name the offending parameter"); + } + + [Test] + public async Task ApiCommands_SortByPackage_OrdersByPackageThenName() + { + // Act + var httpResponse = await m_PipelineClient.GetHttpAsync("/api/commands?detail=compact&sort=package"); + var jsonContent = await httpResponse.Content.ReadAsStringAsync(); + + // Assert - ordered by originating package, ties broken by name + Assert.IsTrue(httpResponse.IsSuccessStatusCode, + $"sort=package should return success, got: {httpResponse.StatusCode}"); + var pairs = (JObject.Parse(jsonContent)["commands"] as JArray) + .Cast() + .Select(cmd => (Package: cmd["package"]?.ToString(), Name: cmd["name"]?.ToString())) + .ToList(); + var expected = pairs + .OrderBy(p => p.Package, System.StringComparer.Ordinal) + .ThenBy(p => p.Name, System.StringComparer.Ordinal) + .ToList(); + CollectionAssert.AreEqual(expected, pairs, + "sort=package should order by package with name as tiebreak"); + } + + [Test] + public async Task ApiCommands_OrderDesc_ReversesNameSort() + { + // Act + var httpResponse = await m_PipelineClient.GetHttpAsync("/api/commands?detail=compact&order=desc"); + var jsonContent = await httpResponse.Content.ReadAsStringAsync(); + + // Assert + Assert.IsTrue(httpResponse.IsSuccessStatusCode, + $"order=desc should return success, got: {httpResponse.StatusCode}"); + var names = (JObject.Parse(jsonContent)["commands"] as JArray) + .Cast().Select(cmd => cmd["name"]?.ToString()).ToList(); + CollectionAssert.AreEqual(names.OrderByDescending(n => n, System.StringComparer.Ordinal).ToList(), names, + "order=desc should reverse the default name sort"); + } + + [Test] + public async Task ApiCommands_SortInvalid_ReturnsBadRequestListingAcceptedValues() + { + // Act / Assert - unknown sort key + var httpResponse = await m_PipelineClient.GetHttpAsync("/api/commands?sort=alphabetical"); + var jsonContent = await httpResponse.Content.ReadAsStringAsync(); + Assert.AreEqual(400, (int)httpResponse.StatusCode, + $"Invalid sort value should be rejected with 400. Response: {jsonContent}"); + StringAssert.Contains("name", jsonContent, "error should list accepted value 'name'"); + StringAssert.Contains("package", jsonContent, "error should list accepted value 'package'"); + + // Unknown order direction + httpResponse = await m_PipelineClient.GetHttpAsync("/api/commands?order=upside_down"); + jsonContent = await httpResponse.Content.ReadAsStringAsync(); + Assert.AreEqual(400, (int)httpResponse.StatusCode, + $"Invalid order value should be rejected with 400. Response: {jsonContent}"); + StringAssert.Contains("asc", jsonContent, "error should list accepted value 'asc'"); + StringAssert.Contains("desc", jsonContent, "error should list accepted value 'desc'"); + } + + [Test] + public async Task ApiCommands_DetailFull_ReturnsFullMetadataWithTagsAndPackage() + { + // Act - detail=full opts into the complete per-command metadata + var httpResponse = await m_PipelineClient.GetHttpAsync("/api/commands?detail=full"); + var jsonContent = await httpResponse.Content.ReadAsStringAsync(); + + // Assert + Assert.IsTrue(httpResponse.IsSuccessStatusCode, + $"detail=full should return success, got: {httpResponse.StatusCode}"); + var commands = JObject.Parse(jsonContent)["commands"] as JArray; + var logEditor = commands.Cast() + .First(cmd => cmd["name"]?.ToString() == "log_editor"); + Assert.IsNotNull(logEditor["parameters"], "full detail should include parameters"); + Assert.IsNotNull(logEditor["schema"], "full detail should include schema"); + Assert.IsNotNull(logEditor["tags"], "full detail should include tags"); + Assert.AreEqual("Unity.Pipeline.Tests.Editor", logEditor["package"]?.ToString(), + "full detail should include the originating package"); + } + + [Test] + public async Task ApiCommands_InvalidDetail_ReturnsBadRequestListingAcceptedValues() + { + // Act - an unsupported detail value + var httpResponse = await m_PipelineClient.GetHttpAsync("/api/commands?detail=verbose"); + var jsonContent = await httpResponse.Content.ReadAsStringAsync(); + + // Assert - rejected with a clear error naming the accepted values + Assert.AreEqual(400, (int)httpResponse.StatusCode, + $"Invalid detail value should be rejected with 400. Response: {jsonContent}"); + var responseJson = JObject.Parse(jsonContent); + Assert.IsNotNull(responseJson["error"], "400 response should have error field"); + StringAssert.Contains("compact", jsonContent, "error should list accepted value 'compact'"); + StringAssert.Contains("full", jsonContent, "error should list accepted value 'full'"); + } + + [Test] + public async Task ApiCommands_CommandStructure_ContainsRequiredFields() + { + // Act - Call /api/commands endpoint using unified Pipeline client + var httpResponse = await m_PipelineClient.GetHttpAsync("/api/commands"); + var jsonContent = await httpResponse.Content.ReadAsStringAsync(); + var responseJson = JObject.Parse(jsonContent); + + // Assert - Command structure validation + var commands = responseJson["commands"] as JArray; + var firstCommand = commands[0] as JObject; + + // Required command fields + Assert.IsNotNull(firstCommand["name"], "Command should have name field"); + Assert.IsNotNull(firstCommand["description"], "Command should have description field"); + Assert.IsNotNull(firstCommand["parameters"], "Command should have parameters array"); + Assert.IsNotNull(firstCommand["schema"], "Command should have JSON schema"); + Assert.IsNotNull(firstCommand["mainThreadRequired"], "Command should have mainThreadRequired field"); + + // Verify schema is valid JSON + var schema = firstCommand["schema"]?.ToString(); + var schemaJson = JObject.Parse(schema); + Assert.AreEqual(firstCommand["name"]?.ToString(), schemaJson["title"]?.ToString(), + "Schema title should match command name"); + } + + [Test] + public async Task ApiStatus_GetBasicStatus_ReturnsServerInfo() + { + // Act - Call basic /api/status endpoint using unified Pipeline client + var httpResponse = await m_PipelineClient.GetHttpAsync("/api/status"); + var jsonContent = await httpResponse.Content.ReadAsStringAsync(); + + // Assert - Response structure + Assert.IsTrue(httpResponse.IsSuccessStatusCode, + $"Basic status endpoint should return success, got: {httpResponse.StatusCode}"); + Assert.AreEqual("application/json", httpResponse.Content.Headers.ContentType.MediaType, + "Basic status endpoint should return JSON content type"); + + // Assert - JSON structure (basic server info only, no Editor APIs) + var statusJson = JObject.Parse(jsonContent); + Assert.IsNotNull(statusJson["status"], "Should have status field"); + + // Verify basic values + Assert.AreEqual("ready", statusJson["status"]?.ToString()); + } + + [Test] + public async Task ApiEditorStatus_GetDetailedStatus_ReturnsEditorInfo() + { + // Act - Call rich /api/editor_status endpoint using unified Pipeline client + var httpResponse = await m_PipelineClient.GetHttpAsync("/api/editor_status"); + var jsonContent = await httpResponse.Content.ReadAsStringAsync(); + + // Assert - Response structure + Assert.IsTrue(httpResponse.IsSuccessStatusCode, + $"Editor status endpoint should return success, got: {httpResponse.StatusCode}. Response: {jsonContent}"); + Assert.AreEqual("application/json", httpResponse.Content.Headers.ContentType.MediaType, + "Editor status endpoint should return JSON content type"); + + // Assert - Rich Editor status structure + var statusJson = JObject.Parse(jsonContent); + Assert.IsNotNull(statusJson["status"], "Should have overall status"); + Assert.IsNotNull(statusJson["compiling"], "Should have compiling state"); + Assert.IsNotNull(statusJson["domainReloadInProgress"], "Should have domain reload state"); + Assert.IsNotNull(statusJson["playMode"], "Should have play mode state"); + Assert.IsNotNull(statusJson["unityVersion"], "Should have Unity version"); + + // Verify Editor-specific data is present + Assert.Contains(statusJson["status"]?.ToString(), new[] { "ready", "compiling", "playing", "reloading" }); + Assert.Contains(statusJson["playMode"]?.ToString(), new[] { "stopped", "playing", "paused" }); + Assert.IsInstanceOf(statusJson["compiling"]?.ToObject()); + } + + [Test] + public async Task ApiExec_PostCommand_ExecutesSuccessfully() + { + // Arrange + var commandRequest = new CommandExecutionRequest("log_editor"); + commandRequest.Parameters["message"] = "Test message from CLI"; + + // Act - Execute command via /api/exec endpoint using unified Pipeline client + var response = await m_PipelineClient.PostJsonAsync("/api/exec", commandRequest); + var responseContent = response.RawResponse; + + // Assert - Response structure + Assert.IsTrue(response.IsSuccess, + $"Exec endpoint should return success, got: {response.StatusCode}. Response: {responseContent}"); + + // Assert - JSON parsing and structure + Assert.IsTrue(response.HasValidJson, "Response should have valid JSON"); + var responseJson = response.JsonResponse; + + // Lean default (AUTHAPI-21): a success is just success + result. The always-on metadata + // (command, executedAt, executionTimeMs) is dropped unless the request opts into verbose. + Assert.IsNotNull(responseJson["success"], "Response should have success field"); + Assert.IsTrue(responseJson["success"].ToObject(), "Command should execute successfully"); + Assert.IsNull(responseJson["command"], "Lean envelope should omit the command echo"); + Assert.IsNull(responseJson["executedAt"], "Lean envelope should omit executedAt"); + Assert.IsNull(responseJson["executionTimeMs"], "Lean envelope should omit executionTimeMs"); + } + + [Test] + public async Task ApiExec_VerboseFlag_IncludesEnvelopeMetadata() + { + // Arrange - opt into the full envelope via the request's verbose flag. + var commandRequest = new CommandExecutionRequest("log_editor") { Verbose = true }; + commandRequest.Parameters["message"] = "Test message from CLI"; + + // Act + var response = await m_PipelineClient.PostJsonAsync("/api/exec", commandRequest); + + // Assert - the metadata the lean envelope drops is present again. + Assert.IsTrue(response.IsSuccess, + $"Exec endpoint should return success, got: {response.StatusCode}. Response: {response.RawResponse}"); + var responseJson = response.JsonResponse; + Assert.IsTrue(responseJson["success"].ToObject(), "Command should execute successfully"); + Assert.IsNotNull(responseJson["command"], "Verbose envelope should include the command"); + Assert.AreEqual("log_editor", responseJson["command"]?.ToString()); + Assert.IsNotNull(responseJson["executedAt"], "Verbose envelope should include executedAt"); + } + + [Test] + public async Task ApiExec_OmitNullsFlag_AcceptedEndToEnd() + { + // The payload-null semantics themselves are pinned at the serializer level + // (ResponseEnvelopeSizeTests); this covers the HTTP wiring: the request flag + // deserializes and the reply still parses. + var request = new CommandExecutionRequest("log_editor") { OmitNulls = true }; + request.Parameters["message"] = "omitNulls round-trip"; + + var response = await m_PipelineClient.PostJsonAsync("/api/exec", request); + + Assert.IsTrue(response.IsSuccess, + $"Exec with omitNulls should succeed, got: {response.StatusCode}. Response: {response.RawResponse}"); + Assert.IsTrue(response.JsonResponse["success"].ToObject()); + } + + [Test] + public async Task ApiExec_ValidationFailure_HonorsVerboseFlag() + { + // A post-parse validation failure (structurally valid JSON, invalid content) can and + // must honor the request's verbose flag — that's precisely when a debugging client + // wants the full envelope. Pre-parse failures (unparseable JSON) can't, by definition. + var verboseResponse = await m_PipelineClient.PostJsonAsync("/api/exec", + new { command = "log_editor", timeout = -1, verbose = true }); + var leanResponse = await m_PipelineClient.PostJsonAsync("/api/exec", + new { command = "log_editor", timeout = -1 }); + + Assert.AreEqual(400, verboseResponse.StatusCode, "Invalid timeout should be rejected"); + Assert.IsNotNull(verboseResponse.JsonResponse["executedAt"], + "A verbose request's validation failure should carry the full envelope"); + + Assert.AreEqual(400, leanResponse.StatusCode, "Invalid timeout should be rejected"); + Assert.IsNull(leanResponse.JsonResponse["executedAt"], + "A lean request's validation failure should stay lean"); + } + + [Test] + public async Task ApiExec_NullJsonBody_Returns400InvalidRequest() + { + // A body of literal JSON "null" parses without a JsonException but deserializes to a + // null request — it must be rejected cleanly, not NRE inside the handler. + var response = await m_PipelineClient.PostJsonAsync("/api/exec", null); + + Assert.AreEqual(400, response.StatusCode, + $"A null JSON body should be rejected with 400. Response: {response.RawResponse}"); + Assert.IsTrue(response.HasValidJson, "The rejection should be a structured JSON reply"); + Assert.AreEqual("Invalid Request", response.JsonResponse["error"]?.ToString()); + StringAssert.Contains("JSON object", response.JsonResponse["errorDetails"]?.ToString()); + } + + [Test] + public async Task ApiExec_InvalidCommand_ReturnsError() + { + // Arrange + var invalidRequest = new CommandExecutionRequest("nonexistent_command"); + + // Act - Execute invalid command via /api/exec endpoint using unified Pipeline client + var response = await m_PipelineClient.PostJsonAsync("/api/exec", invalidRequest); + var responseContent = response.RawResponse; + + LogAssert.Expect(new Regex("^ExecuteCommandByName: No command named")); + + // Assert - Should return error + Assert.IsFalse(response.IsSuccess, "Should return error for invalid command"); + + Assert.IsTrue(response.HasValidJson, "Error response should have valid JSON"); + var responseJson = response.JsonResponse; + Assert.IsNotNull(responseJson["error"], "Error response should have error field"); + // A failure has no `message` (that's for success), so the lean envelope omits it; assert on + // the fields a failure actually carries instead. (AUTHAPI-21) + Assert.IsFalse(responseJson["success"].ToObject(), "Error response should report success=false"); + } + + [Test] + public async Task ApiExec_MissingRequiredParameter_ReturnsValidationError() + { + // Arrange - Try to execute log_editor without required message parameter + var invalidRequest = new CommandExecutionRequest("log_editor"); + // Intentionally not setting the 'message' parameter to test validation + + // Act - Execute command with missing parameter via /api/exec endpoint using unified Pipeline client + var response = await m_PipelineClient.PostJsonAsync("/api/exec", invalidRequest); + var responseContent = response.RawResponse; + + LogAssert.Expect("ExecuteCommandByName: Parameter validation failed: Required parameter 'message' is missing or empty"); + + // Assert - Should return validation error + Assert.IsFalse(response.IsSuccess, "Should return error for missing required parameter"); + + Assert.IsTrue(response.HasValidJson, "Error response should have valid JSON"); + var responseJson = response.JsonResponse; + Assert.IsNotNull(responseJson["error"], "Should have error field"); + Assert.That(responseJson["errorDetails"]?.ToString(), + Contains.Substring("message").IgnoreCase, + "Error should mention missing message parameter"); + } + + [Test] + public async Task ApiExec_OversizedBody_ReturnsPayloadTooLarge() + { + // Arrange - a request whose body exceeds the 1 MiB cap (Content-Length will advertise it). + var oversized = new CommandExecutionRequest("log_editor"); + oversized.Parameters["message"] = new string('a', (1 * 1024 * 1024) + 1024); + + // Act + var response = await m_PipelineClient.PostJsonAsync("/api/exec", oversized); + + // Assert - rejected with 413 before the command ever runs. + Assert.AreEqual(413, response.StatusCode, + $"Oversized body should be rejected with 413. Response: {response.RawResponse}"); + Assert.IsTrue(response.HasValidJson, "413 response should have valid JSON"); + Assert.That(response.JsonResponse["error"]?.ToString(), + Contains.Substring("Payload Too Large"), + "413 response should identify the payload-too-large error"); + } + + [Test] + public async Task ApiExec_UnconvertibleParameter_ReturnsErrorInsteadOfSubstitutingDefault() + { + // Arrange - 'tail' is an int defaulting to 100. Falling back to that default would + // hand the caller far more entries than it asked for, with no way to detect it. + var request = new CommandExecutionRequest("console"); + request.Parameters["tail"] = "not-a-number"; + + // Act + var response = await m_PipelineClient.PostJsonAsync("/api/exec", request); + + LogAssert.Expect(new Regex("^ExecuteCommandByName: Parameter conversion failed: Parameter 'tail'")); + + // Assert - pin the HTTP contract, not just "some failure": without the status and + // category, a regression to the command-execution handler would still pass. + Assert.IsFalse(response.IsSuccess, "Unconvertible argument should not report success"); + Assert.AreEqual(400, response.StatusCode, + $"Unconvertible argument should be a 400, not another failure class. Response: {response.RawResponse}"); + Assert.IsTrue(response.HasValidJson, "Error response should have valid JSON"); + + var responseJson = response.JsonResponse; + Assert.AreEqual("Parameter Validation Failed", responseJson["error"]?.ToString(), + "Should be classified as a parameter validation failure"); + Assert.That(responseJson["errorDetails"]?.ToString(), + Contains.Substring("tail"), + "Error should name the offending parameter"); + Assert.That(responseJson["errorDetails"]?.ToString(), + Contains.Substring("Int32"), + "Error should name the type the value could not be converted to"); + } + + [Test] + public async Task ApiExec_NumericStringParameter_IsConvertedAndApplied() + { + // Arrange - a numeric *string* is what MCP clients send today, since the tool schema + // advertises numeric params as strings. Seed more entries than the limit asked for: + // asserting success alone would pass even if "5" were dropped for the default of 100, + // so the count is what proves the value was applied. + for (var i = 0; i < 12; i++) + { + UnityEngine.Debug.Log($"CLI978_numeric_string_seed_{i}"); + } + + var request = new CommandExecutionRequest("console"); + request.Parameters["tail"] = "5"; + + // Act + var response = await m_PipelineClient.PostJsonAsync("/api/exec", request); + + // Assert + Assert.IsTrue(response.IsSuccess, + $"A parseable numeric string should still be accepted. Response: {response.RawResponse}"); + Assert.AreEqual(5, ReadReturnedCount(response.JsonResponse), + "tail=\"5\" must be honoured, not replaced by the command's default"); + } + + /// + /// Reads result.returned from an /api/exec envelope. The envelope carries `result` + /// either as a nested object or as a JSON string depending on the command, so handle both. + /// + private static int ReadReturnedCount(JObject responseJson) + { + var result = responseJson["result"]; + if (result is JValue { Type: JTokenType.String } stringResult) + { + result = JToken.Parse(stringResult.Value()); + } + + var returned = result?["returned"]; + Assert.IsNotNull(returned, $"Response should carry result.returned: {responseJson}"); + return returned.ToObject(); + } + + [Test] + public async Task ApiExec_ConverterDeclinedToken_IsRejectedNotTreatedAsOmitted() + { + // ObjectRefConverter returns null for an unsupported token kind instead of throwing, so + // {"parent": true} used to read as an omitted argument and create_gameobject ran with + // parent == null — creating the object at the scene root rather than rejecting the + // malformed handle. A declined token must be a conversion error, not a silent default. + var request = new CommandExecutionRequest("create_gameobject"); + request.Parameters["name"] = "CLI978_should_not_be_created"; + request.Parameters["parent"] = true; + + var response = await m_PipelineClient.PostJsonAsync("/api/exec", request); + + LogAssert.Expect(new Regex("^ExecuteCommandByName: Parameter conversion failed: Parameter 'parent'")); + + Assert.IsFalse(response.IsSuccess, "A declined token should not succeed"); + Assert.AreEqual(400, response.StatusCode, + $"Should be a parameter-validation 400. Response: {response.RawResponse}"); + Assert.AreEqual("Parameter Validation Failed", response.JsonResponse["error"]?.ToString()); + Assert.That(response.JsonResponse["errorDetails"]?.ToString(), + Contains.Substring("parent"), "Error should name the offending parameter"); + Assert.That(response.JsonResponse["errorDetails"]?.ToString(), + Contains.Substring("ObjectRef"), "Error should name the target type"); + } + + [Test] + public async Task ApiExec_ExplicitJsonNull_IsStillAcceptedAsAValue() + { + // The guard above must not catch a legitimately null optional argument: an explicit JSON + // null is the one value allowed to convert to null, and it falls back to the default. + var request = new CommandExecutionRequest("console"); + request.Parameters["level"] = null; + request.Parameters["tail"] = 5; + + var response = await m_PipelineClient.PostJsonAsync("/api/exec", request); + + Assert.IsTrue(response.IsSuccess, + $"An explicit JSON null should remain acceptable. Response: {response.RawResponse}"); + Assert.IsTrue(response.JsonResponse["success"].ToObject(), "Command should succeed"); + } + + [Test] + public async Task ApiExec_EmptyObjectRefString_IsAcceptedNotRejectedAsUnconvertible() + { + // An empty ObjectRef string is a documented value, not a malformed one: + // ObjectRefConverter.FromString returns null for it and set_parent advertises + // "Omit (or empty) to move the object to the scene root". The declined-token guard must + // not reject it. Uses a target that cannot resolve, so this asserts parameter BINDING + // without reparenting anything: the call still fails, but not as a validation failure. + var request = new CommandExecutionRequest("set_parent"); + request.Parameters["target"] = "/CLI978_no_such_object"; + request.Parameters["parent"] = ""; + + var response = await m_PipelineClient.PostJsonAsync("/api/exec", request); + + // The command runs and fails at target resolution — which is itself the proof that + // `parent` bound. That failure logs an error, so it has to be declared. + LogAssert.Expect(new Regex("Could not resolve 'target'")); + + // The error CATEGORY is not the discriminator here: set_parent's own resolve failure + // also throws ArgumentException, so it lands in "Parameter Validation Failed" too. What + // separates binding from execution is the detail text. + Assert.IsFalse(response.IsSuccess, "An unresolvable target should still fail"); + Assert.That(response.JsonResponse["errorDetails"]?.ToString() ?? string.Empty, + Does.Not.Contain("could not be converted"), + $"An empty ObjectRef string must bind, not be rejected as unconvertible. Response: {response.RawResponse}"); + Assert.That(response.JsonResponse["errorDetails"]?.ToString() ?? string.Empty, + Contains.Substring("Could not resolve 'target'"), + "The failure must come from the command body, proving 'parent' bound"); + } + + // ------------------------------------------------------------- raw command-line forms + // {"argv":[...]} and {"commandLine":"..."}. The server + // tokenizes/binds, so a client needs no schema knowledge and spends one request + // instead of two. + + [Test] + public async Task ApiExec_ArgvForm_ExecutesTheCommand() + { + var response = await m_PipelineClient.PostJsonAsync("/api/exec", + new { argv = new[] { "test_types", "--count", "5" } }); + + Assert.AreEqual(200, response.StatusCode, $"Response: {response.RawResponse}"); + Assert.IsTrue(response.IsCommandSuccess, $"Response: {response.RawResponse}"); + } + + [Test] + public async Task ApiExec_CommandLineForm_ExecutesTheCommand() + { + var response = await m_PipelineClient.PostJsonAsync("/api/exec", + new { commandLine = "test_types --count 5" }); + + Assert.AreEqual(200, response.StatusCode, $"Response: {response.RawResponse}"); + Assert.IsTrue(response.IsCommandSuccess, $"Response: {response.RawResponse}"); + } + + [Test] + public async Task ApiExec_RawForm_EchoesTheBoundParameters() + { + // The CLI renders this in four output formats; without the echo it has nothing + // to show, because it no longer binds client-side. + var response = await m_PipelineClient.PostJsonAsync("/api/exec", + new { argv = new[] { "test_types", "--count", "5" } }); + + var echoed = response.JsonResponse["parameters"] as JObject; + Assert.IsNotNull(echoed, $"argv requests must echo bound parameters. Response: {response.RawResponse}"); + Assert.AreEqual("5", echoed["count"]?.ToString()); + } + + [Test] + public async Task ApiExec_StructuredForm_DoesNotEchoParameters() + { + // Back-compat: the structured path's envelope must not grow a key. + var request = new CommandExecutionRequest("test_types"); + request.Parameters["count"] = 5; + + var response = await m_PipelineClient.PostJsonAsync("/api/exec", request); + + Assert.IsNull(response.JsonResponse["parameters"], + $"structured requests must be byte-identical to before. Response: {response.RawResponse}"); + } + + [Test] + public async Task ApiExec_ArgvWithSpacesInAToken_IsNotRetokenized() + { + // argv is already split; re-splitting it would corrupt any value containing a space. + var response = await m_PipelineClient.PostJsonAsync("/api/exec", + new { argv = new[] { "log_editor", "hello world" } }); + + var echoed = response.JsonResponse["parameters"] as JObject; + Assert.IsNotNull(echoed, $"Response: {response.RawResponse}"); + Assert.AreEqual("hello world", echoed["message"]?.ToString()); + } + + [Test] + public async Task ApiExec_CommandLineQuoting_GroupsIntoOneToken() + { + var response = await m_PipelineClient.PostJsonAsync("/api/exec", + new { commandLine = "log_editor \"hello world\"" }); + + var echoed = response.JsonResponse["parameters"] as JObject; + Assert.IsNotNull(echoed, $"Response: {response.RawResponse}"); + Assert.AreEqual("hello world", echoed["message"]?.ToString()); + } + + // ------------------------------------------------------------------ mutual exclusion + + [Test] + public async Task ApiExec_CommandAndArgvTogether_IsRejected() + { + var response = await m_PipelineClient.PostJsonAsync("/api/exec", + new { command = "test_types", argv = new[] { "test_types" } }); + + Assert.AreEqual(400, response.StatusCode, $"Response: {response.RawResponse}"); + } + + [Test] + public async Task ApiExec_ArgvAndCommandLineTogether_IsRejected() + { + var response = await m_PipelineClient.PostJsonAsync("/api/exec", + new { argv = new[] { "test_types" }, commandLine = "test_types" }); + + Assert.AreEqual(400, response.StatusCode, $"Response: {response.RawResponse}"); + } + + [Test] + public async Task ApiExec_ParametersAlongsideArgv_IsRejectedNotIgnored() + { + // Silently dropping the payload would recreate exactly the absent-vs-null + // ambiguity this codebase legislates against in the lean envelope. + var response = await m_PipelineClient.PostJsonAsync("/api/exec", + new { argv = new[] { "test_types" }, parameters = new { count = 5 } }); + + Assert.AreEqual(400, response.StatusCode, $"Response: {response.RawResponse}"); + } + + [Test] + public async Task ApiExec_EmptyArgv_IsRejected() + { + var response = await m_PipelineClient.PostJsonAsync("/api/exec", + new { argv = new string[0] }); + + Assert.AreEqual(400, response.StatusCode, $"Response: {response.RawResponse}"); + } + + [Test] + public async Task ApiExec_BlankCommandLine_IsRejected() + { + var response = await m_PipelineClient.PostJsonAsync("/api/exec", + new { commandLine = " " }); + + Assert.AreEqual(400, response.StatusCode, $"Response: {response.RawResponse}"); + } + + // ------------------------------------------------------------------ argument errors + + [Test] + public async Task ApiExec_UnknownFlag_ReturnsInvalidCommandArgsWithProblemsAndSchema() + { + var response = await m_PipelineClient.PostJsonAsync("/api/exec", + new { argv = new[] { "log_editor", "--mesage", "hi" } }); + + Assert.AreEqual(400, response.StatusCode, $"Response: {response.RawResponse}"); + + var json = response.JsonResponse; + Assert.AreEqual("INVALID_COMMAND_ARGS", json["errorCode"]?.ToString(), + "errorCode is the discriminator; every /api/exec failure is already 400"); + + var problems = json["argProblems"] as JArray; + Assert.IsNotNull(problems, $"Response: {response.RawResponse}"); + Assert.AreEqual(1, problems.Count); + Assert.AreEqual("unknownName", problems[0]["kind"]?.ToString(), + "kind is camelCase on the wire even though C# spells it PascalCase"); + Assert.AreEqual("mesage", problems[0]["name"]?.ToString()); + Assert.AreEqual("message", problems[0]["suggestion"]?.ToString()); + + // Replaces the retired per-exec schema fetch: shaped like a /api/commands entry + // so the CLI's existing renderer consumes it with no new code. + var schema = json["commandSchema"] as JObject; + Assert.IsNotNull(schema, "an argument error must carry the command's schema"); + Assert.AreEqual("log_editor", schema["name"]?.ToString()); + Assert.IsNotNull(schema["parameters"] as JArray); + } + + [Test] + public async Task ApiExec_TypeMismatch_ReturnsTypeMismatchProblem() + { + var response = await m_PipelineClient.PostJsonAsync("/api/exec", + new { argv = new[] { "test_types", "--count", "abc" } }); + + Assert.AreEqual(400, response.StatusCode, $"Response: {response.RawResponse}"); + + var problems = response.JsonResponse["argProblems"] as JArray; + Assert.IsNotNull(problems, $"Response: {response.RawResponse}"); + Assert.AreEqual("typeMismatch", problems[0]["kind"]?.ToString()); + Assert.AreEqual("Int32", problems[0]["expectedType"]?.ToString()); + } + + [Test] + public async Task ApiExec_UnbalancedQuoteInCommandLine_IsRejected() + { + var response = await m_PipelineClient.PostJsonAsync("/api/exec", + new { commandLine = "log_editor \"unbalanced" }); + + Assert.AreEqual(400, response.StatusCode, $"Response: {response.RawResponse}"); + Assert.That(response.JsonResponse["errorDetails"]?.ToString(), + Contains.Substring("quote").IgnoreCase); + } + + [Test] + public async Task ApiExec_ATokenizerFailure_IsAnInvalidRequestWithNoErrorCode() + { + // A command line that will not tokenize never reached a command, so it is a malformed + // request shape - the same family as two command forms at once. Reporting it as + // INVALID_COMMAND_ARGS promised an argument diagnosis the reply cannot carry: there is + // no commandSchema and no argProblems, because there is no command. A client keying on + // errorCode to render usage found nothing to render. + var response = await m_PipelineClient.PostJsonAsync("/api/exec", + new { commandLine = "log_editor \"unbalanced" }); + + Assert.AreEqual(400, response.StatusCode, $"Response: {response.RawResponse}"); + Assert.AreEqual("Invalid Request", response.JsonResponse["error"]?.ToString()); + Assert.IsNull(response.JsonResponse["errorCode"], + "no command was resolved, so the argument-error discriminator must be absent"); + Assert.IsNull(response.JsonResponse["commandSchema"]); + Assert.IsNull(response.JsonResponse["argProblems"]); + } + + [Test] + public async Task ApiExec_ARequestWithNoCommandForm_IsAnInvalidRequest() + { + // Relaxing `command` from Required.Always (so the raw forms may omit it) moved this + // case out of JSON.NET's deserializer and into Validate(). Both answer 400, but the + // `error` value changed from "Invalid JSON" to "Invalid Request" - pinned here so the + // wording is a decision rather than a side effect. + var response = await m_PipelineClient.PostJsonAsync("/api/exec", new { }); + + Assert.AreEqual(400, response.StatusCode, $"Response: {response.RawResponse}"); + Assert.AreEqual("Invalid Request", response.JsonResponse["error"]?.ToString()); + Assert.AreEqual("Command name is required", + response.JsonResponse["errorDetails"]?.ToString()); + Assert.IsNull(response.JsonResponse["errorCode"]); + } + + [Test] + public async Task ApiExec_ArgumentErrorSchema_MatchesTheCatalogEntryWithoutTheGeneratedSchema() + { + // commandSchema is the /api/commands entry minus the generated JSON schema, and it is + // built without generating that schema at all. Pinning both halves keeps the shape + // from drifting when the wasteful generate-then-discard is removed. + var error = await m_PipelineClient.PostJsonAsync("/api/exec", + new { argv = new[] { "log_editor", "--mesage", "hi" } }); + Assert.AreEqual(400, error.StatusCode, $"Response: {error.RawResponse}"); + + var entry = error.JsonResponse["commandSchema"] as JObject; + Assert.IsNotNull(entry, $"Response: {error.RawResponse}"); + Assert.IsNull(entry["schema"], "the generated schema must not ride along on an error"); + + var catalogHttp = await m_PipelineClient.GetHttpAsync("/api/commands"); + var catalog = JObject.Parse(await catalogHttp.Content.ReadAsStringAsync()); + var served = (catalog["commands"] as JArray) + ?.FirstOrDefault(c => c["name"]?.ToString() == "log_editor") as JObject; + Assert.IsNotNull(served, "log_editor must be in the catalog"); + Assert.IsNotNull(served["schema"], "/api/commands still carries the generated schema"); + + foreach (var property in served.Properties()) + { + if (property.Name == "schema") + continue; + Assert.IsTrue(JToken.DeepEquals(property.Value, entry[property.Name]), + $"commandSchema.{property.Name} must match the catalog entry verbatim"); + } + + Assert.AreEqual(served.Properties().Count() - 1, entry.Properties().Count(), + "commandSchema must carry every catalog property except the generated schema"); + } + + [Test] + public async Task ApiExec_UnknownCommandViaArgv_MatchesTheStructuredEnvelope() + { + // Both calls log the same registry error; expect one per call. + LogAssert.Expect(new Regex("^ExecuteCommandByName: No command named")); + LogAssert.Expect(new Regex("^ExecuteCommandByName: No command named")); + + var viaArgv = await m_PipelineClient.PostJsonAsync("/api/exec", + new { argv = new[] { "no_such_command_xyz" } }); + var viaStructured = await m_PipelineClient.PostJsonAsync("/api/exec", + new CommandExecutionRequest("no_such_command_xyz")); + + Assert.AreEqual(viaStructured.StatusCode, viaArgv.StatusCode); + Assert.AreEqual(viaStructured.JsonResponse["error"]?.ToString(), + viaArgv.JsonResponse["error"]?.ToString(), + "an unknown raw command name must produce the identical Command Not Found envelope"); + } + + [Test] + public async Task ApiExec_MissingRequiredParameterViaArgv_IsRejectedBeforeExecution() + { + // A raw form is validated up front, so it never reaches ExecuteCommandByName and + // therefore logs no execution error. Message parity with the structured form is + // asserted directly by + // ApiExec_RawFormMissingRequiredParameter_ReportsTheSameMessageInBothForms, which is + // a stronger check than the log line this used to expect. + var response = await m_PipelineClient.PostJsonAsync("/api/exec", + new { argv = new[] { "log_editor" } }); + + Assert.AreEqual(400, response.StatusCode, $"Response: {response.RawResponse}"); + Assert.AreEqual("Parameter Validation Failed", response.JsonResponse["error"]?.ToString()); + Assert.That(response.JsonResponse["errorDetails"]?.ToString(), + Contains.Substring("message").IgnoreCase); + } + + [Test] + public async Task ApiExec_RawFormFailure_HonorsVerboseFlag() + { + // Reply-shape flags are captured before the raw-form branch, so a malformed + // command line still honours them. + var lean = await m_PipelineClient.PostJsonAsync("/api/exec", + new { argv = new[] { "log_editor", "--mesage", "hi" } }); + var verbose = await m_PipelineClient.PostJsonAsync("/api/exec", + new { argv = new[] { "log_editor", "--mesage", "hi" }, verbose = true }); + + Assert.AreEqual(400, lean.StatusCode); + Assert.AreEqual(400, verbose.StatusCode); + Assert.IsNull(lean.JsonResponse["executedAt"], "lean mode drops envelope metadata"); + Assert.IsNotNull(verbose.JsonResponse["executedAt"], "verbose mode restores it"); + } + + [Test] + public async Task ApiExec_JobWithCommandLine_ReturnsAJobId() + { + // RunJobDetached re-reads the request object, so normalizing in place means the + // detached path needs no changes of its own. + var response = await m_PipelineClient.PostJsonAsync("/api/exec", + new { commandLine = "test_types --count 5", job = true }); + + Assert.AreEqual(200, response.StatusCode, $"Response: {response.RawResponse}"); + var result = response.JsonResponse["result"] as JObject; + Assert.IsNotNull(result?["jobId"] ?? result?["id"], + $"detached submission should return a job id. Response: {response.RawResponse}"); + } + + [Test] + public async Task ApiStatus_AdvertisesTheRawFormCapabilities() + { + // Capability negotiation exists so a CLI can tell "this server predates argv" from + // "your request was malformed" WITHOUT a probe request -- an old server answers an + // argv request with a bare Invalid JSON, which the CLI would otherwise render as + // exit 6 plus "Run `unity bug`", i.e. version skew reading as a CLI defect. + var response = await m_PipelineClient.GetAsync("/api/status"); + + var capabilities = response.JsonResponse?["capabilities"] as JArray; + Assert.IsNotNull(capabilities, $"/api/status must advertise capabilities. Response: {response.RawResponse}"); + + var tokens = capabilities.Select(t => t.ToString()).ToList(); + CollectionAssert.Contains(tokens, "exec.argv"); + CollectionAssert.Contains(tokens, "exec.commandLine"); + } + + [Test] + public void ServerCapabilities_AreASingleSharedSource() + { + // The descriptor and /api/status must not be able to drift: one array feeds both. + CollectionAssert.Contains(BasePipelineServer.Capabilities, "exec.argv"); + CollectionAssert.Contains(BasePipelineServer.Capabilities, "exec.commandLine"); + } + + [Test] + public async Task ApiExec_RawFormMissingRequiredParameter_NeverCreatesAJob() + { + // A deterministically invalid submission must not be acknowledged with a job id. + // Binding SUCCEEDS here -- a missing required parameter is not a binder problem, it is + // ValidateCommandParameters' job -- so without a preflight this reached job creation, + // returned 200 plus an id, and only failed later inside the detached run. A client + // polling that id learns minutes later what was knowable up front. + var response = await m_PipelineClient.PostJsonAsync("/api/exec", + new { argv = new[] { "log_editor" }, job = true }); + + Assert.AreEqual(400, response.StatusCode, $"Response: {response.RawResponse}"); + Assert.IsNull(response.JsonResponse["result"], "no job id for a known-invalid submission"); + Assert.That(response.JsonResponse["errorDetails"]?.ToString(), + Contains.Substring("message").IgnoreCase); + } + + [Test] + public async Task ApiExec_RawFormMissingRequiredParameter_ReportsTheSameMessageInBothForms() + { + // The preflight must reproduce ValidateCommandParameters' wording exactly, or the two + // request forms would diagnose the same mistake differently. + LogAssert.Expect("ExecuteCommandByName: Parameter validation failed: Required parameter 'message' is missing or empty"); + + var viaArgv = await m_PipelineClient.PostJsonAsync("/api/exec", + new { argv = new[] { "log_editor" } }); + var viaStructured = await m_PipelineClient.PostJsonAsync("/api/exec", + new CommandExecutionRequest("log_editor")); + + Assert.AreEqual(400, viaArgv.StatusCode); + Assert.AreEqual(400, viaStructured.StatusCode); + Assert.AreEqual( + viaStructured.JsonResponse["error"]?.ToString(), + viaArgv.JsonResponse["error"]?.ToString()); + Assert.AreEqual( + viaStructured.JsonResponse["errorDetails"]?.ToString(), + viaArgv.JsonResponse["errorDetails"]?.ToString(), + "both forms must report the identical validation message"); + } + + [Test] + public async Task ApiExec_CommandLineWithAnEmptyFirstToken_IsAnInvalidRequest() + { + // `"" --message hi` is a NONBLANK source string, so Validate() passes, but it + // tokenizes to an empty first token. Left unchecked it became a Command Not Found, + // telling the caller an empty command is merely unavailable. The argv equivalent is + // already rejected as a bad request, so the two raw forms must agree. + var response = await m_PipelineClient.PostJsonAsync("/api/exec", + new { commandLine = "\"\" --message hi" }); + + Assert.AreEqual(400, response.StatusCode, $"Response: {response.RawResponse}"); + Assert.AreEqual("Invalid Request", response.JsonResponse["error"]?.ToString(), + "an empty command name is a malformed request, not a missing command"); + } + + [Test] + public async Task ApiExec_CommandLineWithAWhitespaceFirstToken_IsAlsoRejected() + { + var response = await m_PipelineClient.PostJsonAsync("/api/exec", + new { commandLine = "\" \" --message hi" }); + + Assert.AreEqual(400, response.StatusCode, $"Response: {response.RawResponse}"); + Assert.AreEqual("Invalid Request", response.JsonResponse["error"]?.ToString()); + } + + [Test] + public async Task ApiExec_MalformedArgumentsNeverCreateAJob() + { + // A mistyped parameter must not return a job id and exit 0. + var response = await m_PipelineClient.PostJsonAsync("/api/exec", + new { argv = new[] { "log_editor", "--mesage", "hi" }, job = true }); + + Assert.AreEqual(400, response.StatusCode, $"Response: {response.RawResponse}"); + Assert.IsNull(response.JsonResponse["result"], "no job id for a malformed command line"); + } + } +} \ No newline at end of file diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/ApiEndpointsTests.cs.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/ApiEndpointsTests.cs.meta new file mode 100644 index 0000000..1df8478 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/ApiEndpointsTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fddeee399ff1c104d82a62adbac36d43 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets.meta new file mode 100644 index 0000000..5b478aa --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7571005014bc4727a0ef06b2056351a2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/AssetCommandsTests.cs b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/AssetCommandsTests.cs new file mode 100644 index 0000000..69412f5 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/AssetCommandsTests.cs @@ -0,0 +1,246 @@ +using System.Text.RegularExpressions; +using NUnit.Framework; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Editor.Commands.Assets; +using Unity.Pipeline.Models; +using UnityEditor; +using UnityEngine; +using UnityEngine.TestTools; + +namespace Unity.Pipeline.Tests.Editor.Assets +{ + /// + /// A trivial ScriptableObject used by the asset-command tests to exercise create / find / move / + /// delete with a real, project-resolvable type. + /// + class CLI191SampleAsset : ScriptableObject + { + public int Value; + } + + /// + /// Tests for the CLI-191 asset lifecycle commands, exercised both directly (static method) and via + /// the isolated . Covers the acceptance flow (create folder tree → + /// create ScriptableObject → find by type → move → delete), the sandbox guard (out-of-project + /// writes rejected), and the destructive guard (delete without confirm rejected). + /// + class AssetCommandsTests + { + private const string Root = "Assets/__CLI191Test"; + + [TearDown] + public void TearDown() + { + ProjectPaths.ResetAuthoringRoot(); + if (AssetDatabase.IsValidFolder(Root)) + { + AssetDatabase.DeleteAsset(Root); + AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport); + } + } + + private static ObjectRef PathRef(string path) => new ObjectRef { Path = path }; + + #region Direct + + [Test] + public void CreateAsset_ScriptableObject_CreatesAssetAndReturnsIdentity() + { + var path = Root + "/Data/Sample.asset"; + var result = AssetCommands.CreateAsset(path, typeof(CLI191SampleAsset).FullName); + + Assert.AreEqual(path, result.AssetPath); + Assert.IsNotEmpty(result.Guid, "Created asset should have a GUID"); + Assert.IsNotNull(AssetDatabase.LoadAssetAtPath(path), "Asset should exist on disk"); + } + + [Test] + public void CreateAsset_OverwriteWithoutConfirm_Throws() + { + var path = Root + "/Data/Dup.asset"; + AssetCommands.CreateAsset(path, typeof(CLI191SampleAsset).FullName); + + Assert.Throws( + () => AssetCommands.CreateAsset(path, typeof(CLI191SampleAsset).FullName), + "Overwriting an existing asset without confirm should be rejected"); + + // With confirm it succeeds. + var result = AssetCommands.CreateAsset(path, typeof(CLI191SampleAsset).FullName, confirm: true); + Assert.AreEqual(path, result.AssetPath); + } + + [Test] + public void CreateAsset_OutOfProject_Throws() + { + Assert.Throws( + () => AssetCommands.CreateAsset("../Outside.asset", typeof(CLI191SampleAsset).FullName)); + Assert.Throws( + () => AssetCommands.CreateAsset("Assets/../Outside.asset", typeof(CLI191SampleAsset).FullName)); + } + + [Test] + public void FindAssets_ByType_FindsCreatedAsset() + { + var path = Root + "/Find/Target.asset"; + AssetCommands.CreateAsset(path, typeof(CLI191SampleAsset).FullName); + + var found = AssetCommands.FindAssets(type: nameof(CLI191SampleAsset), searchIn: Root); + + Assert.GreaterOrEqual(found.Count, 1, "Should find the created asset by type"); + CollectionAssert.Contains( + System.Linq.Enumerable.Select(found.Assets, a => a.AssetPath), + path); + } + + [Test] + public void FindAssets_NoFilter_Throws() + { + Assert.Throws(() => AssetCommands.FindAssets()); + } + + [Test] + public void MoveAsset_RelocatesAndPreservesGuid() + { + var src = Root + "/Move/Src.asset"; + AssetCommands.CreateAsset(src, typeof(CLI191SampleAsset).FullName); + var srcGuid = AssetDatabase.AssetPathToGUID(src); + + var dest = Root + "/Move/Dest/Moved.asset"; + var result = AssetCommands.MoveAsset(PathRef(src), dest); + + Assert.AreEqual(dest, result.AssetPath); + Assert.IsNull(AssetDatabase.LoadMainAssetAtPath(src), "Source should no longer exist"); + Assert.AreEqual(srcGuid, AssetDatabase.AssetPathToGUID(dest), "GUID should be preserved across a move"); + } + + [Test] + public void CopyAsset_CreatesDistinctAsset() + { + var src = Root + "/Copy/Src.asset"; + AssetCommands.CreateAsset(src, typeof(CLI191SampleAsset).FullName); + + var dest = Root + "/Copy/Copy.asset"; + var result = AssetCommands.CopyAsset(PathRef(src), dest); + + Assert.AreEqual(dest, result.AssetPath); + Assert.IsNotNull(AssetDatabase.LoadMainAssetAtPath(src), "Source should still exist after copy"); + Assert.AreNotEqual(AssetDatabase.AssetPathToGUID(src), AssetDatabase.AssetPathToGUID(dest), + "A copy should get a fresh GUID"); + } + + [Test] + public void RenameAsset_RenamesInPlace() + { + var src = Root + "/Rename/Old.asset"; + AssetCommands.CreateAsset(src, typeof(CLI191SampleAsset).FullName); + + var result = AssetCommands.RenameAsset(PathRef(src), "New"); + + Assert.AreEqual(Root + "/Rename/New.asset", result.AssetPath); + Assert.IsNull(AssetDatabase.LoadMainAssetAtPath(src)); + } + + [Test] + public void DeleteAsset_WithoutConfirm_Throws() + { + var path = Root + "/Delete/Doomed.asset"; + AssetCommands.CreateAsset(path, typeof(CLI191SampleAsset).FullName); + + Assert.Throws(() => AssetCommands.DeleteAsset(PathRef(path)), + "delete_asset without confirm should be rejected"); + Assert.IsNotNull(AssetDatabase.LoadMainAssetAtPath(path), "Asset should survive a refused delete"); + } + + [Test] + public void DeleteAsset_WithConfirm_Deletes() + { + var path = Root + "/Delete/Doomed2.asset"; + AssetCommands.CreateAsset(path, typeof(CLI191SampleAsset).FullName); + + var result = AssetCommands.DeleteAsset(PathRef(path), confirm: true); + + Assert.AreEqual(path, result.AssetPath); + Assert.IsNull(AssetDatabase.LoadMainAssetAtPath(path), "Asset should be gone after a confirmed delete"); + } + + [Test] + public void AcceptanceFlow_CreateFindMoveDelete() + { + // create folder tree + FolderCommands.CreateFolder(Root + "/Flow/Configs"); + Assert.IsTrue(AssetDatabase.IsValidFolder(Root + "/Flow/Configs")); + + // create ScriptableObject asset + var path = Root + "/Flow/Configs/Cfg.asset"; + AssetCommands.CreateAsset(path, typeof(CLI191SampleAsset).FullName); + + // find by type + var found = AssetCommands.FindAssets(type: nameof(CLI191SampleAsset), searchIn: Root + "/Flow"); + Assert.GreaterOrEqual(found.Count, 1); + + // move it + var moved = AssetCommands.MoveAsset(PathRef(path), Root + "/Flow/Moved.asset"); + Assert.AreEqual(Root + "/Flow/Moved.asset", moved.AssetPath); + + // delete it (with confirm) + AssetCommands.DeleteAsset(PathRef(moved.AssetPath), confirm: true); + Assert.IsNull(AssetDatabase.LoadMainAssetAtPath(moved.AssetPath)); + } + + #endregion + + #region ViaClient + + [Test] + public void CreateAsset_ViaClient_Succeeds() + { + using (var server = new PipelineTestServer()) + { + var path = Root + "/ViaClient/Made.asset"; + var response = server.Execute("create_asset", new { path, type = typeof(CLI191SampleAsset).FullName }); + + Assert.IsTrue(response.IsSuccess, $"create_asset should succeed: {response.Error}"); + Assert.IsTrue(response.HasValidJson, "Response should have valid JSON"); + Assert.IsTrue(response.JsonResponse.ContainsKey("result"), "Should have result field"); + Assert.IsNotNull(AssetDatabase.LoadAssetAtPath(path), "Asset should exist"); + } + } + + [Test] + public void DeleteAsset_ViaClient_WithoutConfirm_Fails() + { + var path = Root + "/ViaClient/ToDelete.asset"; + AssetCommands.CreateAsset(path, typeof(CLI191SampleAsset).FullName); + + using (var server = new PipelineTestServer()) + { + // The server logs the refusal as a Unity [Error]; expect it so the test does not fail on + // the unexpected log. Matches the message thrown by DeleteAsset ("Refusing to delete ..."). + LogAssert.Expect(LogType.Error, new Regex("Refusing to delete")); + + var response = server.Execute("delete_asset", new { asset = new { path } }); + + Assert.IsFalse(response.IsSuccess, "delete_asset without confirm should fail over the wire"); + Assert.IsNotNull(AssetDatabase.LoadMainAssetAtPath(path), "Asset should survive a refused delete"); + } + } + + [Test] + public void FindAssets_ViaClient_ReturnsResults() + { + var path = Root + "/ViaClient/Findable.asset"; + AssetCommands.CreateAsset(path, typeof(CLI191SampleAsset).FullName); + + using (var server = new PipelineTestServer()) + { + var response = server.Execute("find_assets", new { type = nameof(CLI191SampleAsset), search_in = Root }); + + Assert.IsTrue(response.IsSuccess, $"find_assets should succeed: {response.Error}"); + Assert.IsTrue(response.HasValidJson, "Response should have valid JSON"); + Assert.IsTrue(response.JsonResponse.ContainsKey("result"), "Should have result field"); + } + } + + #endregion + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/AssetCommandsTests.cs.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/AssetCommandsTests.cs.meta new file mode 100644 index 0000000..b525995 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/AssetCommandsTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: d4736a7747a847edb2355c95559ce0b0 diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/AssetImportCommandsTests.cs b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/AssetImportCommandsTests.cs new file mode 100644 index 0000000..1870ba6 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/AssetImportCommandsTests.cs @@ -0,0 +1,103 @@ +using Newtonsoft.Json.Linq; +using NUnit.Framework; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Editor.Commands.Assets; +using Unity.Pipeline.Models; +using UnityEditor; + +namespace Unity.Pipeline.Tests.Editor.Assets +{ + /// + /// Tests for set_import_settings (CLI-191). Uses the importer's userData property — present + /// on every AssetImporter — so the test is independent of any specific importer kind. Verifies the + /// applied/unknown bookkeeping and that the setting actually persists on the importer. + /// + class AssetImportCommandsTests + { + private const string Root = "Assets/__CLI191ImportTest"; + + [TearDown] + public void TearDown() + { + ProjectPaths.ResetAuthoringRoot(); + if (AssetDatabase.IsValidFolder(Root)) + { + AssetDatabase.DeleteAsset(Root); + AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport); + } + } + + private static ObjectRef PathRef(string path) => new ObjectRef { Path = path }; + + private static string CreateSampleAsset() + { + var path = Root + "/Imported.asset"; + AssetCommands.CreateAsset(path, typeof(CLI191SampleAsset).FullName); + return path; + } + + #region Direct + + [Test] + public void SetImportSettings_AppliesKnownMember() + { + var path = CreateSampleAsset(); + var settings = new JObject { ["userData"] = "cli191" }; + + var result = AssetImportCommands.SetImportSettings(PathRef(path), settings); + + CollectionAssert.Contains(result.Applied, "userData"); + CollectionAssert.IsEmpty(result.Unknown); + Assert.AreEqual("cli191", AssetImporter.GetAtPath(path).userData, "Setting should persist on the importer"); + } + + [Test] + public void SetImportSettings_UnknownOnly_Throws() + { + var path = CreateSampleAsset(); + var settings = new JObject { ["definitelyNotAMember"] = 42 }; + + Assert.Throws( + () => AssetImportCommands.SetImportSettings(PathRef(path), settings), + "When no supplied setting exists on the importer, the command should fail"); + } + + [Test] + public void SetImportSettings_DryRun_DoesNotPersist() + { + var path = CreateSampleAsset(); + var settings = new JObject { ["userData"] = "dryrun" }; + + var result = AssetImportCommands.SetImportSettings(PathRef(path), settings, dryRun: true); + + // dry_run reports the member as applicable but never mutates the importer. + CollectionAssert.Contains(result.Applied, "userData"); + Assert.AreNotEqual("dryrun", AssetImporter.GetAtPath(path).userData, "dry_run should not persist the change"); + } + + #endregion + + #region ViaClient + + [Test] + public void SetImportSettings_ViaClient_Succeeds() + { + var path = CreateSampleAsset(); + + using (var server = new PipelineTestServer()) + { + var response = server.Execute("set_import_settings", new + { + asset = new { path }, + settings = new { userData = "viaclient" } + }); + + Assert.IsTrue(response.IsSuccess, $"set_import_settings should succeed: {response.Error}"); + Assert.IsTrue(response.HasValidJson, "Response should have valid JSON"); + Assert.AreEqual("viaclient", AssetImporter.GetAtPath(path).userData); + } + } + + #endregion + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/AssetImportCommandsTests.cs.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/AssetImportCommandsTests.cs.meta new file mode 100644 index 0000000..c008460 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/AssetImportCommandsTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 121fa6671cf449ce863c389aa9b7e18c diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/ImportSettingsCommandTests.cs b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/ImportSettingsCommandTests.cs new file mode 100644 index 0000000..d3e73b7 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/ImportSettingsCommandTests.cs @@ -0,0 +1,432 @@ +using System.IO; +using Newtonsoft.Json.Linq; +using NUnit.Framework; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Editor.Commands.Assets; +using Unity.Pipeline.Models; +using UnityEditor; +using UnityEngine; + +namespace Unity.Pipeline.Tests.Editor.Assets +{ + /// + /// Tests for the CLI-212 per-type import settings + platform overrides: + /// get_import_settings and the platform-aware extension of set_import_settings. + /// + /// Real importers are exercised by writing tiny generated assets, so the actual Unity read/write + /// code paths (including per-platform overrides) are covered end to end: a 4x4 PNG (TextureImporter), + /// a minimal OBJ (ModelImporter), and a tiny 8-bit PCM WAV (AudioImporter). The audio fixture drives + /// a full per-platform override round-trip (ApplyAudioPlatform + + /// ReadAudioPlatformOverride): set override, read it back, then clear it. + /// + class ImportSettingsCommandTests + { + private const string Root = "Assets/__CLI212ImportTest"; + + [TearDown] + public void TearDown() + { + ProjectPaths.ResetAuthoringRoot(); + if (AssetDatabase.IsValidFolder(Root)) + { + AssetDatabase.DeleteAsset(Root); + AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport); + } + } + + private static ObjectRef PathRef(string path) => new ObjectRef { Path = path }; + + // ------------------------------------------------------------------ asset fixtures + + /// Write a tiny 4x4 PNG so Unity imports it with a TextureImporter. + private static string CreateTexture(string name = "Tex.png") + { + EnsureRoot(); + var tex = new Texture2D(4, 4, TextureFormat.RGBA32, false); + var pixels = new Color32[16]; + for (var i = 0; i < pixels.Length; i++) + pixels[i] = new Color32(255, 128, 64, 255); + tex.SetPixels32(pixels); + tex.Apply(); + var bytes = tex.EncodeToPNG(); + Object.DestroyImmediate(tex); + + var projectPath = Root + "/" + name; + File.WriteAllBytes(ToAbsolute(projectPath), bytes); + AssetDatabase.ImportAsset(projectPath, ImportAssetOptions.ForceSynchronousImport); + return projectPath; + } + + /// Write a minimal single-triangle OBJ so Unity imports it with a ModelImporter. + private static string CreateModel(string name = "Tri.obj") + { + EnsureRoot(); + const string obj = + "o Tri\n" + + "v 0 0 0\n" + + "v 1 0 0\n" + + "v 0 1 0\n" + + "vn 0 0 1\n" + + "f 1//1 2//1 3//1\n"; + var projectPath = Root + "/" + name; + File.WriteAllText(ToAbsolute(projectPath), obj); + AssetDatabase.ImportAsset(projectPath, ImportAssetOptions.ForceSynchronousImport); + return projectPath; + } + + /// + /// Write a tiny mono 8-bit PCM WAV (a handful of samples) so Unity imports it with an + /// AudioImporter — enough to exercise the real per-platform override read/write paths. + /// + private static string CreateAudio(string name = "Beep.wav") + { + EnsureRoot(); + + const int sampleRate = 8000; + const int sampleCount = 64; + var pcm = new byte[sampleCount]; + for (var i = 0; i < pcm.Length; i++) + pcm[i] = (byte)(128 + (i % 2 == 0 ? 32 : -32)); // crude square wave around the 8-bit midpoint + + using (var stream = new MemoryStream()) + using (var w = new BinaryWriter(stream)) + { + const short channels = 1; + const short bitsPerSample = 8; + var byteRate = sampleRate * channels * bitsPerSample / 8; + var blockAlign = (short)(channels * bitsPerSample / 8); + + // RIFF header + w.Write(new[] { 'R', 'I', 'F', 'F' }); + w.Write(36 + pcm.Length); + w.Write(new[] { 'W', 'A', 'V', 'E' }); + // fmt chunk + w.Write(new[] { 'f', 'm', 't', ' ' }); + w.Write(16); // PCM fmt chunk size + w.Write((short)1); // audio format = PCM + w.Write(channels); + w.Write(sampleRate); + w.Write(byteRate); + w.Write(blockAlign); + w.Write(bitsPerSample); + // data chunk + w.Write(new[] { 'd', 'a', 't', 'a' }); + w.Write(pcm.Length); + w.Write(pcm); + w.Flush(); + + var projectPath = Root + "/" + name; + File.WriteAllBytes(ToAbsolute(projectPath), stream.ToArray()); + AssetDatabase.ImportAsset(projectPath, ImportAssetOptions.ForceSynchronousImport); + return projectPath; + } + } + + private static void EnsureRoot() + { + if (!AssetDatabase.IsValidFolder(Root)) + AssetDatabase.CreateFolder("Assets", "__CLI212ImportTest"); + } + + private static string ToAbsolute(string projectRelative) => + $"{ProjectPaths.ProjectRoot.Replace('\\', '/')}/{projectRelative}"; + + // ------------------------------------------------------------------ texture: read + + [Test] + public void GetImportSettings_Texture_ReturnsStructuredDefaultsAndOverrideBlock() + { + var path = CreateTexture(); + + var result = AssetImportCommands.GetImportSettings(PathRef(path), platform: "Android"); + + Assert.AreEqual("TextureImporter", result.ImporterType); + Assert.AreEqual("Android", result.Platform); + Assert.IsNotNull(result.Settings); + Assert.IsTrue(result.Settings.ContainsKey("textureType")); + Assert.IsTrue(result.Settings.ContainsKey("isReadable")); + Assert.IsTrue(result.Settings.ContainsKey("mipmapEnabled")); + Assert.IsTrue(result.Settings.ContainsKey("wrapMode")); + Assert.IsNotNull(result.PlatformOverride, "Texture should expose a platform override block"); + Assert.IsTrue(result.PlatformOverride.ContainsKey("overridden")); + } + + // ------------------------------------------------------------------ texture: default round-trip + + [Test] + public void SetImportSettings_TextureDefault_AppliesAndReadBackReflects() + { + var path = CreateTexture(); + + var settings = new JObject + { + ["isReadable"] = true, + ["textureType"] = "NormalMap" + }; + var set = AssetImportCommands.SetImportSettings(PathRef(path), settings); + + CollectionAssert.Contains(set.Applied, "isReadable"); + CollectionAssert.Contains(set.Applied, "textureType"); + CollectionAssert.IsEmpty(set.Unknown); + + var read = AssetImportCommands.GetImportSettings(PathRef(path)); + Assert.AreEqual(true, read.Settings["isReadable"]); + Assert.AreEqual("NormalMap", read.Settings["textureType"]); + } + + // ------------------------------------------------------------------ texture: platform override set + clear + + [Test] + public void SetImportSettings_TextureAndroidOverride_SetsThenClears() + { + var path = CreateTexture(); + + // Default platform maxTextureSize before the override (should be unchanged afterwards). + var defaultBefore = AssetImportCommands.GetImportSettings(PathRef(path)); + var defaultMaxBefore = defaultBefore.Settings["maxTextureSize"]; + + var set = AssetImportCommands.SetImportSettings( + PathRef(path), + new JObject { ["maxTextureSize"] = 1024, ["format"] = "ASTC_6x6", ["overridden"] = true }, + platform: "Android"); + CollectionAssert.Contains(set.Applied, "maxTextureSize"); + CollectionAssert.Contains(set.Applied, "format"); + + var afterSet = AssetImportCommands.GetImportSettings(PathRef(path), platform: "Android"); + Assert.AreEqual(true, afterSet.PlatformOverride["overridden"]); + Assert.AreEqual(1024, afterSet.PlatformOverride["maxTextureSize"]); + Assert.AreEqual("ASTC_6x6", afterSet.PlatformOverride["format"]); + + // Default platform unchanged by the Android override. + var defaultAfter = AssetImportCommands.GetImportSettings(PathRef(path)); + Assert.AreEqual(defaultMaxBefore, defaultAfter.Settings["maxTextureSize"], + "Default platform settings must be unchanged by a platform override"); + + // Clear the override. + AssetImportCommands.SetImportSettings( + PathRef(path), + new JObject { ["overridden"] = false }, + platform: "Android"); + + var afterClear = AssetImportCommands.GetImportSettings(PathRef(path), platform: "Android"); + Assert.AreEqual(false, afterClear.PlatformOverride["overridden"], "Override should be cleared"); + } + + // ------------------------------------------------------------------ audio: read + + [Test] + public void GetImportSettings_Audio_ReturnsStructuredDefaultsAndOverrideBlock() + { + var path = CreateAudio(); + + var result = AssetImportCommands.GetImportSettings(PathRef(path), platform: "Android"); + + Assert.AreEqual("AudioImporter", result.ImporterType); + Assert.AreEqual("Android", result.Platform); + Assert.IsNotNull(result.Settings); + Assert.IsTrue(result.Settings.ContainsKey("loadType")); + Assert.IsTrue(result.Settings.ContainsKey("compressionFormat")); + Assert.IsTrue(result.Settings.ContainsKey("quality")); + Assert.IsNotNull(result.PlatformOverride, "Audio should expose a platform override block"); + Assert.IsTrue(result.PlatformOverride.ContainsKey("overridden")); + // No override has been written yet. + Assert.AreEqual(false, result.PlatformOverride["overridden"]); + } + + // ------------------------------------------------------------------ audio: platform override set + clear + + [Test] + public void SetImportSettings_AudioAndroidOverride_SetsThenClears() + { + var path = CreateAudio(); + + // Default-platform compressionFormat before the override (must be unchanged afterwards). + var defaultBefore = AssetImportCommands.GetImportSettings(PathRef(path)); + var defaultCompressionBefore = defaultBefore.Settings["compressionFormat"]; + + var set = AssetImportCommands.SetImportSettings( + PathRef(path), + new JObject { ["compressionFormat"] = "Vorbis", ["loadType"] = "CompressedInMemory", ["overridden"] = true }, + platform: "Android"); + CollectionAssert.Contains(set.Applied, "compressionFormat"); + CollectionAssert.Contains(set.Applied, "loadType"); + CollectionAssert.Contains(set.Applied, "overridden"); + CollectionAssert.IsEmpty(set.Unknown); + + var afterSet = AssetImportCommands.GetImportSettings(PathRef(path), platform: "Android"); + Assert.AreEqual(true, afterSet.PlatformOverride["overridden"], "Override should be present after a platform write"); + Assert.AreEqual("Vorbis", afterSet.PlatformOverride["compressionFormat"]); + Assert.AreEqual("CompressedInMemory", afterSet.PlatformOverride["loadType"]); + + // Default platform unchanged by the Android override. + var defaultAfter = AssetImportCommands.GetImportSettings(PathRef(path)); + Assert.AreEqual(defaultCompressionBefore, defaultAfter.Settings["compressionFormat"], + "Default platform settings must be unchanged by a platform override"); + + // Clear the override. + AssetImportCommands.SetImportSettings( + PathRef(path), + new JObject { ["overridden"] = false }, + platform: "Android"); + + var afterClear = AssetImportCommands.GetImportSettings(PathRef(path), platform: "Android"); + Assert.AreEqual(false, afterClear.PlatformOverride["overridden"], "Override should be cleared"); + } + + // ------------------------------------------------------------------ model: read + default write + + [Test] + public void GetImportSettings_Model_ReturnsNullPlatformOverride() + { + var path = CreateModel(); + + var result = AssetImportCommands.GetImportSettings(PathRef(path)); + + Assert.AreEqual("ModelImporter", result.ImporterType); + Assert.IsTrue(result.Settings.ContainsKey("meshCompression")); + Assert.IsTrue(result.Settings.ContainsKey("animationType")); + Assert.IsTrue(result.Settings.ContainsKey("materialImportMode")); + Assert.IsNull(result.PlatformOverride, "ModelImporter has no per-platform overrides"); + } + + [Test] + public void SetImportSettings_ModelDefault_AppliesAndReadBack() + { + var path = CreateModel(); + + var set = AssetImportCommands.SetImportSettings( + PathRef(path), + new JObject { ["meshCompression"] = "High", ["importNormals"] = "Calculate" }); + + CollectionAssert.Contains(set.Applied, "meshCompression"); + CollectionAssert.Contains(set.Applied, "importNormals"); + + var read = AssetImportCommands.GetImportSettings(PathRef(path)); + Assert.AreEqual("High", read.Settings["meshCompression"]); + Assert.AreEqual("Calculate", read.Settings["importNormals"]); + } + + [Test] + public void SetImportSettings_ModelWithPlatform_ReturnsNoPlatformOverrides_AndWritesNothing() + { + var path = CreateModel(); + var before = AssetImportCommands.GetImportSettings(PathRef(path)); + var meshBefore = before.Settings["meshCompression"]; + + var ex = Assert.Throws(() => + AssetImportCommands.SetImportSettings( + PathRef(path), + new JObject { ["meshCompression"] = "High" }, + platform: "iOS")); + StringAssert.Contains("no_platform_overrides", ex.Message); + + var after = AssetImportCommands.GetImportSettings(PathRef(path)); + Assert.AreEqual(meshBefore, after.Settings["meshCompression"], "A rejected platform write must change nothing"); + } + + // ------------------------------------------------------------------ dry_run + + [Test] + public void SetImportSettings_DryRun_ReportsButDoesNotChange() + { + var path = CreateTexture(); + var before = AssetImportCommands.GetImportSettings(PathRef(path)); + var readableBefore = (bool)before.Settings["isReadable"]; + + var result = AssetImportCommands.SetImportSettings( + PathRef(path), + new JObject { ["isReadable"] = !readableBefore }, + dryRun: true); + + CollectionAssert.Contains(result.Applied, "isReadable"); + + var after = AssetImportCommands.GetImportSettings(PathRef(path)); + Assert.AreEqual(readableBefore, (bool)after.Settings["isReadable"], "dry_run must not change settings"); + } + + // ------------------------------------------------------------------ unknown key handling + + [Test] + public void SetImportSettings_UnknownKey_GoesToUnknown() + { + var path = CreateTexture(); + + var result = AssetImportCommands.SetImportSettings( + PathRef(path), + new JObject { ["isReadable"] = true, ["definitelyNotAMember"] = 42 }); + + CollectionAssert.Contains(result.Applied, "isReadable"); + CollectionAssert.Contains(result.Unknown, "definitelyNotAMember"); + } + + [Test] + public void SetImportSettings_AllUnknown_Throws() + { + var path = CreateTexture(); + + Assert.Throws(() => + AssetImportCommands.SetImportSettings( + PathRef(path), + new JObject { ["definitelyNotAMember"] = 42 })); + } + + // ------------------------------------------------------------------ platform validation + + [Test] + public void SetImportSettings_UnknownPlatform_Throws() + { + var path = CreateTexture(); + + var ex = Assert.Throws(() => + AssetImportCommands.SetImportSettings( + PathRef(path), + new JObject { ["maxTextureSize"] = 512 }, + platform: "PlayStation")); + StringAssert.Contains("unknown_platform", ex.Message); + } + + [Test] + public void GetImportSettings_UnknownPlatform_Throws() + { + var path = CreateTexture(); + + Assert.Throws(() => + AssetImportCommands.GetImportSettings(PathRef(path), platform: "PlayStation")); + } + + // ------------------------------------------------------------------ sandbox guard + + [Test] + public void GetImportSettings_OutsideAuthoringRoot_Throws() + { + var path = CreateTexture(); + // Confine the authoring root to a sub-folder that does NOT contain the asset, so the asset's + // resolved path falls outside the sandbox. + ProjectPaths.AuthoringRoot = Root + "/Nested"; + + Assert.Throws(() => + AssetImportCommands.GetImportSettings(PathRef(path))); + } + + // ------------------------------------------------------------------ via client (wire) smoke test + + [Test] + public void GetImportSettings_ViaClient_Succeeds() + { + var path = CreateTexture(); + + using (var server = new PipelineTestServer()) + { + var response = server.Execute("get_import_settings", new + { + asset = new { path }, + platform = "Android" + }); + + Assert.IsTrue(response.IsSuccess, $"get_import_settings should succeed: {response.Error}"); + Assert.IsTrue(response.HasValidJson, "Response should have valid JSON"); + Assert.IsTrue(response.JsonResponse.ContainsKey("result"), "Should have result field"); + } + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/ImportSettingsCommandTests.cs.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/ImportSettingsCommandTests.cs.meta new file mode 100644 index 0000000..a318d07 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/ImportSettingsCommandTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 48fae49d74ce4b61941f9c5ff541034f diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/MaterialAssetCommandsTests.cs b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/MaterialAssetCommandsTests.cs new file mode 100644 index 0000000..cb87046 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/MaterialAssetCommandsTests.cs @@ -0,0 +1,182 @@ +using System.Text.RegularExpressions; +using NUnit.Framework; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Editor.Commands.Assets; +using UnityEditor; +using UnityEngine; +using UnityEngine.TestTools; + +namespace Unity.Pipeline.Tests.Editor.Assets +{ + /// + /// Tests for create_asset's Material support (CLI-221), exercised directly and via the isolated + /// . Verifies that a .mat is created with a real (non-null) shader, + /// that an unknown shader name fails clearly (no null Material / null-ref), and that the created + /// Material is loadable and assignable to a Renderer's material slot. + /// + class MaterialAssetCommandsTests + { + private const string Root = "Assets/__CLI221_222Test"; + + // A shader that is guaranteed to exist on whatever pipeline this project runs (built-in or URP). + private string m_KnownShader; + + [SetUp] + public void SetUp() + { + ProjectPaths.ResetAuthoringRoot(); + m_KnownShader = PickKnownShader(); + } + + [TearDown] + public void TearDown() + { + ProjectPaths.ResetAuthoringRoot(); + if (AssetDatabase.IsValidFolder(Root)) + { + AssetDatabase.DeleteAsset(Root); + AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport); + } + } + + /// Pick a shader name that resolves on this project's active pipeline. + private static string PickKnownShader() + { + if (Shader.Find("Standard") != null) + return "Standard"; + if (Shader.Find("Universal Render Pipeline/Lit") != null) + return "Universal Render Pipeline/Lit"; + // Sprites/Default ships with every pipeline as a hard fallback. + return "Sprites/Default"; + } + + #region Direct + + [Test] + public void CreateAsset_Material_WithShader_CreatesValidMaterial() + { + var path = Root + "/Mats/Bar.mat"; + var result = AssetCommands.CreateAsset(path, "Material", shader: m_KnownShader); + + Assert.AreEqual(path, result.AssetPath); + + var loaded = AssetDatabase.LoadAssetAtPath(path); + Assert.IsNotNull(loaded, "Created .mat should load as a Material"); + Assert.IsNotNull(loaded.shader, "Material's shader must not be null"); + Assert.AreEqual(Shader.Find(m_KnownShader), loaded.shader, "Material should use the requested shader"); + } + + [Test] + public void CreateAsset_Material_DefaultShader_IsNonNull() + { + // No explicit shader: should fall back to the active pipeline's lit shader (or Standard). + var path = Root + "/Mats/Default.mat"; + AssetCommands.CreateAsset(path, "Material"); + + var loaded = AssetDatabase.LoadAssetAtPath(path); + Assert.IsNotNull(loaded, "Created .mat should load as a Material"); + Assert.IsNotNull(loaded.shader, "Default-shader Material must have a non-null shader"); + } + + [Test] + public void CreateAsset_Material_InvalidShader_ThrowsClearError() + { + var path = Root + "/Mats/Broken.mat"; + + var ex = Assert.Throws( + () => AssetCommands.CreateAsset(path, "Material", shader: "No/Such/Shader__CLI221"), + "An unknown shader name should fail with a clear ArgumentException"); + StringAssert.Contains("not found", ex.Message); + + Assert.IsNull(AssetDatabase.LoadMainAssetAtPath(path), "No asset should be written on a shader failure"); + } + + [Test] + public void CreateAsset_Material_DryRun_InvalidShader_ThrowsAndWritesNothing() + { + // dry_run is documented as "validate inputs", so an unknown shader must fail fast even in + // dry_run (rather than reporting a would-be success) and still write nothing. + var path = Root + "/Mats/DryRunBroken.mat"; + + var ex = Assert.Throws( + () => AssetCommands.CreateAsset(path, "Material", shader: "No/Such/Shader__CLI221", dryRun: true), + "dry_run should resolve/validate the shader and fail on an unknown one"); + StringAssert.Contains("not found", ex.Message); + + Assert.IsNull(AssetDatabase.LoadMainAssetAtPath(path), "dry_run must never write an asset"); + } + + [Test] + public void CreateAsset_Material_DryRun_ValidShader_WritesNothing() + { + // A valid dry_run resolves the shader (no throw) but writes no asset. + var path = Root + "/Mats/DryRunOk.mat"; + var result = AssetCommands.CreateAsset(path, "Material", shader: m_KnownShader, dryRun: true); + + Assert.AreEqual(path, result.AssetPath); + Assert.IsNull(AssetDatabase.LoadMainAssetAtPath(path), "dry_run must never write an asset"); + } + + [Test] + public void CreateAsset_Material_AssignableToRendererSlot() + { + var path = Root + "/Mats/Assignable.mat"; + AssetCommands.CreateAsset(path, "Material", shader: m_KnownShader); + var mat = AssetDatabase.LoadAssetAtPath(path); + + var go = new GameObject("__CLI221_Renderer"); + try + { + var renderer = go.AddComponent(); + renderer.sharedMaterial = mat; + + Assert.AreEqual(mat, renderer.sharedMaterial, "Created Material should be assignable to a Renderer slot"); + } + finally + { + Object.DestroyImmediate(go); + } + } + + #endregion + + #region ViaClient + + [Test] + public void CreateAsset_Material_ViaClient_Succeeds() + { + using (var server = new PipelineTestServer()) + { + var path = Root + "/ViaClient/Wall.mat"; + var response = server.Execute("create_asset", new { path, type = "Material", shader = m_KnownShader }); + + Assert.IsTrue(response.IsSuccess, $"create_asset (Material) should succeed: {response.Error}"); + Assert.IsTrue(response.HasValidJson, "Response should have valid JSON"); + Assert.IsTrue(response.JsonResponse.ContainsKey("result"), "Should have result field"); + + var loaded = AssetDatabase.LoadAssetAtPath(path); + Assert.IsNotNull(loaded, "Material should exist on disk"); + Assert.IsNotNull(loaded.shader, "Material's shader must not be null"); + } + } + + [Test] + public void CreateAsset_Material_ViaClient_InvalidShader_Fails() + { + using (var server = new PipelineTestServer()) + { + // The server logs the failure as a Unity [Error]; expect it so the test does not fail on + // the unexpected log. Matches the message thrown by ResolveShader ("Shader '...' not found."). + LogAssert.Expect(LogType.Error, new Regex("not found")); + + var path = Root + "/ViaClient/Broken.mat"; + var response = server.Execute("create_asset", new { path, type = "Material", shader = "No/Such/Shader__CLI221" }); + + Assert.IsFalse(response.IsSuccess, "An unknown shader should fail over the wire"); + Assert.IsNull(AssetDatabase.LoadMainAssetAtPath(path), "No asset should be written on a shader failure"); + } + } + + #endregion + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/MaterialAssetCommandsTests.cs.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/MaterialAssetCommandsTests.cs.meta new file mode 100644 index 0000000..a6df6e4 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/MaterialAssetCommandsTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7d514449899cc0f439d287ab64433a22 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/PhysicsMaterialAssetCommandsTests.cs b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/PhysicsMaterialAssetCommandsTests.cs new file mode 100644 index 0000000..c8c5b0b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/PhysicsMaterialAssetCommandsTests.cs @@ -0,0 +1,158 @@ +using NUnit.Framework; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Editor.Commands.Assets; +using UnityEditor; +using UnityEngine; +#if !UNITY_6000_0_OR_NEWER +using PhysicsMaterial = UnityEngine.PhysicMaterial; +#endif + +namespace Unity.Pipeline.Tests.Editor.Assets +{ + /// + /// Tests for create_asset's PhysicsMaterial support (CLI-222), exercised directly and via the + /// isolated . Verifies that BOTH the Unity 6 type name + /// "PhysicsMaterial" and the legacy "PhysicMaterial" resolve to , that + /// the created asset carries the documented defaults (bounciness 0, frictions 0.6), is discoverable + /// via find_assets, and is assignable to a Collider's material slot. + /// + /// NOTE: Unity 6 renamed the class to PhysicsMaterial but the on-disk asset extension is still + /// ".physicMaterial" (AssetDatabase.CreateAsset rejects ".physicsMaterial"). create_asset normalizes + /// a ".physicsMaterial" request to ".physicMaterial", so the created path is asserted via the + /// command result rather than the requested path. + /// + class PhysicsMaterialAssetCommandsTests + { + private const string Root = "Assets/__CLI221_222Test"; + + [SetUp] + public void SetUp() + { + ProjectPaths.ResetAuthoringRoot(); + } + + [TearDown] + public void TearDown() + { + ProjectPaths.ResetAuthoringRoot(); + if (AssetDatabase.IsValidFolder(Root)) + { + AssetDatabase.DeleteAsset(Root); + AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport); + } + } + + private static void AssertDefaults(PhysicsMaterial pm) + { + Assert.IsNotNull(pm, "Created physics material should load as a PhysicsMaterial"); + Assert.AreEqual(0f, pm.bounciness, 1e-4f, "bounciness default should be 0"); + Assert.AreEqual(0.6f, pm.dynamicFriction, 1e-4f, "dynamicFriction default should be 0.6"); + Assert.AreEqual(0.6f, pm.staticFriction, 1e-4f, "staticFriction default should be 0.6"); + } + + #region Direct + + [Test] + public void CreateAsset_PhysicsMaterial_CreatesWithDefaults() + { + var result = AssetCommands.CreateAsset(Root + "/Phys/Ball.physicMaterial", "PhysicsMaterial"); + + StringAssert.EndsWith(".physicMaterial", result.AssetPath); + AssertDefaults(AssetDatabase.LoadAssetAtPath(result.AssetPath)); + } + + [Test] + public void CreateAsset_PhysicsMaterial_NormalizesModernExtension() + { + // CLI-222: an agent may pass the modern ".physicsMaterial" extension; it must succeed, + // normalized to the ".physicMaterial" file Unity actually writes. + var result = AssetCommands.CreateAsset(Root + "/Phys/Modern.physicsMaterial", "PhysicsMaterial"); + + StringAssert.EndsWith(".physicMaterial", result.AssetPath); + AssertDefaults(AssetDatabase.LoadAssetAtPath(result.AssetPath)); + } + + [Test] + public void CreateAsset_PhysicsMaterial_LegacyTypeName_ResolvesToSameType() + { + // CLI-222: the legacy "PhysicMaterial" spelling must resolve to UnityEngine.PhysicsMaterial. + var result = AssetCommands.CreateAsset(Root + "/Phys/Legacy.physicMaterial", "PhysicMaterial"); + + var loaded = AssetDatabase.LoadMainAssetAtPath(result.AssetPath); + Assert.IsInstanceOf(loaded, "Legacy 'PhysicMaterial' type name should resolve to PhysicsMaterial"); + AssertDefaults(loaded as PhysicsMaterial); + } + + [Test] + public void CreateAsset_PhysicsMaterial_FoundByFindAssets() + { + var result = AssetCommands.CreateAsset(Root + "/Phys/Findable.physicMaterial", "PhysicsMaterial"); + + var found = AssetCommands.FindAssets(type: "PhysicsMaterial", searchIn: Root); + + Assert.GreaterOrEqual(found.Count, 1, "Should find the created PhysicsMaterial by type"); + CollectionAssert.Contains( + System.Linq.Enumerable.Select(found.Assets, a => a.AssetPath), + result.AssetPath); + } + + [Test] + public void CreateAsset_PhysicsMaterial_AssignableToColliderSlot() + { + var result = AssetCommands.CreateAsset(Root + "/Phys/Assignable.physicMaterial", "PhysicsMaterial"); + var pm = AssetDatabase.LoadAssetAtPath(result.AssetPath); + + var go = new GameObject("__CLI222_Collider"); + try + { + var collider = go.AddComponent(); + collider.sharedMaterial = pm; + + Assert.AreEqual(pm, collider.sharedMaterial, "Created PhysicsMaterial should be assignable to a Collider slot"); + } + finally + { + Object.DestroyImmediate(go); + } + } + + #endregion + + #region ViaClient + + [Test] + public void CreateAsset_PhysicsMaterial_ViaClient_Succeeds() + { + using (var server = new PipelineTestServer()) + { + var response = server.Execute("create_asset", + new { path = Root + "/ViaClient/Ball.physicMaterial", type = "PhysicsMaterial" }); + + Assert.IsTrue(response.IsSuccess, $"create_asset (PhysicsMaterial) should succeed: {response.Error}"); + Assert.IsTrue(response.HasValidJson, "Response should have valid JSON"); + Assert.IsTrue(response.JsonResponse.ContainsKey("result"), "Should have result field"); + + var created = (string)response.JsonResponse["result"]["assetPath"]; + AssertDefaults(AssetDatabase.LoadAssetAtPath(created)); + } + } + + [Test] + public void CreateAsset_PhysicsMaterial_ViaClient_LegacyName_Succeeds() + { + using (var server = new PipelineTestServer()) + { + var response = server.Execute("create_asset", + new { path = Root + "/ViaClient/Legacy.physicMaterial", type = "PhysicMaterial" }); + + Assert.IsTrue(response.IsSuccess, $"create_asset (legacy PhysicMaterial) should succeed: {response.Error}"); + + var created = (string)response.JsonResponse["result"]["assetPath"]; + Assert.IsInstanceOf(AssetDatabase.LoadMainAssetAtPath(created), + "Legacy 'PhysicMaterial' should resolve to PhysicsMaterial over the wire"); + } + } + + #endregion + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/PhysicsMaterialAssetCommandsTests.cs.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/PhysicsMaterialAssetCommandsTests.cs.meta new file mode 100644 index 0000000..e085b83 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/PhysicsMaterialAssetCommandsTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: af05410e747b85c47ab38e0bf2db7fd8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/TextFileCommandsTests.cs b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/TextFileCommandsTests.cs new file mode 100644 index 0000000..746681e --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/TextFileCommandsTests.cs @@ -0,0 +1,108 @@ +using NUnit.Framework; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Editor.Commands.Assets; +using UnityEditor; + +namespace Unity.Pipeline.Tests.Editor.Assets +{ + /// + /// Tests for read_text_file / write_text_file (CLI-191), direct and via the isolated + /// . Covers round-tripping content, the overwrite-confirm guard, and + /// the sandbox guard (out-of-project writes rejected). + /// + class TextFileCommandsTests + { + private const string Root = "Assets/__CLI191TextTest"; + + [TearDown] + public void TearDown() + { + ProjectPaths.ResetAuthoringRoot(); + if (AssetDatabase.IsValidFolder(Root)) + { + AssetDatabase.DeleteAsset(Root); + AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport); + } + } + + #region Direct + + [Test] + public void WriteThenRead_RoundTrips() + { + var path = Root + "/Notes/hello.txt"; + const string content = "hello cli-191"; + + var write = TextFileCommands.WriteTextFile(path, content); + Assert.AreEqual(path, write.AssetPath); + + var read = TextFileCommands.ReadTextFile(path); + Assert.AreEqual(content, read.Contents); + Assert.AreEqual(System.Text.Encoding.UTF8.GetByteCount(content), read.Bytes); + } + + [Test] + public void WriteTextFile_OverwriteWithoutConfirm_Throws() + { + var path = Root + "/Notes/dup.txt"; + TextFileCommands.WriteTextFile(path, "first"); + + Assert.Throws( + () => TextFileCommands.WriteTextFile(path, "second"), + "Overwriting an existing file without confirm should be rejected"); + + var ok = TextFileCommands.WriteTextFile(path, "second", confirm: true); + Assert.AreEqual(path, ok.AssetPath); + Assert.AreEqual("second", TextFileCommands.ReadTextFile(path).Contents); + } + + [Test] + public void WriteTextFile_OutOfProject_Throws() + { + Assert.Throws(() => TextFileCommands.WriteTextFile("../escape.txt", "x")); + Assert.Throws(() => TextFileCommands.WriteTextFile("Assets/../escape.txt", "x")); + } + + [Test] + public void ReadTextFile_Missing_Throws() + { + Assert.Throws(() => TextFileCommands.ReadTextFile(Root + "/does-not-exist.txt")); + } + + #endregion + + #region ViaClient + + [Test] + public void WriteTextFile_ViaClient_Succeeds() + { + using (var server = new PipelineTestServer()) + { + var path = Root + "/ViaClient/wire.txt"; + var response = server.Execute("write_text_file", new { path, contents = "over the wire" }); + + Assert.IsTrue(response.IsSuccess, $"write_text_file should succeed: {response.Error}"); + Assert.IsTrue(response.HasValidJson, "Response should have valid JSON"); + Assert.AreEqual("over the wire", TextFileCommands.ReadTextFile(path).Contents); + } + } + + [Test] + public void ReadTextFile_ViaClient_Succeeds() + { + var path = Root + "/ViaClient/readable.txt"; + TextFileCommands.WriteTextFile(path, "readable content"); + + using (var server = new PipelineTestServer()) + { + var response = server.Execute("read_text_file", new { path }); + + Assert.IsTrue(response.IsSuccess, $"read_text_file should succeed: {response.Error}"); + Assert.IsTrue(response.HasValidJson, "Response should have valid JSON"); + Assert.IsTrue(response.JsonResponse.ContainsKey("result"), "Should have result field"); + } + } + + #endregion + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/TextFileCommandsTests.cs.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/TextFileCommandsTests.cs.meta new file mode 100644 index 0000000..8c9cb70 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Assets/TextFileCommandsTests.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 4ede31badcf640f6acc3c5baf0fc8ef3 diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring.meta new file mode 100644 index 0000000..897d58c --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 497149ab4929cd34483ff611ce25534a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/FolderCommandsTests.cs b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/FolderCommandsTests.cs new file mode 100644 index 0000000..1f7ccb8 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/FolderCommandsTests.cs @@ -0,0 +1,85 @@ +using NUnit.Framework; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Editor.Commands.Assets; +using UnityEditor; + +namespace Unity.Pipeline.Tests.Editor.Authoring +{ + /// + /// Tests for the create_folder reference command (CLI-190), exercised directly and via + /// PipelineClient. Verifies the result envelope, recursive creation, Assets-relative paths, + /// and the traversal guard. + /// + class FolderCommandsTests + { + private const string Root = "Assets/__CLI190Test"; + + [SetUp] + public void SetUp() + { + // Start from the default authoring root so a leftover EditorPref (from another test or an + // interrupted run) can't shift where bare paths resolve mid-suite. + ProjectPaths.ResetAuthoringRoot(); + } + + [TearDown] + public void TearDown() + { + ProjectPaths.ResetAuthoringRoot(); + if (AssetDatabase.IsValidFolder(Root)) + { + AssetDatabase.DeleteAsset(Root); + AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport); + } + } + + #region Direct + + [Test] + public void CreateFolder_ExplicitAssetsPath_CreatesFoldersAndReturnsIdentity() + { + var result = FolderCommands.CreateFolder(Root + "/Sub/Leaf"); + + Assert.IsTrue(AssetDatabase.IsValidFolder(Root + "/Sub/Leaf"), "Nested folders should exist"); + Assert.AreEqual(Root + "/Sub/Leaf", result.AssetPath); + Assert.IsNotEmpty(result.Guid, "Created folder should have a GUID"); + } + + [Test] + public void CreateFolder_BarePath_ResolvesUnderAssets() + { + // No "Assets/" prefix — should resolve under the default authoring root (Assets/). + var result = FolderCommands.CreateFolder("__CLI190Test/Bare"); + + Assert.AreEqual("Assets/__CLI190Test/Bare", result.AssetPath); + Assert.IsTrue(AssetDatabase.IsValidFolder("Assets/__CLI190Test/Bare")); + } + + [Test] + public void CreateFolder_Traversal_Throws() + { + Assert.Throws(() => FolderCommands.CreateFolder("../Outside")); + Assert.Throws(() => FolderCommands.CreateFolder("Assets/../Outside")); + } + + #endregion + + #region ViaClient + + [Test] + public void CreateFolder_ViaClient_Succeeds() + { + using (var server = new PipelineTestServer()) + { + var response = server.Execute("create_folder", new { path = Root + "/ViaClient" }); + + Assert.IsTrue(response.IsSuccess, $"create_folder should succeed: {response.Error}"); + Assert.IsTrue(response.HasValidJson, "Response should have valid JSON"); + Assert.IsTrue(response.JsonResponse.ContainsKey("result"), "Should have result field"); + Assert.IsTrue(AssetDatabase.IsValidFolder(Root + "/ViaClient"), "Folder should be created"); + } + } + + #endregion + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/FolderCommandsTests.cs.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/FolderCommandsTests.cs.meta new file mode 100644 index 0000000..d202bd3 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/FolderCommandsTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4653539f2cf4a1b4699bd2c7a8d35188 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/ObjectRefConverterTests.cs b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/ObjectRefConverterTests.cs new file mode 100644 index 0000000..0884f66 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/ObjectRefConverterTests.cs @@ -0,0 +1,223 @@ +using NUnit.Framework; +using Newtonsoft.Json; +using Unity.Pipeline; +using Unity.Pipeline.Models; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace Unity.Pipeline.Tests.Editor.Authoring +{ + /// + /// Tests for : a single canonical string handle coerces into the + /// matching ObjectRef field (mirroring ObjectResolver/ToString priority), structured objects still + /// deserialize fully, and serialization still emits a JSON object. Plus one end-to-end ViaClient + /// test proving a string target flows through the real /api/exec dispatch path. + /// + class ObjectRefConverterTests + { + private static ObjectRef Parse(string handle) => + JsonConvert.DeserializeObject("\"" + handle + "\""); + + #region String coercion (one field per canonical form) + + [Test] + public void String_HierarchyPath_LeadingSlash() + { + var r = Parse("/Player"); + Assert.AreEqual("/Player", r.HierarchyPath); + Assert.IsNull(r.GlobalId); Assert.IsNull(r.Path); Assert.IsNull(r.Guid); + Assert.IsNull(r.InstanceId); Assert.IsNull(r.FileId); + } + + [Test] + public void String_HierarchyPath_Nested() + { + Assert.AreEqual("/Level/Floor", Parse("/Level/Floor").HierarchyPath); + } + + [Test] + public void String_GlobalId() + { + var r = Parse("GlobalObjectId_V1-2-abc123def4560000abc123def4560000-1095335325-0"); + Assert.AreEqual("GlobalObjectId_V1-2-abc123def4560000abc123def4560000-1095335325-0", r.GlobalId); + Assert.IsNull(r.HierarchyPath); + } + + [Test] + public void String_AssetPath() + { + var r = Parse("Assets/Prefabs/Enemy.prefab"); + Assert.AreEqual("Assets/Prefabs/Enemy.prefab", r.Path); + Assert.IsNull(r.HierarchyPath); + } + + [Test] + public void String_GuidWithFileId() + { + var r = Parse("guid:a1b2c3d4e5f6:123"); + Assert.AreEqual("a1b2c3d4e5f6", r.Guid); + Assert.AreEqual(123L, r.FileId); + } + + [Test] + public void String_GuidOnly_Prefixed() + { + var r = Parse("guid:a1b2c3d4e5f6"); + Assert.AreEqual("a1b2c3d4e5f6", r.Guid); + Assert.IsNull(r.FileId); + } + + [Test] + public void String_InstanceId_Prefixed_Negative() + { +#if !UNITY_6000_4_OR_NEWER + Assert.AreEqual(ObjectId.FromRaw(-3070), Parse("instanceId:-3070").InstanceId); +#else + Assert.Ignore("Negative int instance ids do not exist in the EntityId (ulong) model on 6000.4+."); +#endif + } + + [Test] + public void String_PlainNegativeInt_IsInstanceId() + { +#if !UNITY_6000_4_OR_NEWER + var r = Parse("-3070"); + Assert.AreEqual(ObjectId.FromRaw(-3070), r.InstanceId); + Assert.IsNull(r.HierarchyPath); +#else + Assert.Ignore("Negative int instance ids do not exist in the EntityId (ulong) model on 6000.4+."); +#endif + } + + [Test] + public void String_PlainPositiveInt_IsInstanceId() + { + Assert.AreEqual(ObjectId.FromRaw(48184), Parse("48184").InstanceId); + } + + [Test] + public void String_32Hex_IsGuid() + { + var r = Parse("a1b2c3d4e5f60718293a4b5c6d7e8f90"); + Assert.AreEqual("a1b2c3d4e5f60718293a4b5c6d7e8f90", r.Guid); + Assert.IsNull(r.InstanceId); + } + + [Test] + public void String_BareName_FallsBackToHierarchyPath() + { + var r = Parse("Enemy_1"); + Assert.AreEqual("Enemy_1", r.HierarchyPath); + Assert.IsNull(r.InstanceId); Assert.IsNull(r.Guid); + } + + #endregion + + #region Authoring-root-relative asset paths (AUTHAPI-9) + + [Test] + public void String_RelativePathWithExtension_IsPath() + { + // No "Assets/" prefix but a file extension: an authoring-root-relative asset path. + var r = Parse("Materials/FloorA.mat"); + Assert.AreEqual("Materials/FloorA.mat", r.Path); + Assert.IsNull(r.HierarchyPath); + } + + [Test] + public void String_BareFileWithExtension_IsPath() + { + var r = Parse("Enemy.prefab"); + Assert.AreEqual("Enemy.prefab", r.Path); + Assert.IsNull(r.HierarchyPath); + } + + [Test] + public void String_RelativeNoExtension_StaysHierarchyPath() + { + // No extension and no leading slash: still a scene hierarchy path, not an asset candidate. + var r = Parse("Root/Child"); + Assert.AreEqual("Root/Child", r.HierarchyPath); + Assert.IsNull(r.Path); + } + + [Test] + public void String_LeadingSlashWithExtension_StaysHierarchyPath() + { + // A leading slash marks a canonical hierarchy path even when a name looks dotted. + var r = Parse("/Root/Cube.001"); + Assert.AreEqual("/Root/Cube.001", r.HierarchyPath); + Assert.IsNull(r.Path); + } + + #endregion + + #region Object form, write, null + + [Test] + public void Object_Structured_DeserializesAllFields() + { + var json = "{\"globalId\":\"G\",\"path\":\"Assets/A\",\"guid\":\"a1\",\"fileId\":42,\"instanceId\":7,\"hierarchyPath\":\"/H\"}"; + var r = JsonConvert.DeserializeObject(json); + Assert.AreEqual("G", r.GlobalId); + Assert.AreEqual("Assets/A", r.Path); + Assert.AreEqual("a1", r.Guid); + Assert.AreEqual(42L, r.FileId); + Assert.AreEqual(ObjectId.FromRaw(7), r.InstanceId); + Assert.AreEqual("/H", r.HierarchyPath); + } + + [Test] + public void WriteJson_EmitsObject_NotString_AndRoundTrips() + { + var json = JsonConvert.SerializeObject(new ObjectRef { HierarchyPath = "/Player" }); + StringAssert.StartsWith("{", json, "ObjectRef must serialize as a JSON object, not a bare string"); + StringAssert.Contains("\"hierarchyPath\":\"/Player\"", json); + + var back = JsonConvert.DeserializeObject(json); + Assert.AreEqual("/Player", back.HierarchyPath); + } + + [Test] + public void Null_DeserializesToNull() + { + Assert.IsNull(JsonConvert.DeserializeObject("null")); + } + + [Test] + public void Number_BareInteger_IsInstanceId() + { + Assert.AreEqual(ObjectId.FromRaw(48184), JsonConvert.DeserializeObject("48184").InstanceId); + } + + #endregion + + #region End-to-end via the real dispatch path + + [Test] + public void SetTransform_StringTarget_ResolvesAndApplies() + { + var go = new GameObject("CLI_ObjRefDispatch"); + try + { + using (var server = new PipelineTestServer()) + { + var resp = server.Execute("set_transform", + new { target = "/CLI_ObjRefDispatch", position = new[] { 1f, 2f, 3f } }); + + Assert.IsTrue(resp.IsSuccess, + $"set_transform with a string target should succeed (string->ObjectRef coercion): {resp.Error}"); + } + + Assert.AreEqual(new Vector3(1f, 2f, 3f), go.transform.localPosition, + "The string handle should have resolved to the GameObject and applied the transform"); + } + finally + { + Object.DestroyImmediate(go); + } + } + + #endregion + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/ObjectRefConverterTests.cs.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/ObjectRefConverterTests.cs.meta new file mode 100644 index 0000000..f22eadc --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/ObjectRefConverterTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b218af7c5c4799a4ab37d7a670a6256e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/ObjectResolverTests.cs b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/ObjectResolverTests.cs new file mode 100644 index 0000000..d41c659 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/ObjectResolverTests.cs @@ -0,0 +1,145 @@ +using NUnit.Framework; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Models; +using UnityEditor; +using UnityEngine; +using Object = UnityEngine.Object; +using Unity.Pipeline; + +namespace Unity.Pipeline.Tests.Editor.Authoring +{ + /// + /// Tests for the object-reference resolver foundation (CLI-190): each handle form resolves back + /// to the same object, and Describe produces a canonical identity. + /// + class ObjectResolverTests + { + private const string AssetFolder = "Assets/AUTHAPI9_Res"; + + private GameObject m_SceneObject; + + [TearDown] + public void TearDown() + { + if (m_SceneObject != null) + Object.DestroyImmediate(m_SceneObject); + m_SceneObject = null; + + if (AssetDatabase.IsValidFolder(AssetFolder)) + { + AssetDatabase.DeleteAsset(AssetFolder); + AssetDatabase.Refresh(); + } + } + + private static string CreateMaterialAsset(string name) + { + if (!AssetDatabase.IsValidFolder(AssetFolder)) + AssetDatabase.CreateFolder("Assets", "AUTHAPI9_Res"); + + var shader = Shader.Find("Standard") + ?? Shader.Find("Universal Render Pipeline/Lit") + ?? Shader.Find("Sprites/Default"); + var mat = new Material(shader); + var path = $"{AssetFolder}/{name}.mat"; + AssetDatabase.CreateAsset(mat, path); + AssetDatabase.SaveAssets(); + return path; + } + + [Test] + public void Describe_SceneObject_ProducesInstanceIdAndHierarchyPath() + { + m_SceneObject = new GameObject("CLI190_Root"); + var child = new GameObject("Child"); + child.transform.SetParent(m_SceneObject.transform); + + var info = ObjectResolver.Describe(child); + + Assert.IsNotNull(info); + Assert.AreEqual(PipelineUtils.GetObjectId(child), info.InstanceId); + Assert.AreEqual("/CLI190_Root/Child", info.HierarchyPath); + Assert.AreEqual("GameObject", info.Type); + Assert.IsNull(info.AssetPath, "A scene object should not report an asset path"); + } + + [Test] + public void Resolve_ByInstanceId_ReturnsSameObject() + { + m_SceneObject = new GameObject("CLI190_ById"); + var handle = new ObjectRef { InstanceId = PipelineUtils.GetObjectId(m_SceneObject) }; + + Assert.IsTrue(ObjectResolver.TryResolve(handle, out var obj, out var error), error); + Assert.AreSame(m_SceneObject, obj); + } + + [Test] + public void Resolve_ByHierarchyPath_ReturnsSameObject() + { + m_SceneObject = new GameObject("CLI190_ByPath"); + var handle = new ObjectRef { HierarchyPath = "/CLI190_ByPath" }; + + Assert.IsTrue(ObjectResolver.TryResolve(handle, out var obj, out var error), error); + Assert.AreSame(m_SceneObject, obj); + } + + [Test] + public void Resolve_EmptyHandle_FailsWithError() + { + Assert.IsFalse(ObjectResolver.TryResolve(new ObjectRef(), out _, out var error)); + Assert.IsNotEmpty(error); + } + + [Test] + public void Resolve_UnknownGuid_FailsWithError() + { + var handle = new ObjectRef { Guid = "00000000000000000000000000000000" }; + Assert.IsFalse(ObjectResolver.TryResolve(handle, out _, out var error)); + Assert.IsNotEmpty(error); + } + + [Test] + public void Resolve_ByRelativeAssetPath_NormalizesUnderAuthoringRoot() + { + // A path without the "Assets/" prefix (AUTHAPI-9) resolves under the authoring root. + var full = CreateMaterialAsset("Floor"); + var expected = AssetDatabase.LoadMainAssetAtPath(full); + var handle = new ObjectRef { Path = "AUTHAPI9_Res/Floor.mat" }; + + Assert.IsTrue(ObjectResolver.TryResolve(handle, out var obj, out var error), error); + Assert.AreSame(expected, obj); + } + + [Test] + public void Resolve_ExplicitAssetsPath_StillResolves() + { + var full = CreateMaterialAsset("Wall"); + var handle = new ObjectRef { Path = full }; + + Assert.IsTrue(ObjectResolver.TryResolve(handle, out var obj, out var error), error); + Assert.AreSame(AssetDatabase.LoadMainAssetAtPath(full), obj); + } + + [Test] + public void Resolve_DottedGameObjectName_FallsBackToHierarchy() + { + // A dotted name (e.g. "Cube.001") is routed to Path by the string converter but is really a + // scene object; the Path branch falls back to a hierarchy lookup. + m_SceneObject = new GameObject("Cube.001"); + var handle = new ObjectRef { Path = "Cube.001" }; + + Assert.IsTrue(ObjectResolver.TryResolve(handle, out var obj, out var error), error); + Assert.AreSame(m_SceneObject, obj); + } + + [Test] + public void Resolve_UnresolvableRelativePath_ErrorListsEveryStrategy() + { + var handle = new ObjectRef { Path = "AUTHAPI9_Res/Missing.mat" }; + + Assert.IsFalse(ObjectResolver.TryResolve(handle, out _, out var error)); + StringAssert.Contains("no asset at", error); + StringAssert.Contains("no GameObject at hierarchy path", error); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/ObjectResolverTests.cs.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/ObjectResolverTests.cs.meta new file mode 100644 index 0000000..2b4e94d --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/ObjectResolverTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e864b00059a57364d902089021b33742 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/ProjectPathsTests.cs b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/ProjectPathsTests.cs new file mode 100644 index 0000000..c2898f8 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/ProjectPathsTests.cs @@ -0,0 +1,84 @@ +using NUnit.Framework; +using Unity.Pipeline.Editor.Authoring; + +namespace Unity.Pipeline.Tests.Editor.Authoring +{ + /// + /// Tests for ProjectPaths (CLI-190): Assets-relative resolution, the traversal/out-of-root + /// guards, and the configurable authoring root. + /// + class ProjectPathsTests + { + [SetUp] + public void SetUp() + { + // Reset to the default root before each test so a leftover EditorPref can't leak in. + ProjectPaths.ResetAuthoringRoot(); + } + + [TearDown] + public void TearDown() + { + ProjectPaths.ResetAuthoringRoot(); + } + + [Test] + public void DefaultRoot_IsAssets() + { + ProjectPaths.ResetAuthoringRoot(); + Assert.AreEqual("Assets", ProjectPaths.AuthoringRoot); + } + + [Test] + public void Resolve_BarePath_PrependsAssets() + { + var resolved = ProjectPaths.Resolve("Gameplay/Enemies", out var error); + Assert.IsNull(error, error); + Assert.AreEqual("Assets/Gameplay/Enemies", resolved); + } + + [Test] + public void Resolve_ExplicitAssetsPath_Unchanged() + { + var resolved = ProjectPaths.Resolve("Assets/Gameplay", out var error); + Assert.IsNull(error, error); + Assert.AreEqual("Assets/Gameplay", resolved); + } + + [Test] + public void Resolve_Traversal_Fails() + { + Assert.IsNull(ProjectPaths.Resolve("../Outside", out var error)); + Assert.IsNotEmpty(error); + } + + [Test] + public void Resolve_EmptyPath_Fails() + { + Assert.IsNull(ProjectPaths.Resolve("", out var error)); + Assert.IsNotEmpty(error); + } + + [Test] + public void ConfigurableRoot_ConfinesBareAndRejectsOutside() + { + ProjectPaths.AuthoringRoot = "Assets/__CLI190Root"; + + // Bare path resolves under the configured root. + var inside = ProjectPaths.Resolve("Foo/Bar", out var insideError); + Assert.IsNull(insideError, insideError); + Assert.AreEqual("Assets/__CLI190Root/Foo/Bar", inside); + + // Explicit path outside the configured root is rejected (confinement). + Assert.IsNull(ProjectPaths.Resolve("Assets/Other", out var outsideError)); + Assert.IsNotEmpty(outsideError); + } + + [Test] + public void SetAuthoringRoot_OutsideAssets_Throws() + { + Assert.Throws(() => ProjectPaths.AuthoringRoot = "Outside"); + Assert.Throws(() => ProjectPaths.AuthoringRoot = "Assets/../Escape"); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/ProjectPathsTests.cs.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/ProjectPathsTests.cs.meta new file mode 100644 index 0000000..25c7f83 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Authoring/ProjectPathsTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9af4698d059fd9d43b72c6e1dad56424 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/AutoTickCommandTests.cs b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/AutoTickCommandTests.cs new file mode 100644 index 0000000..d6b19ba --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/AutoTickCommandTests.cs @@ -0,0 +1,114 @@ +using NUnit.Framework; +using Unity.Pipeline.Editor.Commands; + +namespace Unity.Pipeline.Tests.Editor +{ + /// + /// Tests for auto-tick's SessionState persistence across (simulated) domain reloads. + /// The live editor's own server may already have auto-tick enabled, so SetUp/TearDown save and + /// restore whatever state was live before each test instead of assuming it starts off. + /// + class AutoTickCommandTests + { + private bool m_PrevEnabled; + private long m_PrevIntervalMs; + private bool m_HadPersisted; + private bool m_PrevPersistedEnabled; + private long m_PrevPersistedIntervalMs; + + [SetUp] + public void SetUp() + { + m_PrevEnabled = AutoTickCommand.IsEnabled; + m_PrevIntervalMs = AutoTickCommand.CurrentIntervalMs; + m_HadPersisted = AutoTickCommand.TryGetPersistedSessionForTests(out m_PrevPersistedEnabled, out m_PrevPersistedIntervalMs); + AutoTickCommand.EraseSessionForTests(); + } + + [TearDown] + public void TearDown() + { + // persist:false so this only restores the live in-memory state, not SessionState - + // the persisted baseline (or lack thereof) is restored/erased separately below. + AutoTickCommand.SetAutoTick(m_PrevEnabled, (int)m_PrevIntervalMs, persist: false); + + if (m_HadPersisted) + AutoTickCommand.SetPersistedSessionForTests(m_PrevPersistedEnabled, m_PrevPersistedIntervalMs); + else + AutoTickCommand.EraseSessionForTests(); + } + + [TestCase(true, 5)] + [TestCase(true, 250)] + [TestCase(false, 40)] + public void RestoreFromSession_AfterSimulatedReload_RestoresExactPriorState(bool enable, int intervalMs) + { + AutoTickCommand.SetAutoTick(enable, intervalMs); + + // A domain reload clears the statics (and the update-loop subscription with them) but + // leaves the SessionState copy this call just wrote intact. + AutoTickCommand.ResetForTests(); + + // Pass the opposite of the persisted value as the default, so a passing assertion proves + // the persisted state won, not the default falling through by coincidence. + AutoTickCommand.RestoreFromSession(defaultEnabled: !enable); + + Assert.AreEqual(enable, AutoTickCommand.IsEnabled, + "Restore must bring back the exact enabled state set via SetAutoTick, not the startup default."); + if (enable) + { + Assert.AreEqual(intervalMs, AutoTickCommand.CurrentIntervalMs, + "Restore must bring back the exact interval set via SetAutoTick, not the default interval."); + } + } + + [TestCase(true)] + [TestCase(false)] + public void RestoreFromSession_NoPriorExplicitCallThisSession_AppliesDefault(bool defaultEnabled) + { + // SetUp already erased SessionState and this simulates a reload on top of that, so there + // is no persisted choice for RestoreFromSession to find. + AutoTickCommand.ResetForTests(); + + AutoTickCommand.RestoreFromSession(defaultEnabled); + + Assert.AreEqual(defaultEnabled, AutoTickCommand.IsEnabled); + if (defaultEnabled) + { + Assert.AreEqual(AutoTickCommand.DefaultIntervalMs, AutoTickCommand.CurrentIntervalMs, + "With no explicit prior choice, restoring 'enabled' must use the default interval."); + } + } + + [Test] + public void SetAutoTick_WithPersistFalse_RevertsToPriorPersistedBaselineAfterSimulatedReload() + { + // Establish a persisted baseline, as if the user had configured a normal auto-tick rate. + AutoTickCommand.SetAutoTick(true, 200); + + // A temporary, expensive override (interval_ms=0 pegs a CPU core) that must not overwrite + // the baseline above. + AutoTickCommand.SetAutoTick(true, 0, persist: false); + Assert.AreEqual(0, AutoTickCommand.CurrentIntervalMs, "The temporary override should still apply immediately."); + + AutoTickCommand.ResetForTests(); + AutoTickCommand.RestoreFromSession(defaultEnabled: false); + + Assert.AreEqual(200, AutoTickCommand.CurrentIntervalMs, + "persist:false must not clobber the previously persisted baseline."); + } + + [Test] + public void SetAutoTick_WithPersistFalse_NoPriorBaseline_DoesNotSurviveSimulatedReload() + { + AutoTickCommand.SetAutoTick(true, 0, persist: false); + Assert.IsTrue(AutoTickCommand.IsEnabled); + + AutoTickCommand.ResetForTests(); + AutoTickCommand.RestoreFromSession(defaultEnabled: false); + + Assert.IsFalse(AutoTickCommand.IsEnabled, + "With no persisted baseline, a session-only (persist:false) call must not survive a reload."); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/AutoTickCommandTests.cs.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/AutoTickCommandTests.cs.meta new file mode 100644 index 0000000..9d601ee --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/AutoTickCommandTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 33094abdda6430b4d883852f20d4132f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking.meta new file mode 100644 index 0000000..8df4238 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5e5fd89f0ad042538cfef1bd87763a27 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking/LightingBakeCommandsTests.cs b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking/LightingBakeCommandsTests.cs new file mode 100644 index 0000000..d1e1c97 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking/LightingBakeCommandsTests.cs @@ -0,0 +1,199 @@ +using System.Linq; +using Newtonsoft.Json.Linq; +using NUnit.Framework; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor; +using Unity.Pipeline.Editor.Commands.Baking; +using UnityEditor; +using UnityEditor.SceneManagement; +using UnityEngine.SceneManagement; + +namespace Unity.Pipeline.Tests.Editor.Baking +{ + /// + /// Tests for the CLI-215 lighting bake commands. These cover the parts that are deterministic + /// without waiting on a real (minutes-long) lightmap bake: command discovery/schema, the + /// settings get/set round-trip, the destructive clear guard, the idle status, the no_scene guard, + /// and dry_run being a no-op. The full bake → completed acceptance flow is exercised live against a + /// running Editor (it is too slow/platform-dependent for the unit suite). + /// + class LightingBakeCommandsTests + { + [SetUp] + public void SetUp() => CommandRegistry.SetDiscovery(new TypeCacheCommandDiscovery()); + + [TearDown] + public void TearDown() + { + // Leave the editor with a fresh empty (untitled) scene so other tests are unaffected. + EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); + } + + [Test] + public void LightingCommands_AreDiscovered_WithExpectedSchema() + { + var commands = CommandRegistry.DiscoverCommands().ToList(); + + var bake = commands.FirstOrDefault(c => c.Name == "bake_lighting"); + Assert.IsNotNull(bake, "Should discover bake_lighting"); + CollectionAssert.AreEquivalent(new[] { "confirm", "dry_run" }, + bake.Parameters.Select(p => p.Name).ToList()); + + var status = commands.FirstOrDefault(c => c.Name == "lighting_bake_status"); + Assert.IsNotNull(status, "Should discover lighting_bake_status"); + Assert.IsFalse(status.MainThreadRequired, + "lighting_bake_status must be off-main-thread so it answers while a bake holds the main thread"); + Assert.AreEqual(0, status.Parameters.Count, "lighting_bake_status takes no parameters"); + + Assert.IsNotNull(commands.FirstOrDefault(c => c.Name == "cancel_lighting_bake")); + Assert.IsNotNull(commands.FirstOrDefault(c => c.Name == "clear_baked_lighting")); + Assert.IsNotNull(commands.FirstOrDefault(c => c.Name == "get_lighting_settings")); + Assert.IsNotNull(commands.FirstOrDefault(c => c.Name == "set_lighting_settings")); + } + + [Test] + public void GetLightingSettings_ReturnsCoreFields() + { + var settings = LightingBakeCommands.GetLightingSettings(); + if (!settings.Available) + { + // No LightingSettings are exposed when no scene is open (e.g. batchmode test + // projects start with an untitled empty scene). Skip rather than fail. + Assert.Pass("No active LightingSettings — skipping (no scene open in test project)."); + return; + } + Assert.IsNotNull(settings.Lightmapper, "lightmapper should be reported"); + + // directionalMode must be one of the two spec values, never a raw flags-enum string. + Assert.That(settings.DirectionalMode, Is.EqualTo("NonDirectional").Or.EqualTo("Directional"), + "directionalMode must be 'NonDirectional' or 'Directional'"); + + // lightmapCompression must be the LightmapCompression enum name, not a bool. + var validCompressions = new[] { "None", "LowQuality", "NormalQuality", "HighQuality" }; + CollectionAssert.Contains(validCompressions, settings.LightmapCompression, + "lightmapCompression must be one of the LightmapCompression enum names"); + } + + [Test] + public void SetLightingSettings_DirectionalMode_RoundTrips() + { + var before = LightingBakeCommands.GetLightingSettings(); + if (!before.Available) + { + Assert.Pass("No active LightingSettings — skipping directionalMode round-trip test."); + return; + } + + var target = before.DirectionalMode == "NonDirectional" ? "Directional" : "NonDirectional"; + try + { + var result = JObject.FromObject(LightingBakeCommands.SetLightingSettings( + new JObject { ["directionalMode"] = target })); + CollectionAssert.Contains(result["applied"].Select(t => t.Value()).ToList(), + "directionalMode", "directionalMode should be in applied[]"); + + var after = LightingBakeCommands.GetLightingSettings(); + Assert.That(after.DirectionalMode, Is.EqualTo("NonDirectional").Or.EqualTo("Directional"), + "directionalMode must remain a spec-valid string after set"); + } + finally + { + LightingBakeCommands.SetLightingSettings(new JObject { ["directionalMode"] = before.DirectionalMode }); + } + } + + [Test] + public void SetLightingSettings_RoundTrips_BouncesAndResolution() + { + var before = LightingBakeCommands.GetLightingSettings(); + var newBounces = before.Bounces == 3 ? 2 : 3; + var newResolution = before.LightmapResolution >= 40f ? 20f : 50f; + + try + { + var settings = new JObject + { + ["bounces"] = newBounces, + ["lightmapResolution"] = newResolution + }; + LightingBakeCommands.SetLightingSettings(settings); + + var after = LightingBakeCommands.GetLightingSettings(); + Assert.AreEqual(newBounces, after.Bounces, "bounces should round-trip"); + Assert.AreEqual(newResolution, after.LightmapResolution, 0.001f, "lightmapResolution should round-trip"); + } + finally + { + // Restore the prior values so the suite leaves no residue in the host project's + // lighting settings (the active settings may be a shared scene-default or asset). + LightingBakeCommands.SetLightingSettings(new JObject + { + ["bounces"] = before.Bounces, + ["lightmapResolution"] = before.LightmapResolution + }); + } + } + + [Test] + public void SetLightingSettings_ReportsUnknownKeys() + { + var settings = new JObject + { + ["bounces"] = 2, + ["totallyNotARealKey"] = 5 + }; + var result = JObject.FromObject(LightingBakeCommands.SetLightingSettings(settings)); + + var applied = result["applied"].Select(t => t.Value()).ToList(); + var unknown = result["unknown"].Select(t => t.Value()).ToList(); + CollectionAssert.Contains(applied, "bounces"); + CollectionAssert.Contains(unknown, "totallyNotARealKey"); + } + + [Test] + public void SetLightingSettings_DryRun_DoesNotChangeAnything() + { + var before = LightingBakeCommands.GetLightingSettings(); + var changed = before.Bounces == 1 ? 4 : 1; + + LightingBakeCommands.SetLightingSettings(new JObject { ["bounces"] = changed }, dryRun: true); + + var after = LightingBakeCommands.GetLightingSettings(); + Assert.AreEqual(before.Bounces, after.Bounces, "dry_run must not mutate settings"); + } + + [Test] + public void ClearBakedLighting_WithoutConfirm_Throws() + { + Assert.Throws(() => LightingBakeCommands.ClearBakedLighting()); + } + + [Test] + public void ClearBakedLighting_DryRun_DoesNotThrow_AndReportsWouldClear() + { + var result = JObject.FromObject(LightingBakeCommands.ClearBakedLighting(confirm: true, dryRun: true)); + Assert.AreEqual("dry_run", result["status"].Value()); + Assert.IsTrue(result["wouldClear"].Value()); + } + + [Test] + public void BakeLighting_NoOpenSavedScene_ReturnsNoScene() + { + // A fresh untitled scene has an empty path, so it is not a bakeable (saved) scene. + EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); + Assert.IsTrue(string.IsNullOrEmpty(SceneManager.GetActiveScene().path), "test precondition: untitled scene"); + + var result = JObject.FromObject(LightingBakeCommands.BakeLighting()); + Assert.AreEqual("no_scene", result["code"].Value()); + } + + [Test] + public void LightingBakeStatus_Idle_WhenNothingTriggered_OrAfterStatusFile() + { + // The status reflects either a clean idle or the result of a prior (cancelled/completed) + // bake from another test; in all cases it must be valid JSON carrying a "status" field. + var json = JObject.Parse(LightingBakeCommands.LightingBakeStatus()); + Assert.IsNotNull(json["status"], "lighting_bake_status should always include a 'status' field"); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking/LightingBakeCommandsTests.cs.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking/LightingBakeCommandsTests.cs.meta new file mode 100644 index 0000000..f0e4f61 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking/LightingBakeCommandsTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bdeb4ada982746e1aa5d72b49157fd3e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking/NavMeshBakeCommandsTests.cs b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking/NavMeshBakeCommandsTests.cs new file mode 100644 index 0000000..a60211a --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking/NavMeshBakeCommandsTests.cs @@ -0,0 +1,125 @@ +using System.Linq; +using Newtonsoft.Json.Linq; +using NUnit.Framework; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor; +using Unity.Pipeline.Editor.Commands.Baking; +using UnityEditor.SceneManagement; + +namespace Unity.Pipeline.Tests.Editor.Baking +{ + /// + /// Tests for the CLI-215 legacy NavMesh bake commands. Covers discovery/schema, the settings + /// get/set round-trip, the destructive clear guard, the idle status, the no_scene guard, dry_run + /// being a no-op, and the AI-Navigation stub returning package_not_found when the package is + /// absent. The full bake → succeeded flow is exercised live. + /// + class NavMeshBakeCommandsTests + { + [SetUp] + public void SetUp() => CommandRegistry.SetDiscovery(new TypeCacheCommandDiscovery()); + + [TearDown] + public void TearDown() + { + EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); + } + + [Test] + public void NavMeshCommands_AreDiscovered_WithExpectedSchema() + { + var commands = CommandRegistry.DiscoverCommands().ToList(); + + Assert.IsNotNull(commands.FirstOrDefault(c => c.Name == "bake_navmesh")); + Assert.IsNotNull(commands.FirstOrDefault(c => c.Name == "cancel_navmesh_bake")); + Assert.IsNotNull(commands.FirstOrDefault(c => c.Name == "clear_navmesh")); + Assert.IsNotNull(commands.FirstOrDefault(c => c.Name == "get_navmesh_settings")); + Assert.IsNotNull(commands.FirstOrDefault(c => c.Name == "set_navmesh_settings")); + + var status = commands.FirstOrDefault(c => c.Name == "navmesh_bake_status"); + Assert.IsNotNull(status, "Should discover navmesh_bake_status"); + Assert.IsFalse(status.MainThreadRequired, "navmesh_bake_status must be off-main-thread"); + Assert.AreEqual(0, status.Parameters.Count, "navmesh_bake_status takes no parameters"); + } + + [Test] + public void GetNavMeshSettings_ReturnsAgentFields() + { + var settings = NavMeshBakeCommands.GetNavMeshSettings(); + Assert.IsTrue(settings.Available, "Legacy NavMesh settings should be available"); + Assert.Greater(settings.AgentRadius, 0f, "agentRadius should be a sensible positive default"); + Assert.Greater(settings.AgentHeight, 0f, "agentHeight should be a sensible positive default"); + } + + [Test] + public void SetNavMeshSettings_RoundTrips_AgentRadius() + { + var before = NavMeshBakeCommands.GetNavMeshSettings(); + var newRadius = before.AgentRadius >= 0.5f ? 0.35f : 0.75f; + + NavMeshBakeCommands.SetNavMeshSettings(new JObject { ["agentRadius"] = newRadius }); + + var after = NavMeshBakeCommands.GetNavMeshSettings(); + Assert.AreEqual(newRadius, after.AgentRadius, 0.001f, "agentRadius should round-trip"); + + // Restore the prior value so the suite leaves no residue in the host project's settings. + NavMeshBakeCommands.SetNavMeshSettings(new JObject { ["agentRadius"] = before.AgentRadius }); + } + + [Test] + public void SetNavMeshSettings_ReportsUnknownKeys() + { + var result = JObject.FromObject( + NavMeshBakeCommands.SetNavMeshSettings(new JObject { ["agentRadius"] = 0.5f, ["nope"] = 1 }, dryRun: true)); + + var applied = result["applied"].Select(t => t.Value()).ToList(); + var unknown = result["unknown"].Select(t => t.Value()).ToList(); + CollectionAssert.Contains(applied, "agentRadius"); + CollectionAssert.Contains(unknown, "nope"); + } + + [Test] + public void SetNavMeshSettings_DryRun_DoesNotChangeAnything() + { + var before = NavMeshBakeCommands.GetNavMeshSettings(); + var changed = before.AgentRadius >= 0.5f ? 0.2f : 0.9f; + + NavMeshBakeCommands.SetNavMeshSettings(new JObject { ["agentRadius"] = changed }, dryRun: true); + + var after = NavMeshBakeCommands.GetNavMeshSettings(); + Assert.AreEqual(before.AgentRadius, after.AgentRadius, 0.001f, "dry_run must not mutate settings"); + } + + [Test] + public void ClearNavMesh_WithoutConfirm_Throws() + { + Assert.Throws(() => NavMeshBakeCommands.ClearNavMesh()); + } + + [Test] + public void BakeNavMesh_NoOpenSavedScene_ReturnsNoScene() + { + EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); + + var result = JObject.FromObject(NavMeshBakeCommands.BakeNavMesh()); + Assert.AreEqual("no_scene", result["code"].Value()); + } + + [Test] + public void NavMeshBakeStatus_AlwaysHasStatusField() + { + var json = JObject.Parse(NavMeshBakeCommands.NavMeshBakeStatus()); + Assert.IsNotNull(json["status"]); + } + + [Test] + public void BakeNavMeshSurfaces_WithoutPackage_ReturnsPackageNotFound() + { + // This repo does not reference com.unity.ai.navigation, so the stub should report the + // package is absent (or, if the package is present in the host project, not_implemented). + var result = JObject.FromObject(NavMeshBakeCommands.BakeNavMeshSurfaces()); + var code = result["code"].Value(); + Assert.That(code, Is.EqualTo("package_not_found").Or.EqualTo("not_implemented")); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking/NavMeshBakeCommandsTests.cs.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking/NavMeshBakeCommandsTests.cs.meta new file mode 100644 index 0000000..5114ac5 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking/NavMeshBakeCommandsTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d88fed4842cc4242b9e25237547c5514 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking/OcclusionBakeCommandsTests.cs b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking/OcclusionBakeCommandsTests.cs new file mode 100644 index 0000000..9f80356 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking/OcclusionBakeCommandsTests.cs @@ -0,0 +1,69 @@ +using System.Linq; +using Newtonsoft.Json.Linq; +using NUnit.Framework; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor; +using Unity.Pipeline.Editor.Commands.Baking; +using UnityEditor.SceneManagement; + +namespace Unity.Pipeline.Tests.Editor.Baking +{ + /// + /// Tests for the CLI-215 occlusion-culling bake commands. Covers discovery/schema, the destructive + /// clear guard, the idle status, the no_scene guard, and dry_run being a no-op (and echoing the + /// effective parameters). The full bake → succeeded flow is exercised live. + /// + class OcclusionBakeCommandsTests + { + [SetUp] + public void SetUp() => CommandRegistry.SetDiscovery(new TypeCacheCommandDiscovery()); + + [TearDown] + public void TearDown() + { + EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); + } + + [Test] + public void OcclusionCommands_AreDiscovered_WithExpectedSchema() + { + var commands = CommandRegistry.DiscoverCommands().ToList(); + + var bake = commands.FirstOrDefault(c => c.Name == "bake_occlusion_culling"); + Assert.IsNotNull(bake, "Should discover bake_occlusion_culling"); + CollectionAssert.AreEquivalent( + new[] { "smallest_occluder", "smallest_hole", "backface_threshold", "confirm", "dry_run" }, + bake.Parameters.Select(p => p.Name).ToList()); + + var status = commands.FirstOrDefault(c => c.Name == "occlusion_bake_status"); + Assert.IsNotNull(status, "Should discover occlusion_bake_status"); + Assert.IsFalse(status.MainThreadRequired, "occlusion_bake_status must be off-main-thread"); + Assert.AreEqual(0, status.Parameters.Count, "occlusion_bake_status takes no parameters"); + + Assert.IsNotNull(commands.FirstOrDefault(c => c.Name == "cancel_occlusion_bake")); + Assert.IsNotNull(commands.FirstOrDefault(c => c.Name == "clear_occlusion_culling")); + } + + [Test] + public void ClearOcclusion_WithoutConfirm_Throws() + { + Assert.Throws(() => OcclusionBakeCommands.ClearOcclusionCulling()); + } + + [Test] + public void BakeOcclusion_NoOpenSavedScene_ReturnsNoScene() + { + EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); + + var result = JObject.FromObject(OcclusionBakeCommands.BakeOcclusionCulling()); + Assert.AreEqual("no_scene", result["code"].Value()); + } + + [Test] + public void OcclusionBakeStatus_AlwaysHasStatusField() + { + var json = JObject.Parse(OcclusionBakeCommands.OcclusionBakeStatus()); + Assert.IsNotNull(json["status"]); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking/OcclusionBakeCommandsTests.cs.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking/OcclusionBakeCommandsTests.cs.meta new file mode 100644 index 0000000..d8a677e --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Baking/OcclusionBakeCommandsTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f65c8110a95f44cbbf3aaf0d9832aa0e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Batch.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Batch.meta new file mode 100644 index 0000000..1a024de --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Batch.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1f0ae5fba45d4e60a0bfc82f77f35069 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Batch/BatchCommandTests.cs b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Batch/BatchCommandTests.cs new file mode 100644 index 0000000..07c9be5 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Batch/BatchCommandTests.cs @@ -0,0 +1,958 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text.RegularExpressions; +using NUnit.Framework; +using Newtonsoft.Json.Linq; +using Unity.Pipeline; +using Unity.Pipeline.Editor.Commands.Batch; +using Unity.Pipeline.Editor.Commands.GameObjects; +using UnityEditor; +using UnityEngine; +using UnityEngine.TestTools; +using Object = UnityEngine.Object; + +namespace Unity.Pipeline.Tests.Editor.Batch +{ + /// + /// Tests for the transactional batch command (AUTHAPI-27), driven end-to-end through an + /// isolated (the ViaClient pattern). Covers the acceptance + /// criteria: cross-op references resolve, a mid-batch failure atomically rolls back every prior + /// op, a successful batch collapses into a single Undo group, dry-run validates without mutating, + /// a bad reference errors clearly, on_error=continue applies independent ops without + /// reverting, and the 200-op cap is enforced. + /// + class BatchCommandTests + { + private readonly List m_Spawned = new List(); + + private GameObject Track(GameObject go) + { + if (go != null) + m_Spawned.Add(go); + return go; + } + + private static ObjectId? InstanceIdOf(JToken opResult) => + opResult?["result"]?["instanceId"]?.ToObject(); + + private GameObject ResolveGameObject(JToken opResult) + { + var id = InstanceIdOf(opResult); + if (!id.HasValue) + return null; + return Track(PipelineUtils.IdToObject(id.Value) as GameObject); + } + + [TearDown] + public void TearDown() + { + foreach (var go in m_Spawned) + { + if (go != null) + Object.DestroyImmediate(go); + } + m_Spawned.Clear(); + + // Deliberately NO Undo.ClearAll() here: this suite runs inside the dogfood editor, and + // wiping the global Undo stack would destroy the developer's own undo history. Per-test + // state is cleaned up by destroying m_Spawned above; the batch Undo groups left on the + // stack only reference those (now destroyed) test objects and are inert. + } + + private static JObject Op(string command, JObject parameters = null, string id = null) + { + var op = new JObject { ["command"] = command }; + if (id != null) + op["id"] = id; + op["params"] = parameters ?? new JObject(); + return op; + } + + [Test] + public void Batch_CrossOpReferences_ResolveAndApply() + { + // AC: create_gameobject -> add_component -> set_serialized_field, where later ops use + // $0.instanceId / $1.instanceId, executes in one round-trip with references resolved. + using (var server = new PipelineTestServer()) + { + var operations = new JArray + { + Op("create_gameobject", new JObject { ["name"] = "BatchRef_Root" }), + Op("add_component", new JObject { ["target"] = "$0.instanceId", ["type"] = "Rigidbody" }), + Op("set_serialized_field", new JObject + { + ["target"] = "$1.instanceId", + ["field"] = "m_Mass", + ["value"] = new JValue(2.5f) + }), + }; + + var response = server.Execute("batch", new JObject { ["operations"] = operations }); + Assert.IsTrue(response.IsSuccess, $"batch should return HTTP success: {response.RawResponse}"); + + var batch = response.JsonResponse["result"]; + Assert.AreEqual(3, batch["applied"]?.ToObject(), "all three ops should apply"); + Assert.IsFalse(batch["reverted"]?.ToObject() ?? true, "a successful batch must not revert"); + Assert.IsNotNull(batch["undoGroup"], "execution result should carry the batch Undo group"); + + var results = batch["results"] as JArray; + Assert.AreEqual(3, results.Count); + for (int i = 0; i < 3; i++) + Assert.IsTrue(results[i]["success"]?.ToObject() ?? false, + $"op {i} should succeed: {results[i]["error"]}"); + + // The reference chain wired a Rigidbody onto op 0's GameObject and set its mass. + var root = ResolveGameObject(results[0]); + Assert.IsNotNull(root, "op 0's GameObject should be resolvable from its returned instanceId"); + var rb = root.GetComponent(); + Assert.IsNotNull(rb, "$0.instanceId must resolve so add_component targets op 0's GameObject"); + Assert.AreEqual(2.5f, rb.mass, 0.0001f, + "$1.instanceId must resolve so set_serialized_field targets the added Rigidbody"); + } + } + + [Test] + public void Batch_Transactional_MidBatchFailure_RevertsAllPriorOps() + { + // AC: an op fails mid-batch -> every prior op is reverted; scene equals pre-batch state. + using (var server = new PipelineTestServer()) + { + var operations = new JArray + { + Op("create_gameobject", new JObject { ["name"] = "BatchRollback_A" }), + Op("create_gameobject", new JObject { ["name"] = "BatchRollback_B" }), + // Fails: unknown component type -> add_component throws before mutating. + Op("add_component", new JObject { ["target"] = "$0.instanceId", ["type"] = "NoSuchTypeXYZ" }), + }; + + // The failing sub-op logs an error through the shared command-dispatch path (batch + // reuses it); the batch surfaces the failure structurally, but the log still fires. + LogAssert.Expect(LogType.Error, new Regex("add_component' failed: Could not resolve component type 'NoSuchTypeXYZ'")); + + var response = server.Execute("batch", new JObject { ["operations"] = operations }); + Assert.IsTrue(response.IsSuccess, $"batch itself should return HTTP success: {response.RawResponse}"); + + var batch = response.JsonResponse["result"]; + Assert.IsTrue(batch["reverted"]?.ToObject() ?? false, "a transactional failure must revert"); + Assert.AreEqual(2, batch["applied"]?.ToObject(), "two ops ran before the failure"); + + var results = batch["results"] as JArray; + Assert.IsTrue(results[0]["success"]?.ToObject() ?? false); + Assert.IsTrue(results[1]["success"]?.ToObject() ?? false); + Assert.IsFalse(results[2]["success"]?.ToObject() ?? true, "op 2 must fail"); + StringAssert.Contains("component type", results[2]["error"]?.ToString(), + "the failing op's error should be reported"); + + // The two created objects must be gone (reverted), both by name and by their ids. + Assert.AreEqual(0, GameObjectCommands.FindGameObjects(name: "BatchRollback_A").Count, + "op 0's object must be reverted"); + Assert.AreEqual(0, GameObjectCommands.FindGameObjects(name: "BatchRollback_B").Count, + "op 1's object must be reverted"); + + var id0 = InstanceIdOf(results[0]); + var id1 = InstanceIdOf(results[1]); + Assert.IsTrue(id0.HasValue && id1.HasValue, "reverted ops still report the ids they had created"); + Assert.IsNull(PipelineUtils.IdToObject(id0.Value), "op 0's object should no longer resolve"); + Assert.IsNull(PipelineUtils.IdToObject(id1.Value), "op 1's object should no longer resolve"); + } + } + + [Test] + public void Batch_SuccessfulBatch_CollapsesIntoSingleUndoGroup() + { + // AC: a successful batch shows exactly one Undo group -> a single Undo reverts the whole batch. + using (var server = new PipelineTestServer()) + { + var operations = new JArray + { + Op("create_gameobject", new JObject { ["name"] = "BatchUndo_A" }), + Op("create_gameobject", new JObject { ["name"] = "BatchUndo_B" }), + }; + + var response = server.Execute("batch", new JObject { ["operations"] = operations }); + Assert.IsTrue(response.IsSuccess, $"batch should return HTTP success: {response.RawResponse}"); + + // Track the created objects so TearDown cleans them up even if the Undo below misbehaves. + var results = response.JsonResponse["result"]["results"] as JArray; + ResolveGameObject(results[0]); + ResolveGameObject(results[1]); + + Assert.AreEqual(1, GameObjectCommands.FindGameObjects(name: "BatchUndo_A").Count); + Assert.AreEqual(1, GameObjectCommands.FindGameObjects(name: "BatchUndo_B").Count); + + // One Undo must revert BOTH creations, proving the whole batch collapsed into one group. + Undo.PerformUndo(); + + Assert.AreEqual(0, GameObjectCommands.FindGameObjects(name: "BatchUndo_A").Count, + "a single Undo should revert the first op (batch is one group)"); + Assert.AreEqual(0, GameObjectCommands.FindGameObjects(name: "BatchUndo_B").Count, + "a single Undo should revert the second op too (batch is one group)"); + } + } + + [Test] + public void Batch_DryRun_CatchesErrors_AndMutatesNothing() + { + // AC: dry_run catches unknown command, not_batchable, unknown param, and a bad reference, + // with zero mutation. + using (var server = new PipelineTestServer()) + { + var operations = new JArray + { + Op("create_gameobject", new JObject { ["name"] = "BatchDry_A" }), // valid + Op("no_such_command_xyz"), // unknown command + Op("build"), // not_batchable + Op("create_gameobject", new JObject { ["bogus_param"] = "x" }), // unknown parameter + Op("add_component", new JObject { ["target"] = "$9.instanceId", ["type"] = "Rigidbody" }), // bad ref + }; + + var response = server.Execute("batch", new JObject + { + ["operations"] = operations, + ["dry_run"] = true + }); + Assert.IsTrue(response.IsSuccess, $"dry_run should return HTTP success: {response.RawResponse}"); + + var batch = response.JsonResponse["result"]; + Assert.IsTrue(batch["dryRun"]?.ToObject() ?? false, "result should be marked dryRun"); + Assert.IsFalse(batch["valid"]?.ToObject() ?? true, "the batch has invalid ops"); + Assert.AreEqual(0, batch["applied"]?.ToObject() ?? -1, "dry_run applies nothing"); + + var results = batch["results"] as JArray; + Assert.IsTrue(results[0]["success"]?.ToObject() ?? false, "op 0 is valid"); + StringAssert.Contains("unknown command", results[1]["error"]?.ToString()); + StringAssert.Contains("not_batchable", results[2]["error"]?.ToString()); + StringAssert.Contains("unknown parameter", results[3]["error"]?.ToString()); + StringAssert.Contains("unknown operation", results[4]["error"]?.ToString()); + + // Zero mutation: the valid create op must NOT have run. + Assert.AreEqual(0, GameObjectCommands.FindGameObjects(name: "BatchDry_A").Count, + "dry_run must not create anything"); + } + } + + [Test] + public void Batch_BadReference_ErrorsClearly_AndReverts() + { + // AC: a bad reference errors clearly. Here op 1 references a nonexistent op; under the + // default transactional/abort policy op 0 is reverted. + using (var server = new PipelineTestServer()) + { + var operations = new JArray + { + Op("create_gameobject", new JObject { ["name"] = "BatchBadRef_X" }), + Op("add_component", new JObject { ["target"] = "$5.instanceId", ["type"] = "Rigidbody" }), + }; + + var response = server.Execute("batch", new JObject { ["operations"] = operations }); + Assert.IsTrue(response.IsSuccess, $"batch should return HTTP success: {response.RawResponse}"); + + var batch = response.JsonResponse["result"]; + var results = batch["results"] as JArray; + Assert.IsFalse(results[1]["success"]?.ToObject() ?? true, "the referencing op must fail"); + var error = results[1]["error"]?.ToString(); + StringAssert.Contains("$5.instanceId", error, "the error should name the offending reference"); + StringAssert.Contains("unknown operation", error, "and explain why it is invalid"); + + Assert.IsTrue(batch["reverted"]?.ToObject() ?? false, "the prior op must be reverted"); + Assert.AreEqual(0, GameObjectCommands.FindGameObjects(name: "BatchBadRef_X").Count, + "op 0 must be reverted after the bad reference"); + } + } + + [Test] + public void Batch_OnErrorContinue_AppliesIndependentOps_NoRevert() + { + // AC: on_error=continue collects failures, applies independent ops, reports reverted:false. + using (var server = new PipelineTestServer()) + { + var operations = new JArray + { + Op("create_gameobject", new JObject { ["name"] = "BatchCont_A" }), + Op("add_component", new JObject { ["target"] = "$0.instanceId", ["type"] = "NoSuchTypeXYZ" }), // fails + Op("create_gameobject", new JObject { ["name"] = "BatchCont_C" }), // independent + }; + + LogAssert.Expect(LogType.Error, new Regex("add_component' failed: Could not resolve component type 'NoSuchTypeXYZ'")); + + var response = server.Execute("batch", new JObject + { + ["operations"] = operations, + ["on_error"] = "continue" + }); + Assert.IsTrue(response.IsSuccess, $"batch should return HTTP success: {response.RawResponse}"); + + var batch = response.JsonResponse["result"]; + Assert.IsFalse(batch["reverted"]?.ToObject() ?? true, "continue must not revert"); + Assert.IsFalse(batch["transactional"]?.ToObject() ?? true, "continue forces transactional=false"); + Assert.AreEqual(2, batch["applied"]?.ToObject(), "the two independent creates apply"); + + var results = batch["results"] as JArray; + Assert.IsTrue(results[0]["success"]?.ToObject() ?? false); + Assert.IsFalse(results[1]["success"]?.ToObject() ?? true, "the middle op fails"); + Assert.IsTrue(results[2]["success"]?.ToObject() ?? false, "a later independent op still runs"); + + // Both independent objects must survive (no rollback). + Assert.IsNotNull(ResolveGameObject(results[0]), "op 0's object should survive"); + Assert.IsNotNull(ResolveGameObject(results[2]), "op 2's object should survive"); + } + } + + [Test] + public void Batch_ExceedsOperationCap_ReturnsError() + { + // AC: the 200-op cap is enforced with a structured error (checked before anything runs). + using (var server = new PipelineTestServer()) + { + var operations = new JArray(); + for (int i = 0; i < 201; i++) + operations.Add(Op("create_gameobject", new JObject { ["name"] = "BatchCap_" + i })); + + LogAssert.Expect(LogType.Error, new Regex("batch supports at most 200 operations")); + + var response = server.Execute("batch", new JObject + { + ["operations"] = operations, + ["dry_run"] = true + }); + + Assert.IsFalse(response.IsSuccess, "a batch over the op cap must be rejected"); + StringAssert.Contains("200", response.RawResponse, "the error should state the 200-op cap"); + Assert.AreEqual(0, GameObjectCommands.FindGameObjects(name: "BatchCap_0").Count, + "an over-cap batch must create nothing"); + } + } + + [Test] + public void Batch_AsyncCommand_NotBatchable_AtDryRunAndExecution() + { + // C1: run_tests/list_tests are async Task commands completed by EditorApplication.update + // callbacks, which cannot fire while the batch blocks the main thread — awaiting them + // inline would freeze the editor permanently. They must be rejected, not dispatched. + using (var server = new PipelineTestServer()) + { + var operations = new JArray + { + Op("run_tests", new JObject { ["mode"] = "EditMode" }), + Op("list_tests"), + }; + + // Dry run flags both without executing anything. + var response = server.Execute("batch", new JObject + { + ["operations"] = operations, + ["dry_run"] = true + }); + Assert.IsTrue(response.IsSuccess, $"dry_run should return HTTP success: {response.RawResponse}"); + var results = response.JsonResponse["result"]["results"] as JArray; + foreach (var opResult in results) + { + Assert.IsFalse(opResult["success"]?.ToObject() ?? true, "async ops must fail validation"); + StringAssert.Contains("not_batchable", opResult["error"]?.ToString()); + StringAssert.Contains("async", opResult["error"]?.ToString()); + } + + // Execution rejects them the same way — and returns instead of hanging. + response = server.Execute("batch", new JObject { ["operations"] = new JArray { Op("run_tests") } }); + Assert.IsTrue(response.IsSuccess, $"batch should return HTTP success: {response.RawResponse}"); + var exec = response.JsonResponse["result"]; + Assert.AreEqual(0, exec["applied"]?.ToObject(), "nothing must be dispatched"); + StringAssert.Contains("not_batchable", exec["results"][0]["error"]?.ToString()); + } + } + + [Test] + public void Batch_Transactional_RejectsNonRevertibleCommand_NonTransactionalAllowsIt() + { + // C2: delete_asset mutates the AssetDatabase, which Undo cannot roll back — inside a + // transactional batch "reverted: true" would be a lie, so it is rejected. With + // transactional:false it runs and reports revertible:false. + const string assetPath = "Assets/BatchTests_DeleteTarget.txt"; + File.WriteAllText(assetPath, "batch delete target"); + AssetDatabase.ImportAsset(assetPath); + try + { + using (var server = new PipelineTestServer()) + { + var operations = new JArray + { + Op("delete_asset", new JObject { ["asset"] = assetPath, ["confirm"] = true }), + }; + + // Dry run under the default transactional=true flags it. + var response = server.Execute("batch", new JObject + { + ["operations"] = operations, + ["dry_run"] = true + }); + var dry = response.JsonResponse["result"]; + Assert.IsFalse(dry["valid"]?.ToObject() ?? true); + StringAssert.Contains("not_batchable_transactional", dry["results"][0]["error"]?.ToString()); + + // Execution under transactional=true rejects it too; the asset survives. + response = server.Execute("batch", new JObject { ["operations"] = operations }); + var exec = response.JsonResponse["result"]; + Assert.IsFalse(exec["results"][0]["success"]?.ToObject() ?? true); + StringAssert.Contains("not_batchable_transactional", exec["results"][0]["error"]?.ToString()); + Assert.IsNotNull(AssetDatabase.LoadMainAssetAtPath(assetPath), + "a rejected delete_asset must not touch the asset"); + + // transactional:false allows it — with an honest revertible:false on the op. + response = server.Execute("batch", new JObject + { + ["operations"] = operations, + ["transactional"] = false + }); + exec = response.JsonResponse["result"]; + Assert.IsTrue(exec["results"][0]["success"]?.ToObject() ?? false, + $"transactional:false must allow delete_asset: {exec["results"][0]["error"]}"); + Assert.IsFalse(exec["results"][0]["revertible"]?.ToObject() ?? true, + "the op must report revertible:false"); + Assert.IsNull(AssetDatabase.LoadMainAssetAtPath(assetPath), "the asset must be deleted"); + } + } + finally + { + if (AssetDatabase.LoadMainAssetAtPath(assetPath) != null) + AssetDatabase.DeleteAsset(assetPath); + } + } + + [Test] + public void Batch_OpenScene_AlwaysRejected_EvenNonTransactional() + { + // C2: open_scene/create_scene CLEAR the Editor Undo stack, destroying the batch's ability + // to revert anything before them — they are rejected regardless of the transactional flag. + using (var server = new PipelineTestServer()) + { + var operations = new JArray + { + Op("open_scene", new JObject { ["path"] = "Assets/Nope.unity" }), + }; + + var response = server.Execute("batch", new JObject + { + ["operations"] = operations, + ["dry_run"] = true + }); + var dry = response.JsonResponse["result"]; + StringAssert.Contains("not_batchable", dry["results"][0]["error"]?.ToString()); + StringAssert.Contains("Undo stack", dry["results"][0]["error"]?.ToString()); + + response = server.Execute("batch", new JObject + { + ["operations"] = operations, + ["transactional"] = false + }); + var exec = response.JsonResponse["result"]; + Assert.IsFalse(exec["results"][0]["success"]?.ToObject() ?? true); + StringAssert.Contains("not_batchable", exec["results"][0]["error"]?.ToString()); + } + } + + [Test] + public void Batch_FirstOpPartialMutation_IsRolledBack() + { + // I1: an op that mutates and THEN throws leaves partial Undo-registered state even when + // it is the first (and only) op — the transactional rollback must run with applied == 0. + // set_transform applies 'position' before it parses the invalid 'rotation'. + using (var server = new PipelineTestServer()) + { + var go = Track(new GameObject("BatchPartial_Target")); + go.transform.localPosition = Vector3.zero; + + var operations = new JArray + { + Op("set_transform", new JObject + { + // Version-stable id: GetInstanceID() is obsolete-as-error from 6000.4. + ["target"] = PipelineUtils.GetObjectId(go).RawValue, + ["position"] = new JArray(5f, 6f, 7f), + ["rotation"] = new JArray(1f, 2f), // invalid: 2 components -> throws after position applied + }), + }; + + LogAssert.Expect(LogType.Error, new Regex("set_transform' failed: 'rotation' must have exactly 3 components")); + + var response = server.Execute("batch", new JObject { ["operations"] = operations }); + Assert.IsTrue(response.IsSuccess, $"batch should return HTTP success: {response.RawResponse}"); + + var batch = response.JsonResponse["result"]; + Assert.AreEqual(0, batch["applied"]?.ToObject(), "the only op failed"); + Assert.IsTrue(batch["reverted"]?.ToObject() ?? false, + "a transactional failure must revert even when applied == 0"); + Assert.AreEqual(0f, go.transform.localPosition.magnitude, 0.0001f, + "the failing op's partial position change must be reverted"); + } + } + + [Test] + public void Batch_TimeBudgetExceeded_SkipsRemainingOps_AndRevertsTransactional() + { + // I2: the cooperative time budget is checked before each op after the first. Budget 0 is + // exhausted immediately after op 0, so ops 1..n are skipped and the transactional batch + // rolls back with a batch-level error. + using (var server = new PipelineTestServer()) + { + var operations = new JArray + { + Op("create_gameobject", new JObject { ["name"] = "BatchBudget_A" }), + Op("create_gameobject", new JObject { ["name"] = "BatchBudget_B" }), + Op("create_gameobject", new JObject { ["name"] = "BatchBudget_C" }), + }; + + var response = server.Execute("batch", new JObject + { + ["operations"] = operations, + ["time_budget_ms"] = 0 + }); + Assert.IsTrue(response.IsSuccess, $"batch should return HTTP success: {response.RawResponse}"); + + var batch = response.JsonResponse["result"]; + StringAssert.Contains("batch time budget exceeded", batch["error"]?.ToString()); + Assert.AreEqual(1, batch["applied"]?.ToObject(), "only op 0 runs on a zero budget"); + Assert.IsTrue(batch["reverted"]?.ToObject() ?? false, "budget abort is a transactional failure"); + + var results = batch["results"] as JArray; + Assert.AreEqual(3, results.Count); + Assert.IsTrue(results[0]["success"]?.ToObject() ?? false, "op 0 always gets to run"); + Assert.IsTrue(results[1]["skipped"]?.ToObject() ?? false, "op 1 must be skipped"); + Assert.IsTrue(results[2]["skipped"]?.ToObject() ?? false, "op 2 must be skipped"); + + Assert.AreEqual(0, GameObjectCommands.FindGameObjects(name: "BatchBudget_A").Count, + "op 0 must be reverted by the budget-abort rollback"); + Assert.AreEqual(0, GameObjectCommands.FindGameObjects(name: "BatchBudget_B").Count); + } + } + + [Test] + public void Batch_ReferenceToFailedOp_ErrorsClearly() + { + // I3: under on_error=continue an op can fail without stopping the batch; a later $ref + // into the failed op must error explicitly instead of silently resolving to null. + using (var server = new PipelineTestServer()) + { + var operations = new JArray + { + Op("add_component", new JObject { ["target"] = "/NoSuchObjectXYZ_00", ["type"] = "Rigidbody" }), // fails + Op("rename_gameobject", new JObject { ["target"] = "$0.instanceId", ["name"] = "Renamed" }), + }; + + LogAssert.Expect(LogType.Error, new Regex("add_component' failed:")); + + var response = server.Execute("batch", new JObject + { + ["operations"] = operations, + ["on_error"] = "continue" + }); + Assert.IsTrue(response.IsSuccess, $"batch should return HTTP success: {response.RawResponse}"); + + var results = response.JsonResponse["result"]["results"] as JArray; + Assert.IsFalse(results[0]["success"]?.ToObject() ?? true, "op 0 must fail"); + Assert.IsFalse(results[1]["success"]?.ToObject() ?? true, "the referencing op must fail"); + var error = results[1]["error"]?.ToString(); + StringAssert.Contains("$0.instanceId", error, "the error should name the offending reference"); + StringAssert.Contains("failed; its result cannot be referenced", error, + "and say the referenced op failed"); + } + } + + [Test] + public void Resolver_ReferenceToVoidResult_Errors_WholeValueAndPath() + { + // I3: a SUCCEEDED op with a null result (void command) is distinct from a failed op — + // referencing it errors with "returned no result", for whole-value and path refs alike. + var operations = new List + { + new BatchOperationInput { Command = "noop_a" }, + new BatchOperationInput { Command = "noop_b" }, + }; + var outcomes = new List + { + new BatchOperationResult { Command = "noop_a", Success = true }, + new BatchOperationResult { Command = "noop_b" }, + }; + var results = new JToken[] { JValue.CreateNull(), null }; + var idToIndex = new Dictionary(); + + var wholeRef = new JObject { ["value"] = "$0" }; + var ex = Assert.Throws(() => + BatchReferenceResolver.Resolve(wholeRef, 1, operations, idToIndex, results, outcomes)); + StringAssert.Contains("returned no result", ex.Message); + + var pathRef = new JObject { ["value"] = "$0.instanceId" }; + ex = Assert.Throws(() => + BatchReferenceResolver.Resolve(pathRef, 1, operations, idToIndex, results, outcomes)); + StringAssert.Contains("returned no result", ex.Message); + } + + [Test] + public void Resolver_ReferenceToFailedOp_Errors_WholeValueAndPath() + { + // I3: whole-value refs into a FAILED op must error just like path refs (the end-to-end + // test above covers the path form; this pins the whole-value form). + var operations = new List + { + new BatchOperationInput { Command = "noop_a" }, + new BatchOperationInput { Command = "noop_b" }, + }; + var outcomes = new List + { + new BatchOperationResult { Command = "noop_a", Success = false, Error = "boom" }, + new BatchOperationResult { Command = "noop_b" }, + }; + var results = new JToken[] { null, null }; + var idToIndex = new Dictionary(); + + var wholeRef = new JObject { ["value"] = "$0" }; + var ex = Assert.Throws(() => + BatchReferenceResolver.Resolve(wholeRef, 1, operations, idToIndex, results, outcomes)); + StringAssert.Contains("failed; its result cannot be referenced", ex.Message); + } + + [Test] + public void Batch_RuntimeOnlyCommand_NotBatchable() + { + // I5: runtime-only commands (Player server surface) are discoverable via the registry but + // must not be dispatchable through an editor-server batch. + using (var server = new PipelineTestServer()) + { + var response = server.Execute("batch", new JObject + { + ["operations"] = new JArray { Op("set_timescale", new JObject { ["scale"] = 0.5f }) }, + ["dry_run"] = true + }); + + var dry = response.JsonResponse["result"]; + Assert.IsFalse(dry["valid"]?.ToObject() ?? true); + var error = dry["results"][0]["error"]?.ToString(); + StringAssert.Contains("not_batchable", error); + StringAssert.Contains("runtime-only", error); + } + } + + [Test] + public void Batch_MenuCommand_NotBatchable() + { + // I6: menu items can open modal dialogs, which would wedge an unattended batch. + using (var server = new PipelineTestServer()) + { + var response = server.Execute("batch", new JObject + { + ["operations"] = new JArray { Op("menu", new JObject { ["path"] = "File/Save" }) }, + ["dry_run"] = true + }); + + var dry = response.JsonResponse["result"]; + Assert.IsFalse(dry["valid"]?.ToObject() ?? true); + StringAssert.Contains("not_batchable", dry["results"][0]["error"]?.ToString()); + } + } + + [Test] + public void Batch_NumericOpId_Rejected() + { + // M3: a purely numeric id would be ambiguous with a 0-based index selector in "$". + using (var server = new PipelineTestServer()) + { + var operations = new JArray + { + Op("create_gameobject", new JObject { ["name"] = "BatchId_A" }, id: "0"), + }; + + LogAssert.Expect(LogType.Error, new Regex("ids must match")); + + var response = server.Execute("batch", new JObject + { + ["operations"] = operations, + ["dry_run"] = true + }); + + Assert.IsFalse(response.IsSuccess, "a numeric op id must be rejected outright"); + StringAssert.Contains("ids must match", response.RawResponse); + } + } + + [Test] + public void Batch_DollarDollar_EscapesToLiteralDollar() + { + // M7: "$$..." escapes a literal '$' — the op receives "$literal", not a reference. + using (var server = new PipelineTestServer()) + { + var operations = new JArray + { + Op("create_gameobject", new JObject { ["name"] = "$$literal" }), + }; + + var response = server.Execute("batch", new JObject { ["operations"] = operations }); + Assert.IsTrue(response.IsSuccess, $"batch should return HTTP success: {response.RawResponse}"); + + var results = response.JsonResponse["result"]["results"] as JArray; + var go = ResolveGameObject(results[0]); + Assert.IsNotNull(go, "op 0's GameObject should be resolvable"); + Assert.AreEqual("$literal", go.name, "\"$$literal\" must unescape to the literal \"$literal\""); + } + } + + [Test] + public void Batch_IdBasedReference_Resolves() + { + // M7: references can select the target op by its id, not only by index. + using (var server = new PipelineTestServer()) + { + var operations = new JArray + { + Op("create_gameobject", new JObject { ["name"] = "BatchIdRef_Root" }, id: "root"), + Op("add_component", new JObject { ["target"] = "$root.instanceId", ["type"] = "Rigidbody" }), + }; + + var response = server.Execute("batch", new JObject { ["operations"] = operations }); + Assert.IsTrue(response.IsSuccess, $"batch should return HTTP success: {response.RawResponse}"); + + var batch = response.JsonResponse["result"]; + Assert.AreEqual(2, batch["applied"]?.ToObject(), + $"both ops should apply: {batch["results"]}"); + + var root = ResolveGameObject((batch["results"] as JArray)[0]); + Assert.IsNotNull(root); + Assert.IsNotNull(root.GetComponent(), "$root.instanceId must resolve by op id"); + } + } + + [Test] + public void Batch_ResultFields_ProjectsOpResult() + { + // M7: result_fields keeps only the requested result fields for the op (context economy). + using (var server = new PipelineTestServer()) + { + var operations = new JArray + { + Op("create_gameobject", new JObject { ["name"] = "BatchProject_A" }), + }; + + var response = server.Execute("batch", new JObject + { + ["operations"] = operations, + ["result_fields"] = new JObject { ["0"] = new JArray("instanceId") } + }); + Assert.IsTrue(response.IsSuccess, $"batch should return HTTP success: {response.RawResponse}"); + + var results = response.JsonResponse["result"]["results"] as JArray; + var projected = results[0]["result"] as JObject; + Assert.IsNotNull(projected, "the projected result should be an object"); + Assert.IsNotNull(projected["instanceId"], "the requested field must be kept"); + Assert.IsNull(projected["hierarchyPath"], "unrequested fields must be dropped"); + Assert.IsNull(projected["globalId"], "unrequested fields must be dropped"); + + // Cleanup: the projection kept instanceId, so the object is still resolvable. + Assert.IsNotNull(ResolveGameObject(results[0])); + } + } + + [Test] + public void Batch_OversizedOpResult_Truncated_ButReferencesStillResolve() + { + // M7: an op result over the per-op cap is replaced by a truncation marker in the envelope, + // but later $refs resolve against the FULL (untruncated) result. + const string bigPath = "Assets/BatchTests_BigFile.txt"; + File.WriteAllText(bigPath, new string('x', 20000)); // > 16 KiB serialized + try + { + using (var server = new PipelineTestServer()) + { + var operations = new JArray + { + Op("read_text_file", new JObject { ["path"] = bigPath }), + // References a scalar of the oversized result — must still resolve. + Op("create_gameobject", new JObject { ["name"] = "$0.assetPath" }), + }; + + var response = server.Execute("batch", new JObject { ["operations"] = operations }); + Assert.IsTrue(response.IsSuccess, $"batch should return HTTP success: {response.RawResponse}"); + + var results = response.JsonResponse["result"]["results"] as JArray; + Assert.IsTrue(results[0]["resultTruncated"]?.ToObject() ?? false, + "the oversized read_text_file result must be truncated"); + Assert.IsTrue(results[0]["result"]?["resultTruncated"]?.ToObject() ?? false, + "the result must be replaced by the truncation marker"); + + Assert.IsTrue(results[1]["success"]?.ToObject() ?? false, + $"the referencing op must still succeed: {results[1]["error"]}"); + var go = ResolveGameObject(results[1]); + Assert.IsNotNull(go); + Assert.AreEqual(bigPath, go.name, "$0.assetPath must resolve against the untruncated result"); + } + } + finally + { + if (File.Exists(bigPath)) + File.Delete(bigPath); + if (File.Exists(bigPath + ".meta")) + File.Delete(bigPath + ".meta"); + } + } + + [Test] + public void Batch_NestedBatch_Rejected() + { + // M7: batch-in-batch is excluded (recursion/auditing hazard). + using (var server = new PipelineTestServer()) + { + var response = server.Execute("batch", new JObject + { + ["operations"] = new JArray { Op("batch", new JObject { ["operations"] = new JArray() }) }, + ["dry_run"] = true + }); + + var dry = response.JsonResponse["result"]; + Assert.IsFalse(dry["valid"]?.ToObject() ?? true); + StringAssert.Contains("not_batchable", dry["results"][0]["error"]?.ToString()); + } + } + + [Test] + public void Batch_NonTransactional_Abort_KeepsAppliedOps_SkipsRest() + { + // M7: transactional:false + on_error=abort stops at the failing op but keeps what was + // already applied (no rollback), and marks the rest skipped. + using (var server = new PipelineTestServer()) + { + var operations = new JArray + { + Op("create_gameobject", new JObject { ["name"] = "BatchNoTx_A" }), + Op("add_component", new JObject { ["target"] = "$0.instanceId", ["type"] = "NoSuchTypeXYZ" }), // fails + Op("create_gameobject", new JObject { ["name"] = "BatchNoTx_C" }), + }; + + LogAssert.Expect(LogType.Error, new Regex("add_component' failed: Could not resolve component type 'NoSuchTypeXYZ'")); + + var response = server.Execute("batch", new JObject + { + ["operations"] = operations, + ["transactional"] = false + }); + Assert.IsTrue(response.IsSuccess, $"batch should return HTTP success: {response.RawResponse}"); + + var batch = response.JsonResponse["result"]; + Assert.IsFalse(batch["reverted"]?.ToObject() ?? true, "transactional:false must not revert"); + Assert.AreEqual(1, batch["applied"]?.ToObject()); + + var results = batch["results"] as JArray; + Assert.IsTrue(results[0]["success"]?.ToObject() ?? false); + Assert.IsFalse(results[1]["success"]?.ToObject() ?? true, "op 1 must fail"); + Assert.IsTrue(results[2]["skipped"]?.ToObject() ?? false, "op 2 must be skipped (abort)"); + + Assert.IsNotNull(ResolveGameObject(results[0]), "op 0's object must survive (no rollback)"); + Assert.AreEqual(0, GameObjectCommands.FindGameObjects(name: "BatchNoTx_C").Count, + "op 2 never ran"); + } + } + + [Test] + public void Batch_InvalidResultFieldsPath_DoesNotFailTheAppliedOp() + { + // Review finding: a malformed result_fields JSONPath threw AFTER the op had mutated + // state, and the outer catch flipped the op's Success to false — rolling back a + // succeeded op under on_error=abort. The projection must report the bad path instead. + using (var server = new PipelineTestServer()) + { + var operations = new JArray { Op("create_gameobject", new JObject { ["name"] = "BatchProj_BadPath" }) }; + var response = server.Execute("batch", new JObject + { + ["operations"] = operations, + ["result_fields"] = new JObject { ["0"] = new JArray("foo[") } + }); + Assert.IsTrue(response.IsSuccess, $"batch should return HTTP success: {response.RawResponse}"); + + var batch = response.JsonResponse["result"]; + var results = batch["results"] as JArray; + Assert.IsTrue(results[0]["success"]?.ToObject() ?? false, + "a malformed projection path must not flip an already-applied op to failure"); + Assert.IsFalse(batch["reverted"]?.ToObject() ?? true, + "and must not trigger a rollback of the succeeded op"); + StringAssert.Contains("foo[", results[0]["result"]?["invalidResultFields"]?[0]?.ToString(), + "the bad path is reported inside the projection"); + + var survivors = GameObjectCommands.FindGameObjects(name: "BatchProj_BadPath"); + Assert.AreEqual(1, survivors.Count, "the op's mutation must survive"); + Track(GameObject.Find("BatchProj_BadPath")); + } + } + + [Test] + public void Batch_TransactionalRevert_LeavesUndoStackClean() + { + // Review finding: after Undo.RevertAllDownToGroup discarded the batch group, the + // enclosing AuthoringUndoScope still collapsed that stale group id on dispose. The + // scope is now canceled after a revert; the contract this pins: the next PerformUndo + // must undo the USER's previous operation, not be absorbed by a stray batch group. + using (var server = new PipelineTestServer()) + { + Undo.IncrementCurrentGroup(); + var marker = Track(new GameObject("BatchUndoStack_Marker")); + Undo.RegisterCreatedObjectUndo(marker, "create marker"); + Undo.IncrementCurrentGroup(); + + var operations = new JArray + { + Op("create_gameobject", new JObject { ["name"] = "BatchUndoStack_Tx" }), + Op("add_component", new JObject { ["target"] = "$0.instanceId", ["type"] = "NoSuchTypeXYZ" }), + }; + LogAssert.Expect(LogType.Error, new Regex("add_component' failed: Could not resolve component type 'NoSuchTypeXYZ'")); + var response = server.Execute("batch", new JObject { ["operations"] = operations }); + Assert.IsTrue(response.IsSuccess, $"batch should return HTTP success: {response.RawResponse}"); + Assert.IsTrue(response.JsonResponse["result"]["reverted"]?.ToObject() ?? false, + "precondition: the transactional batch reverted"); + + Undo.PerformUndo(); + Assert.IsTrue(marker == null, + "PerformUndo after a reverted batch must undo the previous user operation " + + "(the marker creation) — a surviving marker means a stray batch group absorbed it"); + } + } + + [Test] + public void ProjectResult_MeasuresUtf8Bytes_NotUtf16Chars() + { + // Review finding: the per-op cap compared UTF-16 char counts while the wire is UTF-8 — + // a CJK payload at ~12k chars is ~36 KB on the wire and sailed under the 16 KiB cap. + var op = new BatchOperationInput { Command = "noop" }; + var opResult = new BatchOperationResult(); + var budget = int.MaxValue; // isolate the per-op cap from the aggregate budget + var cjk = new string('\u597D', 12_000); // 12k chars, ~36 KB UTF-8 + + var projected = BatchCommand.ProjectResult(cjk, JToken.FromObject(cjk), op, 0, null, opResult, ref budget); + + Assert.IsTrue(opResult.ResultTruncated == true, + "a payload under the char count but over the UTF-8 byte cap must be truncated"); + var marker = (JObject)JToken.FromObject(projected); + Assert.Greater(marker["length"]?.ToObject() ?? 0, 16 * 1024, "length reports wire bytes"); + } + + [Test] + public void ProjectResult_AggregateBudget_ElidesLaterResults() + { + // Review finding: nothing bounded the SUM of per-op results (200 ops x 16 KiB each is a + // ~3.2 MB reply). Once the aggregate budget is exhausted, later results become markers. + var op = new BatchOperationInput { Command = "noop" }; + var budget = BatchCommand.MaxBatchResultBytes; + var big = new string('a', 15_000); // under the per-op cap; ~17 of these exhaust the budget + + object last = null; + BatchOperationResult lastResult = null; + var truncatedAt = -1; + for (var i = 0; i < 30; i++) + { + lastResult = new BatchOperationResult(); + last = BatchCommand.ProjectResult(big, JToken.FromObject(big), op, i, null, lastResult, ref budget); + if (lastResult.ResultTruncated == true) { truncatedAt = i; break; } + } + + Assert.GreaterOrEqual(truncatedAt, 2, "several results must fit before the budget trips"); + Assert.AreNotEqual(-1, truncatedAt, "the aggregate budget must eventually trip"); + StringAssert.Contains("aggregate result budget", ((JObject)JToken.FromObject(last))["error"]?.ToString(), + "the marker explains the aggregate elision"); + } + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Batch/BatchCommandTests.cs.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Batch/BatchCommandTests.cs.meta new file mode 100644 index 0000000..082609b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Batch/BatchCommandTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7dffec4aa4e549679a30d77044ee314d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/BuildConfigCommandsTests.cs b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/BuildConfigCommandsTests.cs new file mode 100644 index 0000000..3589b5e --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/BuildConfigCommandsTests.cs @@ -0,0 +1,105 @@ +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor; +using Unity.Pipeline.Editor.Commands.Build; +using UnityEditor; + +namespace Unity.Pipeline.Tests.Editor +{ + /// + /// Tests for the build-configuration commands (CLI-204): list_build_targets, + /// get_build_settings, set_build_settings (dry run only — no real mutation), + /// list_build_profiles, and the switch_build_target command surface. The read-only + /// commands are executed directly on the test (main) thread; nothing here triggers a build or switch. + /// + class BuildConfigCommandsTests + { + [SetUp] + public void SetUp() => CommandRegistry.SetDiscovery(new TypeCacheCommandDiscovery()); + + [Test] + public void NewCommands_AreDiscovered() + { + var names = CommandRegistry.DiscoverCommands().Select(c => c.Name).ToList(); + + foreach (var expected in new[] + { + "list_build_targets", "get_build_settings", "set_build_settings", + "list_build_profiles", "switch_build_target", "switch_build_target_status" + }) + { + CollectionAssert.Contains(names, expected, $"Should discover the {expected} command"); + } + } + + [Test] + public void SwitchBuildTarget_RequiresTarget_AndConfirm() + { + var switchCmd = CommandRegistry.DiscoverCommands().First(c => c.Name == "switch_build_target"); + + var target = switchCmd.Parameters.First(p => p.Name == "target"); + Assert.IsTrue(target.Required, "switch_build_target 'target' must be required"); + + // Missing confirm must be refused without attempting the switch. + var result = JObjectOf(SwitchBuildTargetCommand.SwitchBuildTarget( + EditorUserBuildSettings.activeBuildTarget == UnityEditor.BuildTarget.StandaloneWindows64 + ? "StandaloneLinux64" + : "StandaloneWindows64", + confirm: false)); + + Assert.AreEqual("error", (string)result["status"]); + Assert.AreEqual(false, (bool)result["success"]); + } + + [Test] + public void ListBuildTargets_IncludesActiveTarget_AsInstalled() + { + var targets = (List)BuildConfigCommands.ListBuildTargets(); + Assert.IsNotNull(targets); + Assert.Greater(targets.Count, 0, "should enumerate at least one build target"); + + var active = EditorUserBuildSettings.activeBuildTarget.ToString(); + var entry = targets.FirstOrDefault(t => t.Name == active); + Assert.IsNotNull(entry, "the active build target should appear in the list"); + Assert.IsTrue(entry.IsInstalled, "the active build target must be installed"); + } + + [Test] + public void GetBuildSettings_ReportsActiveTargetAndScenes() + { + var settings = (BuildSettingsResult)BuildConfigCommands.GetBuildSettings(); + Assert.IsNotNull(settings); + Assert.AreEqual(EditorUserBuildSettings.activeBuildTarget.ToString(), settings.ActiveBuildTarget); + Assert.IsNotNull(settings.Scenes, "scene list should be present (may be empty)"); + Assert.IsNotNull(settings.Il2CppCodeGeneration); + } + + [Test] + public void SetBuildSettings_DryRun_ReportsPlan_WithoutMutating() + { + var before = EditorUserBuildSettings.development; + + var input = new SetBuildSettingsInput { DevelopmentBuild = !before }; + var result = (SetBuildSettingsResult)BuildConfigCommands.SetBuildSettings(input, dryRun: true); + + Assert.IsTrue(result.Success); + Assert.IsTrue(result.DryRun); + Assert.IsTrue(result.Applied.ContainsKey("developmentBuild"), + "the flipped field should appear in the dry-run 'applied' plan"); + Assert.AreEqual(before, EditorUserBuildSettings.development, + "a dry run must not change EditorUserBuildSettings"); + } + + [Test] + public void SetBuildSettings_NoSettings_Fails() + { + var result = (SetBuildSettingsResult)BuildConfigCommands.SetBuildSettings(null, dryRun: false); + Assert.IsFalse(result.Success); + } + + static Newtonsoft.Json.Linq.JObject JObjectOf(object value) => + Newtonsoft.Json.Linq.JObject.FromObject(value); + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/BuildConfigCommandsTests.cs.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/BuildConfigCommandsTests.cs.meta new file mode 100644 index 0000000..f786b4a --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/BuildConfigCommandsTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f6dcfbbcfcc4e70428b62c04568efe8b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Capture.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Capture.meta new file mode 100644 index 0000000..be6ac1d --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Capture.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c83fc76f10b96db43a56fd1bbf79c646 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Capture/CaptureCommandsTests.cs b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Capture/CaptureCommandsTests.cs new file mode 100644 index 0000000..f750a19 --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Capture/CaptureCommandsTests.cs @@ -0,0 +1,428 @@ +using System; +using System.Collections; +using System.IO; +using Newtonsoft.Json.Linq; +using NUnit.Framework; +using Unity.Pipeline.Editor.Authoring; +using Unity.Pipeline.Editor.Commands.Capture; +using UnityEditor; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.TestTools; + +namespace Unity.Pipeline.Tests.Editor.Capture +{ + /// + /// Tests for the visual-feedback commands (CLI-199), exercised directly and via PipelineClient. + /// Render tests are GPU-gated: under batchmode/headless the graphics device is + /// and the tests self-ignore rather than fail. + /// + class CaptureCommandsTests + { + private const string CameraName = "CLI199_Cam"; + private const string SaveFolder = "Assets/CLI199_CaptureTests"; + + // PNG file signature: 0x89 'P' 'N' 'G' 0x0D 0x0A 0x1A 0x0A. + private static readonly byte[] PngSignature = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }; + + private GameObject m_CameraObject; + + [SetUp] + public void SetUp() + { + m_CameraObject = new GameObject(CameraName); + m_CameraObject.AddComponent(); + } + + [TearDown] + public void TearDown() + { + if (m_CameraObject != null) + UnityEngine.Object.DestroyImmediate(m_CameraObject); + + if (AssetDatabase.IsValidFolder(SaveFolder)) + AssetDatabase.DeleteAsset(SaveFolder); + } + + private static string AbsolutePath(string projectRelative) => + Path.Combine(ProjectPaths.ProjectRoot, projectRelative); + + private static bool IsHeadless => SystemInfo.graphicsDeviceType == GraphicsDeviceType.Null; + + private static void AssertPngSignature(byte[] bytes) + { + Assert.GreaterOrEqual(bytes.Length, PngSignature.Length, "PNG payload too short to contain a signature"); + for (var i = 0; i < PngSignature.Length; i++) + Assert.AreEqual(PngSignature[i], bytes[i], $"PNG signature mismatch at byte {i}"); + } + + #region Direct + + [Test] + public void CaptureGameView_NamedCamera_ReturnsPng() + { + if (IsHeadless) + Assert.Ignore("No GPU in batchmode"); + + var result = CaptureCommands.CaptureGameView(64, 64, CameraName); + + Assert.IsNotNull(result, "Capture should return a result"); + Assert.IsNotEmpty(result.Base64, "Base64 payload should be non-empty"); + Assert.AreEqual(64, result.Width, "Width should match the requested size"); + Assert.AreEqual(64, result.Height, "Height should match the requested size"); + Assert.AreEqual("png", result.Encoding); + Assert.AreEqual($"camera:{CameraName}", result.Source); + Assert.IsNull(result.SavedPath, "No savePath was requested"); + + var bytes = Convert.FromBase64String(result.Base64); + AssertPngSignature(bytes); + Assert.AreEqual(bytes.Length, result.Bytes, "Reported byte length should match decoded payload"); + } + + [Test] + public void CaptureSceneView_ReturnsPng() + { + if (IsHeadless) + Assert.Ignore("No GPU in batchmode"); + + var sv = SceneView.lastActiveSceneView; + if (sv == null) + Assert.Ignore("No Scene View"); + + var result = CaptureCommands.CaptureSceneView(64, 64); + + Assert.IsNotNull(result, "Capture should return a result"); + Assert.IsNotEmpty(result.Base64, "Base64 payload should be non-empty"); + Assert.AreEqual("sceneView", result.Source); + + var bytes = Convert.FromBase64String(result.Base64); + AssertPngSignature(bytes); + } + + [Test] + public void CaptureGameView_SavePath_OmitsBase64_AndWritesPng() + { + if (IsHeadless) + Assert.Ignore("No GPU in batchmode"); + + var result = CaptureCommands.CaptureGameView(64, 64, CameraName, $"{SaveFolder}/path_only.png"); + + Assert.IsNull(result.Base64, "save_path without include_inline_image should omit the base64 payload"); + Assert.IsNotNull(result.SavedPath, "SavedPath should be set"); + + var fileBytes = File.ReadAllBytes(AbsolutePath(result.SavedPath)); + AssertPngSignature(fileBytes); + Assert.AreEqual(fileBytes.Length, result.Bytes, "Reported byte length should match the file"); + } + + [Test] + public void CaptureGameView_SavePath_IncludeImage_ReturnsFileAndBase64() + { + if (IsHeadless) + Assert.Ignore("No GPU in batchmode"); + + var result = CaptureCommands.CaptureGameView(64, 64, CameraName, $"{SaveFolder}/both.png", includeInlineImage: true); + + Assert.IsNotEmpty(result.Base64, "include_inline_image=true should return the base64 payload"); + Assert.IsNotNull(result.SavedPath, "SavedPath should be set"); + AssertPngSignature(Convert.FromBase64String(result.Base64)); + AssertPngSignature(File.ReadAllBytes(AbsolutePath(result.SavedPath))); + } + + [Test] + public void CaptureGameView_MaxResolution_ClampsInlineRender() + { + if (IsHeadless) + Assert.Ignore("No GPU in batchmode"); + + // No save_path: the inline image is the only artifact, so the cap applies to the render. + var result = CaptureCommands.CaptureGameView(128, 64, CameraName, maxResolution: 32); + + Assert.AreEqual(32, result.Width, "Long edge should be clamped to max_resolution"); + Assert.AreEqual(16, result.Height, "Short edge should keep the aspect ratio"); + AssertPngSignature(Convert.FromBase64String(result.Base64)); + } + + [Test] + public void CaptureGameView_SavePath_MaxResolution_DownscalesInlineOnly() + { + if (IsHeadless) + Assert.Ignore("No GPU in batchmode"); + + var result = CaptureCommands.CaptureGameView(128, 64, CameraName, $"{SaveFolder}/full.png", + includeInlineImage: true, maxResolution: 32); + + Assert.AreEqual(128, result.Width, "The saved file keeps the requested resolution"); + Assert.AreEqual(32, result.InlineWidth, "The inline copy is downscaled to max_resolution"); + Assert.AreEqual(16, result.InlineHeight, "The inline copy keeps the aspect ratio"); + AssertPngSignature(Convert.FromBase64String(result.Base64)); + AssertPngSignature(File.ReadAllBytes(AbsolutePath(result.SavedPath))); + } + + [Test] + public void CaptureSceneView_SavePath_OmitsBase64_AndWritesPng() + { + if (IsHeadless) + Assert.Ignore("No GPU in batchmode"); + + var sv = SceneView.lastActiveSceneView; + if (sv == null) + Assert.Ignore("No Scene View"); + + var result = CaptureCommands.CaptureSceneView(64, 64, $"{SaveFolder}/scene_path_only.png"); + + Assert.IsNull(result.Base64, "save_path without include_inline_image should omit the base64 payload"); + Assert.IsNotNull(result.SavedPath, "SavedPath should be set"); + AssertPngSignature(File.ReadAllBytes(AbsolutePath(result.SavedPath))); + } + + #endregion + + #region Source routing (AUTHAPI-10) + + [Test] + public void CaptureGameView_ScreenSource_InEditMode_Throws() + { + // Overlay/screen capture is a Play-Mode operation; in Edit Mode it must fail with a clear + // message (this guard runs before the GPU check, so the message is deterministic headless too). + var ex = Assert.Throws( + () => CaptureCommands.CaptureGameView(64, 64, source: "screen")); + StringAssert.Contains("Play Mode", ex.Message); + } + + [Test] + public void CaptureGameView_UnknownSource_Throws() + { + var ex = Assert.Throws( + () => CaptureCommands.CaptureGameView(64, 64, source: "bogus")); + StringAssert.Contains("Unknown source", ex.Message); + } + + #endregion + + #region ViaClient + + [Test] + public void CaptureGameView_ViaClient_Succeeds() + { + if (IsHeadless) + Assert.Ignore("No GPU in batchmode"); + + using (var server = new PipelineTestServer()) + { + var response = server.Execute("capture_game_view", new { width = 64, height = 64, camera = CameraName }); + + Assert.IsTrue(response.IsSuccess, $"capture_game_view should succeed: {response.Error}"); + Assert.IsTrue(response.HasValidJson, "Response should have valid JSON"); + Assert.IsTrue(response.JsonResponse.ContainsKey("result"), "Should have result field"); + } + } + + [Test] + public void CaptureGameView_ViaClient_SavePath_SerializedResultOmitsBase64Key() + { + if (IsHeadless) + Assert.Ignore("No GPU in batchmode"); + + using (var server = new PipelineTestServer()) + { + var response = server.Execute("capture_game_view", + new { width = 64, height = 64, camera = CameraName, save_path = $"{SaveFolder}/via_client.png" }); + + Assert.IsTrue(response.IsSuccess, $"capture_game_view should succeed: {response.Error}"); + var result = (JObject)response.JsonResponse["result"]; + Assert.IsFalse(result.ContainsKey("base64"), + "A path-only result must not carry a base64 key on the wire (AUTHAPI-8)"); + Assert.IsNotNull(result["savedPath"]?.ToString(), "savedPath should be present"); + } + } + + #endregion + + #region Screen capture in Play Mode (AUTHAPI-10) + + // Draws a full-screen two-tone quad via IMGUI. Like a Screen Space - Overlay canvas it + // composites straight to the screen and never renders through a camera — the case AUTHAPI-10 + // covers — so it lets the test prove overlay content shows up in a screen capture but not a + // camera capture, without a uGUI dependency. + // + // The tones are chosen to catch two capture-path bugs a flat saturated color (the old pure + // red) is blind to: + // * MID-GRAYS, because a primary like (255,0,0) is invariant under gamma conversion — 128 + // turns into ~188 when the path double-encodes gamma (the washout Thomas reported), so + // asserting captured luminance pins the tone round-trip. + // * TWO DIFFERENT tones (light top, dark bottom), because a uniform screen is invariant + // under vertical flips — CaptureScreenshotIntoRenderTexture returns GPU-UV-oriented + // content that must be un-flipped on D3D/Metal/Vulkan, so asserting which half is which + // pins the orientation. + private static readonly Color32 OverlayTopGray = new Color32(128, 128, 128, 255); + private static readonly Color32 OverlayBottomGray = new Color32(64, 64, 64, 255); + + private class FullScreenOverlay : MonoBehaviour + { + private Texture2D m_TopTex; + private Texture2D m_BottomTex; + + private static Texture2D Solid(Color32 c) + { + var tex = new Texture2D(1, 1); + tex.SetPixels32(new[] { c }); + tex.Apply(); + return tex; + } + + private void OnGUI() + { + if (m_TopTex == null) + { + m_TopTex = Solid(OverlayTopGray); + m_BottomTex = Solid(OverlayBottomGray); + } + + GUI.depth = -1000; // draw on top of any other IMGUI + var half = Screen.height / 2f; + GUI.DrawTexture(new Rect(0, 0, Screen.width, half), m_TopTex); + GUI.DrawTexture(new Rect(0, half, Screen.width, Screen.height - half), m_BottomTex); + } + + private void OnDestroy() + { + if (m_TopTex != null) DestroyImmediate(m_TopTex); + if (m_BottomTex != null) DestroyImmediate(m_BottomTex); + } + } + + [UnityTearDown] + public IEnumerator ExitPlayModeIfNeeded() + { + // A failed assertion inside the play-mode test would otherwise leave the editor playing. + if (EditorApplication.isPlaying) + yield return new ExitPlayMode(); + } + + [UnityTest] + public IEnumerator CaptureGameView_ScreenSource_CapturesOverlayUi() + { + // Overlay/screen capture reads the presented game-view backbuffer, which requires a real, + // rendering game view. In pure headless/batchmode there is none (and WaitForEndOfFrame never + // fires), so self-ignore early. Edit-Mode + unknown-source guards cover CI regardless. + if (IsHeadless || Application.isBatchMode) + { + Assert.Ignore("Screen capture requires an interactive game view (skipped headless/batchmode)."); + yield break; + } + + yield return new EnterPlayMode(); + + // Tolerate unrelated error logs from whatever project hosts the run (this test only checks pixels). + LogAssert.ignoreFailingMessages = true; + + // A camera that clears to blue and renders nothing, so a camera capture is overlay-free. + var camGo = new GameObject("CLI199_ScreenCam"); + var cam = camGo.AddComponent(); + cam.clearFlags = CameraClearFlags.SolidColor; + cam.backgroundColor = Color.blue; + cam.cullingMask = 0; + + var overlayGo = new GameObject("CLI199_Overlay"); + overlayGo.AddComponent(); + + // Poll a few frames: the overlay only appears in the capture once the game view has + // repainted it into the backbuffer (a single frame is racy in the automated harness). + CaptureResult screen = null; + var overlayObserved = false; + var stats = default((float fraction, float topLuma, float bottomLuma)); + for (var frame = 0; frame < 30 && !overlayObserved; frame++) + { + yield return new WaitForEndOfFrame(); + screen = CaptureCommands.CaptureGameView(64, 64, source: "screen"); + stats = GrayStats(screen.Base64); + // The full-screen overlay should dominate the frame with neutral gray of ANY + // brightness — brightness-agnostic on purpose, so a tone or orientation bug is a + // failed assert below rather than an "overlay not observed" ignore. + overlayObserved = stats.fraction > 0.8f; + } + + // Reliable everywhere the screen path runs: it returns a correctly-sized PNG tagged "screen". + Assert.IsNotNull(screen, "screen capture should have run"); + Assert.AreEqual("screen", screen.Source); + Assert.IsNotEmpty(screen.Base64, "screen capture should return an image"); + Assert.AreEqual(64, screen.Width); + + // Pixel-presence needs the environment to actually present the overlay into the backbuffer. + // Some CI/windowless setups render a blank/stale backbuffer even in Play Mode; treat an + // unobservable overlay as inconclusive rather than a failure (verified live in the PR). + if (!overlayObserved) + { + UnityEngine.Object.Destroy(overlayGo); + UnityEngine.Object.Destroy(camGo); + // ExitPlayModeIfNeeded ([UnityTearDown]) restores edit mode after this ignore. + Assert.Ignore("Overlay not observable in this environment's game-view capture; screen path still verified."); + } + + // Tone round-trip: the authored grays must read back near their values. The old AsTexture + // path double-encoded gamma in Linear projects (128 washed out to ~188). Orientation: the + // light half must be on top — CaptureScreenshotIntoRenderTexture returns GPU-UV-oriented + // content that the command must un-flip on D3D/Metal/Vulkan. (AUTHAPI-10 review) + Assert.That(stats.topLuma, Is.EqualTo((float)OverlayTopGray.r).Within(20f), + "top half should be the light gray at its authored tone (flip and/or gamma bug otherwise)"); + Assert.That(stats.bottomLuma, Is.EqualTo((float)OverlayBottomGray.r).Within(20f), + "bottom half should be the dark gray at its authored tone (flip and/or gamma bug otherwise)"); + + // Overlay is observable here: prove it shows in a screen capture but NOT a camera capture + // (the camera clears to solid blue and renders nothing, so it contains no neutral gray). + var cameraShot = CaptureCommands.CaptureGameView(64, 64, camera: "CLI199_ScreenCam", source: "camera"); + Assert.Less(GrayStats(cameraShot.Base64).fraction, 0.2f, "overlay UI must be absent from a camera capture"); + + UnityEngine.Object.Destroy(overlayGo); + UnityEngine.Object.Destroy(camGo); + + yield return new ExitPlayMode(); + } + + /// + /// Decode the PNG and measure its neutral-gray content: the fraction of pixels that are + /// near-neutral (r≈g≈b, away from black/white clip), plus the mean luminance of the image's + /// top and bottom halves. Brightness-agnostic so gamma distortion shows up in the luminance + /// values (not as a hidden overlay), and per-half so a vertical flip swaps them detectably. + /// + private static (float fraction, float topLuma, float bottomLuma) GrayStats(string base64) + { + var tex = new Texture2D(2, 2); + try + { + Assert.IsTrue(tex.LoadImage(Convert.FromBase64String(base64)), "capture PNG should decode"); + var width = tex.width; + var height = tex.height; + var pixels = tex.GetPixels32(); + var gray = 0; + long topSum = 0, bottomSum = 0; + int topCount = 0, bottomCount = 0; + for (var y = 0; y < height; y++) + { + for (var x = 0; x < width; x++) + { + var p = pixels[y * width + x]; + if (Mathf.Abs(p.r - p.g) <= 12 && Mathf.Abs(p.g - p.b) <= 12 && p.r >= 40 && p.r <= 240) + gray++; + + // GetPixels32 row 0 is the image's BOTTOM row. + var luma = (p.r + p.g + p.b) / 3; + if (y >= height / 2) { topSum += luma; topCount++; } + else { bottomSum += luma; bottomCount++; } + } + } + + return (pixels.Length == 0 ? 0f : (float)gray / pixels.Length, + topCount == 0 ? 0f : (float)topSum / topCount, + bottomCount == 0 ? 0f : (float)bottomSum / bottomCount); + } + finally + { + UnityEngine.Object.DestroyImmediate(tex); + } + } + + #endregion + } +} diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Capture/CaptureCommandsTests.cs.meta b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Capture/CaptureCommandsTests.cs.meta new file mode 100644 index 0000000..0ce465b --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/Capture/CaptureCommandsTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7469ce0ae01ac444280398a19366fdfc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/AIClient/Packages/com.unity.pipeline/Tests~/Editor/CaptureVisualElementCommandsTests.cs b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/CaptureVisualElementCommandsTests.cs new file mode 100644 index 0000000..b4afeee --- /dev/null +++ b/AIClient/Packages/com.unity.pipeline/Tests~/Editor/CaptureVisualElementCommandsTests.cs @@ -0,0 +1,243 @@ +#if UNITY_6000_7_OR_NEWER +using System.IO; +using System.Linq; +using NUnit.Framework; +using Unity.Pipeline.Commands; +using Unity.Pipeline.Editor; +using Unity.Pipeline.Editor.Commands; +using Unity.Pipeline.Runtime.Commands; +using UnityEditor; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.UIElements; + +namespace Unity.Pipeline.Tests.Editor +{ + /// + /// Tests for the visual-element capture commands. The selector resolver + /// () is the + /// riskiest new logic and is GPU-independent, so it gets the most coverage; the + /// capture_editor_element command is covered for its validation/miss branches plus a + /// GPU-gated happy path. + /// + class CaptureVisualElementCommandsTests + { + // -- Selector resolver ------------------------------------------------------------------- + + static VisualElement BuildTree() + { + // root + // #toolbar .toolbar + // #search Button .primary (direct child of toolbar) + // #content + // #title Label .big (disabled) + var root = new VisualElement { name = "root" }; + + var toolbar = new VisualElement { name = "toolbar" }; + toolbar.AddToClassList("toolbar"); + var search = new Button { name = "search" }; + search.AddToClassList("primary"); + toolbar.Add(search); + + var content = new VisualElement { name = "content" }; + var title = new Label { name = "title" }; + title.AddToClassList("big"); + title.SetEnabled(false); // sets the :disabled pseudo-state + content.Add(title); + + root.Add(toolbar); + root.Add(content); + return root; + } + + [Test] + public void Resolve_ById() + { + var root = BuildTree(); + var e = VisualElementCaptureSupport.ResolveElement(root, "#search"); + Assert.IsNotNull(e); + Assert.AreEqual("search", e.name); + } + + [Test] + public void Resolve_ByClass() + { + var root = BuildTree(); + var e = VisualElementCaptureSupport.ResolveElement(root, ".toolbar"); + Assert.IsNotNull(e); + Assert.AreEqual("toolbar", e.name); + } + + [Test] + public void Resolve_ByType() + { + var root = BuildTree(); + var e = VisualElementCaptureSupport.ResolveElement(root, "Label"); + Assert.IsNotNull(e); + Assert.AreEqual("title", e.name); + Assert.IsInstanceOf

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 z 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%0DO0&pTFKM{+l6c&ggKM;v23C0Cs{3#pQ_@^;| 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

x!<3Qeh58p?$*tN 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%0DBpA z3G>Ukq^_feW6iKWT(!X6g_vp;SIw}d*#p?$*j_rwJjdvR*M6~IU)fHXX0DhSifjGL zai6KWAZ^3M;r(gHX;Q*5alO8}T(TRev+7?;|pkdRLmKBHkrJ zzMcgQlP_oc{xJn=oF1%e-xZ!K%{vfsc)u5smV2N9n`|3@Mec5z))c;usJR|VC?DyR zKF;QO?R1XP-?yzPKd2mte(8gw&>kttIC>p*8gvgt%|NZ<(reU6)KW3kaMWB4CC%oG zc4wsCr5RjvDdv)zhFXu>g5#h|t8nhk`7_Ia?UXZLhV0TqLy?aOAf}Wh#FY|DgJqf; zy^P~g_0R2ocE&b##X^0*;7i*tXG*-Ib^WTbVuB{-oMQkrHS_E0jWHb!sM}q-IL}bK zYFjGlGk2xAe*3RwY6ru7`Q|w{wOe7n9Y6OV!W*M|6i>=#7MbanO@+*vj%h;XB-=S5 zbH+N$Lwho$8ECeUIT>;V^zx$!Z-$Ozn2-s1D=6}@l~oZkC#J`Pj>9&c7a8TZwU9Zv z%ryVsae~CvyThOOoclvV)L0B{fgT+$i`Jlqs-%rWt4s=!}s0KA0wC-PHk2 z2b~les`ug2#Io+{fhL0XV=qJXOS3}TG(5s9sr}M+xA-t;{Lcy*cQ--wL3g3pkx?gq z7>YWjY)%9HHp!17wbN^43?+&9HF0DYGCNewh0F<(#h^by#p6Uq?H=_JGB-=s3z>T- z@#02C-8*?l$dvtDA#=Lz24qF!S=)X>=5*U;p~bonCWvosYY7>hI1zLdlr_TIwgD{$ z#fr4H6@^S%rU;p{DI8NCz+J-kWam@wcRrsW(p#<5l1<2@;8jq4P%n`BhG9Zh-!Rr` zzv>%?k#!$#Pp9(b5xyQWRzlgKeJm8(qbcs}2(PoA-!Bu{AuUt7$(+y0hLCT4W>4FE zFYe4vbgWrcRtBec==UuA(#K};dqT&tPsrr=Pf)ysR`%n-_))gGAS+PQj!_GwJsZEH zhsBMe6_Bj~UFvB|gI^H%9ZYFL^8yIJe(`+}bze7G-B|MdD3;{Id>f-*+WwQ@=cD;m z-_W9;R^m4il3E3t@0a|ZqSk}iba?7)lu3(9L2fNmJ=*ynXYL+!@e5m^XE<)O=f9E%~UfZ7DmCS5*p0ZJAuw5UQu$@jRC*@y1%l zwxN8O)GHtD;KRt2kIwL6Wc)tJc$L2YK)X|4eg^$^{ehE;icH9d@ue^ah#@mP z_13}sXyN6T@0^RZEbT!1HI44*m#v*?;cGqWg$NV!?vplEe+dP)^g&z7*d|@J>IDW9 zhsy`Q*S;WM6r;O)88W(4y)3#r)ys@5ysdgu!nk8ys(l(GQ)dxP&8Qt4BjXEAB=$U( zGjq;z{%_osmb92uv2FY}al|ydf8&njqH1utZn1xtnXmP#4H;d>T420wnnifuYriaU z+OjklGIaz`4jlX-p7)aur7UWi8icxuU!X5v_y6*Sm1z+SnSNK?^}U@s@R)+|;W2ON=f#WC{LI@RXcd;d`fk5hrs!`LQ~ z6C{Uq9Q4cBnC7%4BfOK*>Vxi7sxE6=#`YIm#FkF_hk2QdV;+4pK^ZWYPFsZM3MD19 zBSWF)zlJ!N-x1Rzyz4sk$^@rs=muchg!^aLuvylyk>?mYcgr3%^PXJr$Sf=W}%DFy^(+=*gi!7D)+W<29 z$PC#c#8wlswU8y1vt?$)R%GI+0F7B&D6@{EF=UM6Pt@D1uSa-!w7cC$Z76hi0`W3$ z7ch#mOsS=g!Im;=uKqF`E}&zh=3=j)EqgNK7;?||N@>5%h01GU9Gn#}N6ZIPKwGAO zqceRlUNx?o5~4db>PD9_=n=y|QR4{Bhh${8=-MP&aCf8s6t`6kA}xmkal zuj5$ZI@v|dz!GPw*ml_>)H$-QI=^fYOaXK5I;-ZAF*epTYlb0DL4PYW!|I6evCV}K zSG?bbwOtR}@Nu}bfGf8AcmcD13{#&7DPY-CtFY`{WtAU(X&ckerL7?QK*+cYpL(|9ERJ}oY1ndHLJQFS{0Ph^i%EE<&Ij^WlNbWyb;*DVd_1Z zjhL3mTrwX|i|uF8^3fTkp?c^-Z9B7Y9B+vx)^uOEql{(R(qUUgN^PYMrKZq&O)PO& zzhtd)W<(z=WcS15jqbLiwO5D6WIv~FdIz@bWoh77?T49lg<5r(oi_Sqc&rb)Q!AUT zI&WN^aJIynVOg!3WVN0vWOa}97abmba7<Op}jr1+crmi zuuQpP{;x}yHK^V+`R5x2tDtx3gK7DD{T|UR$5p@VZ;GPsC*yVqZMjlcYhtqkQhm^n z>UoB^VrCCzzhs$mKa6qI7HwfdQDkNS>|5KgqGDQHt#cxFm{~5Yt(eY%*|(TJ-j%71 zvR5IW)1~XW!x6q8G30@=H*CI>C^EYX>TAmt9dcqJQyTQ~M|-==ej8)YoPzPZyV?iK zUadqPY8h)mX(_WquWaMhS33mUr=}0?OfbL7Hj(zhyA)iZF}(11F6fTC$;=zqQ7WZR z>)6!&qg0yCBERZOQq(*V?r5vNTV>WhSd!|yRSqpvH^TF3Qn${dhr;!Y`j%yE)fX&7 z;nSyXryF-F4nu6k%#kY&_4UitK4S~-Bk7%3UO}CYnEFt?!t8v~2jd+s?a%Z zNqCE57@l$$lkimE|K~bqeQ@LqUmxR;KGlaA=; z>aA=;>U}*!;md$;^Rc!{LQB0Z^qfAw5xxhgP)uyBOBITdsZh+G$3LaTxML{loj@aF zKGX>uBUA4L8VVntdIdCkDB*pm7jk0i!?c%Km_>#!A>}T7noW40N(u}$K`nFyg^xq| zHE}4vhLqobj(7iPd-~)r8eM#tk%VK)`;dJsWX?RDuJ3up_1Mkd%$WdpJo)pL$jWGU zE*~y;jDz9vm39990^PYnre9Yau9uM;$k#}7w~8lq=yxsh)?R+?rmD`-7Ll1>A=oEm z&er}aWJ;W8o^FWDoCS-UIMS=B{i@rZbu~qb%#?UVA@l0hV4-RHw9*bxvLrGm)H8sN zpdFwrNh7_=`fgBe(1XnKAexpH5?Ny%+c?k-&}&acdd;=%d{AUED^vS9#lGlt5a|SRN@&cn+UooWO5YKkYnoZu7n(Qqx4xzOF#*eM|vG~ z`r3fDfMOa)OxGjaI6F|2?RZ~TJ?`zwyKnYV@SqsoQp}yK( z`sXb51sxGGHy(Jyr6weG{vVggi>y_7XC+IubM+#1n%nL}ubpzi(iAvTI)a6WtB7 zXY&q1#?>cJ^M&8ZfAYO`eqpe^2(%Sqc0r6B5_XW7$sorcbJCNM{;2s6P{%4Tz z#_2L;ox6U`%_ZY6yzw{TC{y~y{K`&vzcVETMzb;nY12h|Q*^3|fcQ%w&)4;%enX+A z*qZkaH>~iznc4?$Ve@7-@1pSLhMMb{F^?zMc`}%1zYTe;j;r>=*SVVOnb$9PXEZZzkFo}-kys1iZCXyhfU0iERr_mBjXaO*i4UtH}Cm**wrbArlAV z_3O%SfNFP#CCw&e-scRTD#ph2F)iU!z}W6fye1zhGDLdc>tAAJsWlT>GCkuND3n&y zRH4k8mI&q06jOJX`qtI7V98;C}i48Ox?|p8-iWr6oluw=7j&>+j115 zF6J77vs}&z*&8`~r8eV?k=l_nZvG;NdY{4kB9TkeaNKvz6J2_evtiEVId7*f=A4x; zad7s^7dtoxxaP5(0dNJxwE;&Lu1@%?U@SkD5X;3?8W}T2dXJ)MIG5JzBJRvB)BkmS znmy`r3;7iS-B-KIU61;v*9w^)#k|E?6hCSt=G|tF_H1<=%Q%X2wBme{+Kl>?dX2HU zW?yXW92+?c;(UX1F17<#&9L3G#WtUB-(uj{%~@X){DzFH6>}EJKFE0;@2Q8siOv?r zcF*~)Yu?1UEoZMB&pBiKH}gNvt~saX?8`MvV;iDY>4kTlUHy`)XqRqc4`r>ov@%PG z<>wkN&r5%c^^Vf*>~HkJP*{F!b?ggl_iP)ibGAB`6h!3udej&X5^0>yo{ZrOOvo z*!Nk3EN9Nldpi0)#|pLszVO0wVa;$B?y7y(Ip^rqDxC9wIn(YpF_%x?VyTr`E-VAK z;(rsz|B2yoHo`dwH4^KMZH;Th{diM?{haNO<0botYmUUW#+e&yfvto(kvf)h8rG_- zwbxE-zua=3$hj2fSDbUPwY#*pYxc#N7Uxnfon0zZWYoJ>uM3&qPHG_Zh5l70=EIk_ zfy~Zgd$Ens+MBh&y$qHW$3fQ)8edamUkJbB#WG+!aA|LrIBScVhAqPN7I3W`p0`i0 z?wE6i$6rBX&I^vTGq+TuEaeBiEp$YO_a0;kAR7tU9MA?3Q+iTlXLTsdIY%|>XV*)a ziT|{-s*k1K%!~f)3k;7XslK6^U&%Tr`rgzzTRVFrcjMDHmERoK^H{dnR@jLS-~RZf zG2cGsOU8UbnI+CNvu0RZ9FJTtD7)TGcDcuR+ zrAKNawq}QgGcuMWOI)>x&vf2gJM{dP@b~#k^c{Nc81g#=bN-E_#l*2$$mHX(kjY2c ztoHq!zMwUrheFS4-BkJoO9O?T)3O6X(N|e)_bPAZL#WyZ8rNxPh%mIzDYtR zeaD5&%Vg=YM|xRxyv;yg3z-x=1{Ka>W!*qaKzBh!UW|_)A|%nr+Y z;?C^Es9BJqaUwJEsy$@${*bGMF_*4+`xg?*;%IwcoV{`dsoJ>NLw4yLuG#5VmA&!d z`fXJHA}U)V>y359wE^dUoE`qXO`5$WwnXZ%N0Q6v?SSJO#}sO$@M9i-g^yp2_$7&7 zjrcW)V`EH5#HZufukh4_)Q%ke66K8aa_Tn8eqLW>`J%}diL7um*<+C{k5>DxmE0S- zBE2oq+|3f%E78KcE3$IYWEFGUzR&cn6q#uolx5Eo8TDEtWz?tCu`bO@eaardm%mu6 ztOaTYuazAG*i)uTT8tJrC}gxi`n*;Pv;Zv0{9slR0VWp~gr&|T2W`K;!D zSIG3_wL<3P1=HfnTja|&ebt4GZi=bCXD?G_VBW`c^)0TCxCZ-se={#?a&5()$3D#w zC#G?5O~;V$^ssg0`bFqTQU=v^Eo>EP5Uu^WWFKF$zcbHrPL)40>X+YLJ%H_sK3Fr2 z#P83#fAkSD?d6P+nRn(cV8^$fLgt;eABD_|a*+k?i*ikbn(5Rp0^JcZ^MgW#BBN%E zy@X7A`301|u$6TKZ2+lX-npqyD%O_0X5*LnNKquxYop_(yXqn{ucy<8tJDtVvf-@- z{SK-W;YZDtW9PQ+T1v;s&!&ATa-d*Rs@nri;v0N{(E+`Ijac6#odEZ;Hy=;0uPTk49IhGppOU=sg zI8)%S`SSN`S*Dz|g#Q&>{t~e3_ka1jzWlA<@W1fOa-JjQXJ)UIT@;yV#p#OKR@_X; z=!m(XQ=pW^?fCnKka0I&$c(1@A!Avw$FmHMW1QJ2WWLEIDPc7*TN7s^tOd47u9&&T z=IJ}Gw*NAdX>0Xg_?0zdV|Z*$EWhlMX7kI|?Sy)3z44vUApPsW73IZu(@xnA*gCmK z#*n!q$9XZ^IOoq#zHi2zyRG;x&iy)`&Ewu7_l#WoYvK3OT)TtZRb%P0=drzHJ?};R z>K1zx-LZ$denZ;TFWIBmr`bc<8(BxL`e6Flig|v`)mPa=*=xi1)!-F7GiO?uU+(F1 z<;s+@y|~JNEr;tFel2L?_(s6C!JT}z2)0x1RL)Hk&l~Z!4Ef$Ol8+B{Utqnl{J5%& z>CBhyh3nsqG6pQtH#|6d<0gb(JK4%U+#te_HDt{;EBH!!7);x3fiX#mx4?-{s*+O0KrqBDl(DOANnvy*H2j zT?*!sIcJ%cmp3%b-5}}%_FDF2{^C5_8h<}N{G7|Ro9xw&f2Fw2(SOB8CV+BTrPb@Ek(^0USBa}{?+T}K@e z{@XiCjX7rtu?#Xi??v6*V5-;-m_FBTGJoAsy?&8d->3U~KBE8PBg^2rtb2Cqc{a;= zu)N}7W_alu*cu{3z9{jU5nnz?hnU$+}$F z5}8ug0#nM`V%gIN^Tv4DO4ueDGQT4-EiPhg90NFF7n4^kE9;(DS;*Ylsx4$R7k^b~ zf&7m4YkC(<{q|lC-Mc4>td^E-lhT->OQYR!sUv+#g}-zAPqrqM?R9)_f%bbuLfNd- z!rwHo-oPu92zj(ll`YISxSqTZHy#7MOudmzzpDDIxw7&>?v6TI4L?15ML~&>KBI)jt z$kymI$15G_ZPQdh?l`@wNA~ALwoA+M37MTr`sE%9>({l`2!C>grOOrllkeSx4}~p} zy{thidkTqrE!>w<<JA)t&i}hN|<`ac6E&X_Vhr=%!ZSWm798c7P)X-gm+QXW}#b}_T%jiS6gGd zaW9#F2 zP*KoZpe~@{Any4tg6!jW?QaLKhwK=Lzn*;uvWT)a1+JMY+lH$1%hBqbE!I^+Pd>|~ z_HoT}IS1x^m$l#;2RQ@Xk5lq|v4a{jygO=iYI*vNsdmgK<$PV2A4jXDA~P>TQO17B zzDn)r(nGYpD&d)vFkZPx@2-w5Ldf*^n4UT231XfbWx=oC-$2aDej_of_)WyD z>o*g#p5H>u`hF`h-|^ds*}!inW>dd|m_7VXV)pbqi`mQXD(3rscQJeWJ;nUM?>Hi#T@C67IVBmR?G?h zI58*s6U3b4PZD#oKSk-Y zz@I0)P|U#l%AYUh*ZxA0ED|&D7W-d|xy)ZI=5l|DnBVzJ#a!ht7xR06rI;K2Rbp=P zzZY|dzedcR{*Pkr@_!O@x4%Kmef}mf5BOWeJm_x|^N_zo%)|cAVjlB%iFw}NBj!ba zpO}~Y17cqG4~cojKO*K;|CpG+`6tBu-9IJfHUEs5*Zp6`yy2f0^QM1M%v=6tF>m`< z#r(tnUCev_bul0LH^qGH-xkvg?uzLL_rwf>`(nlp9*P+!cr0eZ!1tvc1|cyM2eHLW z62uiVX%Jt`r-Dc^lLZOId^SidW{M!Gm??u~Vx|h75i@m=T+HW#lwzh0Qj3`}NF!$E zAg!2Lg7ji$4Kj-PLXcU^Y(Z8rvj^G4%n{@e^Ti;im^p*oV&)3+ikUaaCuY7NznCuv z1;xxC6c)2UP*lueH zDrV)Nx|mghH^i(K)D-iL;4Lw02DQbk71R~;t)RY`ZwC#;tQRyA^PQlHm<@tvVm1s~ zh}kG;C1&HGjhIb>c49UUI*8dK=p<%`ptG2rg05n|8*~@5bI?=FE=yJ9 zvwP4_%pSo2F?$As#C$IpB4)2(sF?2u!^P|yj1aS5FjCC^!DulD1Y^Y<9E=n5!(f7# zLxV|T4hyD;IXsvu=10MFF-HV5#r!y!CFX?Sb1^3dbH$t-%oB4;Fkj41gN0&F4Zaq0 zTCiBm>A?~)X9P>doEa<^^Rr;3m~(?wVtx^PFXp^pjhG99AI1DC_({yKgAHOX3O0$k zIM^cQH^DYBmjpY+Tps)^=89mKn5%+4Vy+GLiMcU2Am*mvkeHi;BVz6dj)}Q5I3ebN z;FOpLgEL|t3Vs#yXmDQ4W5Go+j|Z2G5-wWig`bXFJ`Pzq?oZo3B`;P zN-SpFP*O4Dg_4OGKlF^45uxN_Mut*~nIM!}%p{>SVkQlx74xZ3dNGrQGK!fzlv&Ia zp{!!23}q8DRVas;X+k;0OdHBAX1Y*bG1G_giJ3W+U(9Twf?{S56&5o`sHm8^L&e3+ z6M99=e4$cez8oqeX2DQ7F^h)Ei&;EWQOpvd*Tj4!R7K3vp{in*3so1hQs@matA=Wd zSuOOInAJnI#jFvkD`w45eKBi?8i-jZ)JV*_p(bM13pEq7eyD|*?}S>3*&x(L%!Z+M zVm1kN5VJ+7lb9_-oyBYw>MCaIP{O@9o&+y#t^2-igiLo%oFRE^P7c!sooZajW-kZ1e8H7rcA1-MbH8^zO$F?*V+t zdl0vI@5PtB_u;GF`*ElD0sM#eLG1J%!q>bH;TztEvD^CyzUh4w-}XL+z23w4j`wlw z_dbDpyiekL-luTT`!v4qeFpb=kKl*iqxg~c7!G-##eaE^<00<}{KR__Kl7f#Vee`D z+8Z*M&3t;P#f0(z@NRH<|*s(jH` z<&S%FOI1cRsX{PRWx_C37@AcUj8I8vRar4oWkZ`P8lzM(7_GA7MJflz zsGJz9N<_QLg$XJ*CaO{~NtK2!l?Rhm3SO*QhH0uyOjl*0N0p7TDhCx+E@r6mFjJL} zS*ilOOjU^4sv^u)72}nv<(Q``!K+lIn6E0st5xM#psK(k)e5{pwGvBItFTP98Y@(5 z@K#kN-ma>`RjRdkhiVp(LqiV+%RR=z&+J;+I+p$fx17A?> z#CBCDzNp%TFRQw6yQ&*^s&?Z)R6W?K>c!VoefWl|AG=ip_@-(QcdPc|TdIB7quP&e zs}A71s)N|C8p1uQL-?WUFz#0!!H-l&@nh97{I_Zt537#je^e*%Q`Jd4raFb6t4`x_ z)fqgY8o@7Bqj*v^hW}Na#Z#(r{7N-}r&W_UqME{QRns`Cn!&TGS^PmYhvTYq_@inb zCsYgglj=N9sk~II3o38?Ri(xmm4LsgM4VOW@OPCj&Z+!yUS+_)RDrml3c~-XjOe8f zL2tDQRq8NQt1T$1CG=5Sak1Klf$C@sR>xq7+Kwi*14GqL3|A+jq;_G1+Ko}_RE$=q z;YDf>#;6r^sFz{9Iun!BS?E${W3oC2-RfLSQRm^s>U>O77ht-&5IyQ5l-0$Usa}qk zs!K3iU5b~h%P>b>j=Aazyi&aa^VBQxD)lPNSFgrv)NAlsbtM+5tMGdDTD(EM4olS4 zSgKx+H>qo|OuYfi)f@2^^(L%P*W#_}I$WWy$J^AKaizKeZ&x?sD)kn;L*0a{)y;UP zx&_y$Tk$USR;*OF;aYV&-mC7wb?R++pL#o1t9Rgf^-g?1-HA2oUHG873pc8}@genY z+@$Woht<7UtM0=`)cyFVdI0OygXp8#i#p9d)NA&mQF8z<)Eq=fGlUVELl~twjM17S zc#-BP#%PXVtY#P;n&TL+If03qlbEDAg)Yr$Ox2vhi!~#drWr+#W(;M`SyVLRn4y`# zWtvI6L^Fk%nrXaLGlN;0S-ea$huNBQn4_7;D>Mt3t2vKXYP{53S&cVdrBP$PM!*7% zh}URzSg7&EYc>8@q%mNzCJ?XJ1mO)DBbI1FuvBBhn>1l~v&Mqu8VPUFSg}H5!&^1c zxIzQhG>zD)*@CZWnsAq<8DH15;9Htjd|R^>do^wNj;0;^ zG#&V!W*ZJ_w&VMn9k^GsQ|-0r1Ee!+I&r^d7aq`b;XzF|4rzAdCz>AoRMU&cG=2D) zrXPnj1NgaS5Wmpu#S@x+_@!n)p41$`|7s56Da{amtvQ5eG>7qf%@I7SIf_4Mj^Vgw z7=P3p$DcJPa7uF$=QXGByyi4663(EvFoG&!6xG5QYJ{^W2;-;~CQuY6(MOmjk%9?rLKsE~7K|1oj1jEp5NsGPM59xP!34pMiGl-@1Sh(LL`)W3 z=oZ|VBBWxfkcJlv9+U+I6=4}>2${G{$ihp6Y|IpL@KPZcFB9@GTgb;Ng#yeI3h^qT z2=j$vyjoa}1wsj4Bb4H`LKzkbHt+Rd}1Q z7FP=E@OGgZR|)I!4xt8D3mfoGVI!^)HsM`DEmjJ3c(+iGRl;VxM`*ycLL=TQY{7Lx z6W%8@W3|wN_Y1AKUf7Bc2yIv+wBv(92W}9y;r|KSaig#U9};%rCZQ7_7IxtyLKoHv z-T0`m8ykfld{XGeW}y$C5&E%37{F(RL401=i!TWKaEGuTJB0)Ins5+b7lyD)ID~Hq zhp}5Yf^P~(@h#yP_6WoHws0KZ5l&#Aa1!4YPT?NmG`=UC!TrJrek6?I8DR{66wcyL z!Z=O}6Zo?*iBrN9P7Blct1yG-gjxJkn8SJD9R4ND?tj$8VHXBp4 zIhdx+#dK{R%G!KXv;~-#;~%gUhuW@CNNhEYWVl8@07q zs;$GDwDnk~-HbPD8?ap4h_`6BV1>2`Z`C&A3T+GCrftQQ+O2rIwhdQl+wl%<2i~dO zhLzgwc(-;3-mBe->$IJCpLQ2kYrF7%Z8xsh?#2hSJy@gd#Rs*0xIx>G|EC?mhqQyZ zNxK&x*6zbv?S6bjdjRXS2k}wu5Y}rC;bYpvxLJDyAJ-nm2JJC?LOYC&+T-}7_5^Ox zp2VlLr?5$T8lTpl!Dj6UKBFDQ7VQ{5t38XY+HrhNJAqrZllX#m3fr~Q*rA=lm$b9^ zvUU!4XwPA%b{=2TF5oWhd3;^#rDdLKy|G)X#y7PBzN-~+K&!*|w7$4s>yIC44R}Bs zhzGSn__5ZAL)sAhm)3-bwPE;&)`E*f3B5!s3Zf0QVl;|k4El(6)QJw%i%#?v6VXp} zp}*+H#bPQ3ifOn+^k9&vV6eChjbbKVC}!bOF&j-{4u*=k7$)YSSxqC#XIiCeHp zY{KirW-Jz4@OrTomy28R2C)rG#CE(H^0coLr$Phqoo8lMr*V2e0{&x)hiDvsfE;#u4( zj^p#<1h$Ej_<}fv?cy}PD9&JqIEycdbGS`BhcAosxLsVpSH$zUL-Z1v5u!J~E~>Fh z6z~mE#BNcCZ;HOSTlB}bL<9DSf%vu-w{KwPc-4XVi@*|7ThCBI3QZ_J<*1P zVl=)l#^7Gjjvt5)+$TEmLopHei!S^~bmIXr75^!w;X%=ZABzeOiOcX`VkRCEv+&*W&NuI-C=$@egr5o)c^EPjLgziyQGTaT6|x zwfH}=4$q7AxX5QSUf|P!7y2|}h|d;$#it2(_%!3IJ}tP@rxjoK*@|60ZTN;yJ9hhY z;F~_%u*YXR_WA6Y!IfiF^hVdJp zogXw`*bq|SmiorKXkD_*3tp<5S?>AD#7=Neo0ZX5xiG_6z|g?!)pC7uGb&O2lOX!qy8j5sy~JG`qS8; zKZ8%`N3c;picjgsut|RwpVp6Kvwi}f(NE&D`YC))KaJ1pXRu8_i!bQs@J0PO?9k8S z%lZY}u0M~j>b-Py5yYwQyq1R!z-WT81`{Vn11Ad|p#9@69ey%s- zDSZfjr8nVeeHebHx8Rsw!teD~Jgc|i5Bg{v*T>+GdOJ?&9r%;piIe(7{8{h9DZLwi z)u-Z&J`I1KfNwS$d~*6zEUN-TOUa`={zwGKll?jPEA=&9@e3 zee3Xd-+G+$-Hhja8}LuxMx6KEf`9oo;eu~7-s9JT_xZJAwcl2}->(hV`?cc(ejQlj zw+$Qpw&Rn2J8+BNPJG(06QA+hg)M$v_^e+yw)*YHHoqS1@ax5w{Q7XaUq9~f8^Bln z2Js($d$H4RAHL?dA9wj3z}Ni_Vwc|#zTtNWyZsL1n|?=dx8G5G%kLQW_zmORe#f!b z?*tC|oy7P3PT@hn)A+I98T{051W)>n;#YoSc*gH6e&aWeBYqP&;Wvpt`Ay-h-!%U2 zH-mG2v*_(VhbsSbm=Q3K+XEKx^?>u(72u`k(*}5BcYqq-3=nX4fQWAe=&&ci7vB!> z$KC(~z7r6LeE~uEZh#T@1ccx~fC)bi2*bkx7W_Ow!V>{j{3^hPrvsw#>wp+M6JW=0 z0vtFJ;KXkO5^*%Zh2I6ZaV#JezYj>mvjHCbAwa?LfMxh&KqgKEWZ_Q%**F=HgFgr4 z;#5E${t}Rn(*XteYd|5+1Qg+K0mV2QupEC6D8adaQv4&J49^9WHzdFwoG1OAO5zWN5))Ln|5$Tk%3e8-^I#ajBsLO@?h4YS@lp zh8<`#?8In8C&n3ep~KLH@rG`68g^rXp$8KUy_jU^Lzkf+lMMstHVk5lVK1f{_Tj~b z{g`GrfSHDac$r}cvkiyva>HTFF&x1n!%pTUIh8p5#OV8J~G2?q>Te9vG*$Kq&wd~pmmEVknliyhdw*ojXrPQ)#XT{sZv z#@Z#RxMxWk{<_42GfNcwZOJm6U6P5vFUdkFC>yT|%E6|fTzonx51WJX@tL3kYzZpF zXM>8cHK-Wdf|lb8K_%E8REjSKm0?FvIldEAfqg+M@ZF%5*dMeC_XMrRfuJ?`UQi_t z236tvL2Geu&^r7es2cYLt;Y|8YH)wh1{@9Ah~EWm!ttP5oCvDJ$)I|i3fhdn1U2Av zP$Mn`Z9$*lCe#HtqdvF=eS=%kFL*2Z2e+XixE;;G9cT&OhSuQi7#X|+ZNWP+D!3D) zgLmOY!Cjae+>KWT@5a2~9=s~J7jF*k!}8#Myd`)5R|gMbW$<2H8@vzK1@FiEf)8MI z@IkykcnH@AAHoNM593q8N3bdQC_Wv044Z?8@tNS`*b#gJUkW~n+k#Kw%fYAdmEbeD zBX|T~4Iagv!DIN3;Ir5nJdUpgPv9rPlXx_E3O@~=#$&-VI2=5Sp9jz3@!)g#Mesa+ z8N7fegU{oCgT4Id%)#FHb+8)G1Pl0Wu!uhg>u@UA7pH^$@z-Dj{uUgFv%x|5d$1Ab zf;X<$#y^S_h8KY5cj6sdjj)KvFi;YeUG$!H_qYHzKZd__i zMUycNLyaB`Gb(5?F2itRCQ8OEj4)=S)tG~k#$2=+^Dx?&k1@sqj5QWwys-$K#$rq` zF2_V;3A&7>m~1RVx3L^kj1`z_T!9xGS7MrR6?%-TQ8unY#aM|M#wxtTxE8aF>+mvT zHD(*v)@lY%v-W%!^e6E~Q$@L^Ln)|ztgQBy9~ zoAU56Q$B7s72xBhLToY>VY8_ipEWJ#JGLULt*HdJno99`QyKL(WHm9BliUBc!&E`# z#lL;kw1T|Tv=X~atFXtk8s9dp!Cq4(zH6$&J*KrdU|NUonW}Nnv>x9#)!;tU2K>;p z5kE3*!h@z-{Mb~7L#BHCmuWK|GBx18O^tZiv<3fTYQiI?X8gp|g2Sd({M@t^kDJ=? z3sXCuFm>RUrfv9@X*+&x+JWDgcH&Q_PW;)l3#Uw7_=~9B_(+%s+rt!mF>D!jgk@r9SQfq(mW{i@a_~f0 zE}G4GXffyGMdku@nhP<(T!e|{VoWkG$7FK}rkG1H)m(-bo6Au)SD<2Efy>M*@e=bY z%rvjYOU-LA%Up?=w_&xp9q%`H;Ck~me89XN zYs@?FLGw=BVD7|?=3V%(xeIH}-S~)kH`bYZ@KJLw)|>nAF>^m|HV@!a=0R*S@5QIh z`>@%(AD=NFz!vjCeAYaKt>#16Ww?i9P01 z__p~p_L|RNpLqoLm`8EIJcjR?&*GqY9N#xj;9m12eqf%$edcNW&^&|t&9nHCc@7Vl z&*4AK^LWs_fFGOBB7FU)~> z!W@KOnvFPT4#7XnCOl^j!#~XyoHt7-SgfeE*if`YW2hwt!z^|*TO4SyI5FIkh?2#H z5f(SvEU6e}Ny7w-2NNv{=3ACwfh7|QEm?T2B^z(FD$VJRT5v=rh!mLl9_DaMB_%dyr{f=^mXaf_u4pR$x=lcfUNEh}(`WhK69S%o_- ztMP5i8tk=H;sHw)4q4XXVaqx^VyVVYEbH;8r3OE>Y`|ldjdAr2`i%+wgyu?Reg@ z0~dwwM6d8p^bX&J>hLbqgmcgi`onj0iu1*6^bk8Ga0t!-vrwejHQ7PvFJjCowJj6h07s z8f(JO;Dg~KxG8)TYs1H|F8nM$8a|Ho;S=~+_#|!)pTft(r?DY?2A>F@#m4YC+!B5c zo5JVu>F@=7A^beP6z;W{`55kvo#ASHEnL9fa1q}L*Wm}@zPK;k9}k5a@ZaHqcsM)= zzX&(tiSQ8oGTekG!^3ba+=AbSOL#WiiZkIh{5?Dx=fY#~0?CeA$$_HeL?0;;gC!S+ zNN!vzrDB|vhKZ5~lO+Y+(lShuGBH)k!i%MBOp|gjUCKp|l!vmEkBU@)8B!rGlZx;X zsTePpmSe6|f>%nVm?xFtRZ=?3JeR9cc#pq*;7dn!|qS9PW|kaX?zY_oVYUD0v04vPisCvuLlR#t$R` z_emmtDCuy&a zDH?~R7#x@E_><(oNy&*nONlryx$rN^jSEsLsw2`+i145`LP0TN8R{Z3Q6G_oz7g5z z7mtVS42>wlu!v$bM=VE6Ls_@E)wOAOj4zG=<#-fPzcwIyd7DsHrTO&5&iik~E z8BvRON7P|eL_OXUu^I1=Xut;|8u9-kwqR{U6Fwf%j88_i;Ik2}_+rFX?1*T?&WLt= zEusT=MQp=&BDP~+#14EnVkh=TbmE?fT{slch5w4^#zPUiaX6v}Kac3e;}L!MMMOV- z8!>>R5rg<$#9kbW*oU(b`|dK8yfk71B?7{jf{ zQL>&uyY(c-Sx=$EdKy!$XYgX{2xeMG@k;9$=2_3;b=Gk#woc&n)=9j@I)xS1X}r@q zgKMm_c$ak!E3N17ZtFZgXkEZZtmm=L>a~O!ZS}^dtZHns3iz~D#Ad4wU$pvSht(fn zvKnxkH4tC724R=gh;LX!u-j_FJ=QQBuv+jvtAvAAD}HRX;gB^Nk6B~zGpikktq%O$ z>clhFMEu6;!V#+*zqO{~q%{qHwt8^Ns^BlyWjJlk#9yshc;1?giz0K-D>4`Lk$LDF znU8*v1$bd(A%;X2VMJsxS|gWZWMm0CBTF$MvJ4X=%P}dk0_DgRm=U=Wmqo6^OCnce zR^%GYj;zGXBdahsaxLaXuEVP$t1&-vJzg7GgV#rHz=t9?;-<(=_;6$`)<)LhBa!u3 z7r7Z9jcmaB$VPlDatm&bY{JJQo3SCX1)qp)#m303_+(@oHbu7MGm#zG61feZkKB$g zM()6l$es97WGC*9+=cH%c42>HH@+9S8$XEb!H*+*aVWA6{}tJf$0G;uROBFj6}cBr zNAAP%$o=?ZzMru+e71r)*)^Vzb~@n}pkKR(!=~!&hz5xYHJc|FGHdGn)gyv^nvlEfN1~ zbKxnQ8^5uo;)pE`zqNUA)TZEfwq-bG%f#<(S$Ni#jX&6OaNL%QKicwe!j_Le*$Qyd zR)|x!BAl@mY~=5KB^LZ zqpHv^YAyOlt;2w*YBWTx$Hh@K7#OtymqcyEpr}n4994_Ps5-nbsvbk4HsjK$1~f%A zVrbMB42x<)b5t`*Q7sr9)ruEIZN-?VHjIsGM|)HU#zk$z+^FqX5VZrZiQ0*UQJr{g z)GjQF>cZ=yy0I#1H{KJ~gYQN4;$T!Cz8}?(d!q*MgQ!8=7qu5ZjM|6$qxR!RQ3voq z)It1b)DV6aa|nlH4&&!BNAP&eQT!t27@mk3#xG-zpX5k1^+PB4!?c zidn$PnDh8^j8`z@A;uejiBaQpjDWw!h&U6Y!{1_jaX!W$Rj~$C#|EN4HVFMg@z)K~{z9P7li*hExfU6>K;#$~ao zcu8y;X2yE((pUwvVwd4%v6+}1n}wIhW@BD#4qg?Ti}|s6cy(+(7Q`0dHL-~buNEy42GQd|*RhIhr5V`Xdw-W|IFt72E;J+Z6s;n>yK7`q0WVk`0K*eYy} zU5n4euES?ztFbk9J-!rMgWF;^;LEWaaeM40d?mIP-;Axp-Ldt!Cw4Oq#5UkZv5ole z*e&=;Y!e=hZN^VyTkxycRvd}lia*7+;dE>}{u^o6!??hkw zF7&f^p~>Ejl6^Nu*?Z7#@5OX`AC}qs@n-t~mfHvM7W-bj)xHl`*!SaI_5)aHKZrH< zA>3p?gb&*fW3BxN*4dBZ6ZT{Hq`vksXpTr&ZDSXvFjXUi#*kzx^H|=w{+kOt;vd?3WeF5LLpT}Oi zmyvbQ&WrSm`s`|a*DhecUBo?h9S+!i@jbgg4%!X)zC954+Jo=|yAl6s55a?W6P~n( z;Wu^*j@Tvq!EVJVyA4C*qA@Zq25oV6jE{3*N}Ll@;}Y@WI2WeHx$*M2RLqG>!)xL^ zSQw|^wQ9)xeEh$-0(>;C5bNWL@Ts_BY>Hcs zPsf#Ddt52L7*~cJapl+DD%EvR<1qQi80y%8QI4G$?dZe=$1Y5CbfMzt#tg@9 zT;}M(OB}s;jiV0>9sPK%V*raBgLs`|FBUuY;q{LFxZH67Z*UyM62}nU=QxDbj>CAr z;|Q*I9K{D5$FRmRj1M}F9Dd|DhX)+<_)o_I9(0_?j~!kYvMM>e@uWkI zUpWLk;}G#%hYrUazW9T~AEz7!{KXN7(~clK?=a$`_z?7pH=%!g7zV^!&=4=-;&>}c z@ivTzk49^J3`WM=(H8H(sCXw{9G{43@h(h{ccUjh6|am>!@PJ8UKOuke*7}LIzAI` zj?cpK_-wo-J_jq}bMe;rJgkn-$NS?8ur9t3AB``<`uJjeEPgq*#+Tr8@uj#mz6?9# z%kj1N3fvXH0^f^YiG%U0@csDJxHoH#(iWG1=LJ7dv|~-Pwm8 zXFtl$0aToWnBm-umpb=hmUBPmIS=5~&VyLs9Kvgyhp^Cj7_W66!RwqyvDkSGmpg~? z2Ip}sah|{%ohPx>c?xfGp2jlg87y~>;4RKktZ{mCkc`w{sq=oC|o5^E|F~dWFy@ogAUEXq{7y_c;Zuc8YkvQ-|xF zzW9LCA8VWje9#$)8=OJ-e@-LTJ45g>rwJc-hGB!#f=@UlY;;=jNv92;aYkc{GX`6o zcHHW8;PXx=wmB2=1*Z$!oo;;5nTj3GGJ@I7Zf4mk_(U(P~2wYb>lFISRqze3R(hB@KX(gUX zT7@G?tMS{UH8`47iQgqv;aJjI{61+No=vL8AClJNcv21in6v>Wk~X5BYZESU)uPc= zhoP=|lw6xJ&eed)u0~9CZNZCOO_=6t#&lN;dR(n2ySCybt~Shcwd19(4$N|G!^>RT zG268RFL&+499Jh^;o60{t}eXN)s1N^h0hxK3e<>oh*=I)kmQ5q!=yiUY1O-0M1vAGpTxh-(6mx+d{c*A#x{n#SX<8T`^U zi{H8CaLjcMzjw{!S=R#o;5v`vE-w>T$Hfs^izZxZR3{6lNfuE^)}c1p7sX_M^hq|L zE;$hO$wBCwY(z(L2*xLy(3u>D3CR{rOqMVy*@~`Y8zv`5qdPeUi<9kmeX;|WCp+&A4^uSA$b`-k(`N*$yxYhayD*B&cUaWbFnEo51&rX z$L8b$>`E@gH#Np&s_(Sq) z{4seAP9#_2Psvp{nYevDm#EA9DBLCU-AB?C!%_cRxPj9>6;HAU^8ei}mh(_?UY? zZgwBQ$K409$328^yANTn`!K%aK7xJjqxi1-81}n|agX~r4!BR?d+w7s=sty`?$h|a z`wX6SkKhmPQ5<)V;g9aKIN=`0pWG8T>7K-&-BUQ_o<=cc27OazaY@P?2Bn-sDPO!j zQt|ebG`u6lgOw=?R;4V%wJDi+UrH9%q-5j9lpL&0$;HQ0@~|N#A6rri@Y$3?Y)vV` z=TeGsYszx$Oew+FQ%bQrr3~LnDaZbl3f!Br0zXJuiThGk;fE=!@joeR@RO8E{4}Ks zzerh&-=?g?(UfZZE@eHArPSaLDI0J+Wh4HWvI!?sYH=#1F4Sw$Zz=WUnZNxbWixqE zY6E(uHsS@TThJ%933aK>=$qPteyOeKpSl%|scopFw&N|S9e7*nHoP-+JFZFHfmNwH zab0RBu20>C52beDBdOikkh&Y6NbSL=QhV{~)IMxZ?Z@X*2k?c|L2OUmi!Y|`!;aMb zxIOg%zLI(n|B*U`ovDZLwbaA-X6g}qEA=S8oq7y^O&!MB)Z=Kq_yh*0okU~WDGX0L zjZ)efj7u9qXWA&b(#9}3?JT;}#<3`E0&h&4#L~1WyeVxO%hG1>=CoNXPn*Mvv~zfC z+B~jETfp1W&g057uQ0|~8b>HDT9u~8)oB8*NfYs|G#yr^`QqJa{#cb}z6Q3&dKEUOuf=E5*I`R~HMXX&$LG>(@cHx&*p|K#Ur67CucX)Fj`TY0POrx|(>LSW z=?&PI-iX1TEokyIVW_7W!#pi$_OxQSXDdpcHjMJLW3;CO<2>8Y;n|Myo*kIr*@+i> zIx)?&3m^4#;hUar-0j(oZ+Uv~T~9Ced-`yXrymDA132Uv#6zCFc*3&}zw+$I)1CwP zjpraIiGS-EB9Hv-cb-G!G0$QA-g5-cdXC}`o?|%f8O9$y$8o}Q0)O(H#7WO7{MmCF zr#xry7taVzdq(kB<{l&f;&Lah&x`;P0MEobycKAD(GE=b6DjJ+nCPnZv(4=WxL@ zkN@*5;Cat^TqJv$={B-AULdQ{TNY3yi>Q`$sF8h9ko{3B8&H%3(MJwKooqzC9D=^G z3H{_S^p`CdAWLYFt+-gWVW1q1OXL^~lI<8QJJ2XQ@j^KfLu3~&mECBPQ!!Ld!!X%{ zW?4atybQzTOqAp-jF7X@D(7INoQpO&52NIKjFt=VBDoM_qT#K1<9bPKeW0t%bFOwTETW-Y5;aH{lg>Gv>-Ic%|HmdGc1gN^Zk^ zxgD>TJFr0BhS$j3u~6QD*UCGwNbbbz@7__Qoxvuwp@WE-}~(fF(!gRQb1pOYQ9Rd(X@ zaw4|LE_^|DW4oM+FUo1yA$#y8S;1}cGJILi#O-nxz9MJi4mk&3m2+{YoQMCA^RZJd zz}MtL+$9&`>vA!6$;N2H%w{ zv0tvjJ@Q%{kk{dRay1Uh>+yZL2KUMv@B?`x?vpp+hjK0Mm+SB&xgHP5oAIA=10Iwc z@nd-l4#`dUFS!{H$u0PAxfKt~Tk$_~8y=C{@e{cNkILKdQ+YcclXu`}@=hFJYQ}P-7MIOOvc@%$@ z$8bhIi@(X^I4e)!@A4$h$y4};JdNk%8T?b8#d&!S|B}z)f;^A^lNa#3d>$7mUg7kA z#TzeB)ab1Us8U2!D>~FDz9=aEs8tLoDuL*u1ffnbqFxC>U&VxeN*MYp77S1%G$>YF ztk^J6iN+;L3a z*=SXAFjC1yo05l7N z{aB$Kz+07rxI!7i+mu7NQaOybD@SmZaun}Sj^S!$81Gb$;~M1z-ld$xO63&Zt(?Xx zj6z^5WaGi1%?^DLHTA9H6l}TK$OyL8{G}b6H_@FY285ROay^ zWdS!S=ka01OQQcP-uQ^3#yUm7M->t46&*gN_~K^8A0Jl?*q{XB6G{*^Dn@)#3BfIj z37=BJut~At(~5-6iWQ$xY}leic_)i|iE z$M=;Q+^cNB50s6#PuYYYDz&&@sl$(ydOVm6&Yh^EQhVe(`I8G=h@F(RYPAaGHXXP|bDQEB(Wdx^{QT$aI!x`l){-%uMtTKVWE0Z{< zOyM8OG@est@K0qH=ao79OF4%N$~^v0S-|tkd0dp?6+!>c@Wu-=)aacdpejQ|b%qW# z8NMiF_@g$%fMP}<`eX#5F2jiWj1ctAFri;Y82V>eFd#!hLxvR>XV@?>BN~@v#9&Z{ z9fLC*Xv}cpg&Bz$lHtOo8E!OXq+)1B8ir+f(43*5C1V+eXJn$3k%bW%*=Wtk!N`nU zv}NRBR7O5VXB6N?8HE^=QG~G>#c0o1j&T_!=*TF=_>3}iW|U(>Mg=BjtiYs&m@ALZn z^SEBu`#RUT&bi>V+mW2z$^dG^0sqL9@_` z8-+GZ657!sbYQa3iFXQnF-6#icL`mXDs*F-upg~L52g#fXcPJ{L+D4lZ~!xfgP0{8 z!n=jTm@N!ojxdP1!Vu;O!{`u>V7_n^3xp9Y6po=&IF3caD7u6(bPMBHEKFdDZ~{HT zN!%oy!ct)p?-8bOvoMYK3Nu(H%;NtEr*VrghxZBdxK%iV_X`U`=zn1$J|HZ@?ZRSw zQ1HSXf;T=S_+YuP1RoZBu|imij|hHPDfr`~LI73?f%urP40j4a__z>^)j|k9AuPul zVFf-Zti)Pj6+R`b#yVjQJ}rb|y|5Oa5yEhn5RT6Z5!fKC!{>xZ+%1UsydYzvpyCTc zG&Ttud{KzSJwiObBqU(7pv9L3J+=r&d_^#0tB{1R3dz_eq~L2pDz*z&d|j|%hhWDy zge>e7vhhtJ7xxMdd`l?6eS#C;7F^gR6yrOB2fKw*d{@|v`-L)mPuPMz!d84=*oM8r zcKkrtfqgV5%%G?LKhwry74<pr#0A&T|KdVCTU>+-#l?7z=!J_!Z#-A@!NuYdJWupRFL5cJFZ!Xk=#LkO z0q7$J;)UWeTp|YHMPe}eiXnKhxEz;?EASF=CHjf0@KSL#`ipDuGBFeb#I<<27>0pj zI9?$};4*O?UMWUmkSO9+qKv_!idT!#7$R!$8Zj1^i}84^n1CxpEnX+;aiwU)>qRrJ z5|i)-F&S5jDR`rpifcqG-Xz*ERJ7yGViv9yv+))&7sEsc-YOPgxah>&L>ESg#dy2u z!F6IO-XU(rNU;nBaSMv#R+PkTD2v-s5qF>}mSdDyfze_mt{1CNBksf)u^MB=8jKTb zFcu8BhmcZpq?Dt2R}l1Mx9&8SWH=@NqF1tHls}LR^kD;tG6HT#2>fDtt;@jdkK0 zd|C{}dT}j2BZlEFF&v*2Bd|eShtG+TxLXwQc~QnjQNC_^!Aa_lsrtp11{j#I5+gxD9*7?f8MX1N+2s{7|gGez6ii z607ilxD!7XtMQ;%gP(}Ccu1_nPsMsXEbhY3#0DG?cjM<`BMyp9_=UI!hs0+5Qf$Ft zu@%1(+wh3kj$ex%cvS4fZ^XSgBJRU)#V$N1cH?*AempMr;P+xLj*5NwgV>K_;sN|o zJc#4sA^b@^j1%Gj{wxmS32_L25r^@lcm#hHkK!qD1b-8c;iPyRe-}q_N*u#K#BrP! zC-6`41kQ*j@h|Zd&We-xw>X8T#cBLUoWVJ97XKAbMm&RONeix}|D}a^ zwzLQrN{jIv$qN@r-gvI$gNvmlc%I~oUeZ!LU-Cn5$saF}0?IgX^SHyhGZIky057(iRk@ zttd&`P?ol%BJDs`D#s|P0;8o$TrX9jM%sxnQZ>d(H5ez=V!Tv`8>D(nkal6B)PP!P zH|nHD)JsihkoKTaYDSaPf@Y}|H%e`oB(cC{F6YrGvVv4j6?~=MORqDnxX+K(} z9!!^d(I)j_hSZOC=>TR*2Qf=Jgm+7aF=wm zbR3JMQFKXT=$6K@Sen2R=>&SDlekGbg{9IY-Xl%nW@#Glm1eL^n#KQ$4UGTbQz;p0*;R!brHgtQ!Mq!sw2v=VEjRrr*&8tbGr__P#?_0n2=Mhe4SQaC;< zMPP%p4xf`EaknJm^OB5>l8P@#(byzu@I@&W_ek;hl9YhWk``Z<^w=U9@fFF8tx^)c zDkWo^l!C8Gsn{-A@pZ|D9g-d2kg~8-%EmXPT-+-;@GYqT_eoBCTXJESRE+OP9_*G% z@m*;%?w88&J!uQ}NL%rJX&d%R+wlWw2lh$j_@PvR{Zb`c;P+{dipJ!SAJB9F_X;2dN*&qyzY)bP&g-L-><)7$>9w{8<{r z6Ved=A`Rn7=?MNR9mP}92>vD=!%68l{w|H;lr)BaNaHvyP2iu>37nBm;$PA!oRuc= zZ)ploOVjv|G=p=}EdDE<#(8ND|C8qNjC2Oik{4V@|H}*UYmFOq0 z!b|1V=r6Cq%j8fDkk{hnau^26;dq4{fy?A|c%>YPL9&Qf$ub7ZDqbx|V~DK5Yvfp5 zF301wassZ9wRoMZ$Ca`Xub0iZN>0KX9o< z1y&@GQ+u{?n# z@(J|FCvlT}3QOflyhonG&GIzfE6-q=Jd6J)pT;fn9Ns6-<5u|$-Y+j$N&m~dB=xKZ z4N*$*pae|%I9z$!TqACs5iPB{o4mxHld z4#6knr{vXGC$GV$nhe1ZORl275RJc)nHQ+QgQ#((4)oReqq zU->l7%X9djJdbDOGkBJ=;ClLBS%_yVi*TW`7|&6>aFODT=PEw9SXqMSDZc2XEXDH` zKlE1o@d70PeUw1FP+5jclpwrF2}WNf1TR*W<5Fb>UZSi-KV=nOs;owTWer}YgkpfQ z7B5%AFi;7{E0hRarmVv&l}HRyM7&CoF<4RYY9$&&6b)XZ#Nu)#9l8h% zRE&7NV#ZZU65gOB<7y=ZZ&Xrojbg={6dQ&rcDz~1!nH~^-lF7UnBu@&l>!V`oOqk! z!U&}pZ&y6HPASDZl+75al%b$(K~dR?lClkDWjiX$4pfzLj8ZBvTB*eKN)>99ofxB3 zW2{nxaY`-5D|NU*smBCm7bYqVs8x2OPH9BF(u4+O4;qzbG$}1;R$6hR(uPS&J6el>y9A z1~FF|!aQXd9m)~RSB_$VGJ=K5F?1@&u}B$3mokQKWgLr@2`o`gphr20o0L;ns!ZZN z$`o!^rtw~72FsLL{6FP1Zc*m&K4l)aDrfM1Wx*=?U*YxGXFZ@S!tKgpd{FVi9f~(T zr1)UDvIHMie6d1VijOFMSgH8qqe=i)DS`NyvJ7`BLHM{5jMYjAKA|kf8f67OsjS3W zWfeZ9tj0QJ4L+@eV!g5!pHaeamlBT8DiPSAti$J&NZhT6_`D)xqoU#qN;Ebp8hlZS z#XU+qzN92zv!cb96+N~nMtnsvW2=&cuPVvdrljC&N-DN1R(xHtVTWSJHwRI>3+ zB^UQ94tz@~zVsliW_T0ErG;ipPH9#(eYXG#MOD7*1Ezr*U4H!~c|dJfob! zv(yDQ(EsW}JX>9a3)RJVj_QSrRBt?2^})sJ5u(HNp?@ESE1m#gu3t(t%T#uN#OqZvu2Pfm1~nO1 zt0{P+nu=>wE8e8qFjTeU&1x2|RkQIHH5bEF2i~d{V7ThU+f)}usKt1@>cMqtDc+%O z#z?gc1$7IG>Q)f$XbYcXD}!wqUZ zCaAkGQEfo2x*K(BBkI*AG^l&fs5YZXZ9%iziW}87Oj6s?qIO`i+KG3ndoe}bhj*!6 zn5uSTnz|pYY7eHXy=YVWFhlJ}yLtdK)q|L&9>TlT!L|L@F?6frSgcN9iFyJ(>Pg(Bp2AXf67Nx`aI-p%_o_2krq1I3 zsi$#^I*0eE^SD(#gZHZoR@49LLVQ47gxl4{_@L^AJ5+CcNcF*TbqPMK`eKE;6dzIj zuu}EMN7VqVQUmcZbs6qdgYa=R7^~F~d_rB0HR=j{QeBC)>MDFnU5$0>8hly}#d>uu zKBI==E;SsVRU@!LU5C%9k+@qG@p)CoMpeZZ)M#u{HTa?$i+j{~d`V5fW>t$Xt9oov zjrfXc##S{6UsaQ_O-;eq)KqL&t@yfX!w%JsZ>U+=sb=GwYA)_o9r%`7fcsP@zOA~j zOD)ECR1bEmrTDJ88TYGY_@252d(^G?zPb&2)$RC!x&!;va{N%Oz<#w7KT@mkfVvYu zR;%%#T7#dcwRlLa!%x+EJgn}*&(sDSPV7<~_TcwwFOI5x_=DPyW9k9?Q9X#`>LL6| zJ&Y6T0RF5F;t6#Ke^H0=qhiqx{f2${#O?3P7KzK)f(&87_$m!i%DU(Kjjt zFOFJ{OQTlcB~dHUFKQKD8nqhzqt@VMQK1+RwH7ar3d6vtaJ(Wa0+&Ut!z-gAF(^vJ ztDyWO2WRVWbBVh!2?mL zcreO}pGMj6aFiXti^{^^qq1=-Di{BVa^Q4S0sa}~#F;1;{uNb>vr!&=e|;(TuHTFw ztS`e4*KffC>$l>^>$leGt8i}pPW*R$HO{ZE!T;9R z;su&I^wHGgg_>QsMALv5X?Ek4nnn!LG~rd6J$R$08P{l9@Fq5|nqS=qHXnL?!(~GZa`mjyYkFRMCV7ulZc4`jc+nU4Jr5V6? zG=tc!8NwdTFut!jg1wrf_T9f7HbU;KrChw8SjKJ7a?Iu9#p##H?67P)>u`EW$Ct_5r ziHXK1V>DPB6N_~*@z@ZPfX~Hfad(U!pN}!(D=}tljY+~+W0J8gCIzpKO~sH{E9S-8 z&=G6L{Malkh|R{r*j#)n)`8E&7T~T}CpN~q@P*i7Y>M^Zi?OBnYV2lgi!H+~aa-_# zxUIN7ZX1@zZO4b>c3@RpIX)Iwfz@%9_(WV4*2V3_XXC1|A+82rh^xisxH^0_t{&Us zcHtXw4cHmC8{dp;#ICp|d?#)XcE>eiPh1PWAJ>Y#ac%ffTst0$>%h^b$+z^Pv8r!ORCafl3hV*~J8oWFql#weE){+DN=amUzQV_@nAw3`Xp|_$i%HEByK}7aXU(hJ1{k|9Mcjj(3)6@>4{b7Ox%fE605N* zu?F8sti|rcI(#>=9=}Z7g~N#r_*LR=Jet^u-y}BSw~2f3SYk7Nm)L^G6I*dKu?@!( z+i^Ux11A$Z@%O~NIF+~$|48h@>BMgQGjTu8B=+E6iM=?R*oS{7_T%Zq1NcwkL7YoG zg!74q@xR0Y=J(A1T%a9f<)@ z+Ho{$C(x`tfg80aF-dz0E!s&;)=puDb{g;2&S1877IUdD?j_(w;$=c0nl5 z9omIhtX+g9+QsP6df_ImH6K$ zn^Dx2p`_b_vTiFXx^1ZHwqulT2S)44alNhrHM&ZS(N$rrZYRd+sxd)VgNeFY)amNb zsH;blZWo$$4Y*Oa8wNJ&-BRq)`QiIIf9%x-;0L-u?9(m7!@3~+Oc#s;x)A(aw;Ts`EAR{5N*vOy z!f$k|aYVNUztx4}G2L4HP8Wv9b>aBEE&@k&>+nZiB#!Gu{7EO{Nu7$PbkX>mPJ@%W zSe(+u<3G9toYQIXU!5N3bw>P8XT~$SBs@!>jOXZ6aFIS0z4TV}*4yv`y&Zk@S$Ls7 z8<*&F@gltgef0%+vEGSG^)9?bUyOcw4_>M-MSuNfyi8w)0s1X?xqd4K>bKz)`t7(( zzXPw-mt&B=0VbM*SWP)i>kK`WC!J--==SHoR5ej@$Gd_?W&Ed-Z#k@e6$)4(a>xOZ@>H)*r;5^oMXle;9w(58w&?ApW8s!jt-8{8fJhf72huN&N`^ zu0Mv;`s4VgeiZ-GkKwF-9RJo&;A#B{oYSAg%M7P5z%YqHhAF(tFpa^68NAvsi#Hoi z<66TUh8gDZcEcHrHY`|6+ZYz2#;^!u4T~|(;Dzx9Z`@$;!34t+Of>kS*02?Dbi-=28P;HiAr$R~wU}uL z!z@EM<`^O{*RT#9hDgjeh*)Tl(P>bz$PkS#g9hD(SS&WgV~HUFJq9gqGU&0?V8nY2 zX54H@!g~$LSY}AU|1+fG7K0Vj~WWF%HYJu3@+Sh zD8|PP9;`N$;uD6=SYs%|Ck zhMk6X+-vB-w+x-Q&#)KYHtfSLLl?ed=*Ditetg%^gZmA=_@1E;dkp>fzTp7&8V=$I zhC|qAIE)_}2C&~Sh#wh-@PJ_$4;qf(Cx)YV$S{JR8jj&%!*Tq~Fp2|)G5p*xj)R5? z{K9YohYTn2OT#G~HcaAIhAI5kFpb9yGdO0L#UBl)aojM6KN;q6!f*zEHY~V>RcTm= zzZe$bq+v1sZt%h>gE#(Z@WC0w68y{Hi*tsh_^-ha|1f?#!$S(xEB44VR)%A9Q}Rx0Wt5F7D#mD3jT($L#$t>y9^;G&7;n_#2BRJmj7Cf}n$ciPLZdMmO~w>78&h$k z(TYh%8(NHZOg3iWoyKfTG3Mf3MhB)E3oy;-M61z->BeHrFnZ8#EX6G2X3RB~VV-dd zI*eN}-?$A6jN7r$xC5QWa@=98z=w>LSZ=JshmAY2!dQ)u7;CW7Sc{Ju>#)jLkNw77 z_>r*z4;Xjj$Hqqd!`Ot=#y$9_u^DHKE%=wQ6)!Ngp^vE@{Y@PhWa`ALOnWidv=7&q zy6`4bH-?(_{0XIhKLO=0+hDICX45jbvIhd-Gjal$0x&n6j9m{k156pbfM8vNB1 zi>FNS_?syKCrw)X-K57UlM(+gnQ_{bgnycnamJK_f0q5E;2jtTyp^~Haqb=vkSe<#dyBigWl#+yuiE}eavO(XWoLBnzy3Ac^h74-i`t0 z9eBC990Sc2c!jwVmzk?D$h;GS&DD6dxdubbwRnxW4wswj@mljPTw!j&>&&}xrMVHW zH#gxb^B%mx+>EQuEqJ5371x;C@FsIRhMGI@W^*U5HSfh+%=<9R+=aKAyD{9nA8#}F zV1&6BZ#VbhI&(kXVLpJ7=7T7i520*6jH-D6qs)UCZ5~36c^I|kBWN-oMYDMXH=2)O zlKD7V%%hlW9>Wy#INoKRz*O@Iw3<(1y7?4lm?zP0p2AG?G-jJ;FvmQLx#rWDXP(1i z^E_@dpTURC3vQ)P%nR{R^CGM=FUH5rURZ7R#wW}^SYuv-PnvzP*1Qy-GW%hj*&m-a z2VlK95T7wG!(HYeeAXO{4dxJh&b%CVn^)lT=9SoJUWG51S7VcT4Zdg V=_>wsc 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

y2F+tV4*X(*A^H|^tNyMD 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%0DT<_VPYRH_7P$qDfUrfcZj`E>`t+}#6DW=MPeT# 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