diff --git a/.gitignore b/.gitignore index 959ee2e..e381470 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,4 @@ uv.lock # Claude Code .claude/* !.claude/plugins/ +TestProject/Screenshots/ diff --git a/README.jp.md b/README.jp.md index 8a4c100..4daea0c 100644 --- a/README.jp.md +++ b/README.jp.md @@ -4,6 +4,7 @@ [![Complexity](https://img.shields.io/badge/complexity-A%2FB-brightgreen)](https://github.com/bigdra50/unity-cli/actions/workflows/ci.yml) [![Maintainability](https://img.shields.io/badge/maintainability-A-brightgreen)](https://github.com/bigdra50/unity-cli/actions/workflows/ci.yml) [![Python](https://img.shields.io/badge/python-3.11%20%7C%203.12%20%7C%203.13-blue)](https://www.python.org/) +[![Platform](https://img.shields.io/badge/platform-macOS%20%7C%20Windows%20%7C%20Linux-lightgrey)](https://github.com/bigdra50/unity-cli) [![Unity](https://img.shields.io/badge/Unity-2022.3%2B-black?logo=unity)](https://unity.com/) [![openupm](https://img.shields.io/npm/v/com.bigdra50.unity-bridge?label=openupm®istry_uri=https://package.openupm.com)](https://openupm.com/packages/com.bigdra50.unity-bridge/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) @@ -125,6 +126,9 @@ u completion -s bash >> ~/.bashrc # Fish u completion -s fish > ~/.config/fish/completions/unity-cli.fish + +# PowerShell +u completion -s powershell >> $PROFILE ``` ### プロジェクトを開く @@ -549,7 +553,8 @@ flowchart TB ```bash # Relay Serverが起動しているか確認 -lsof -i :6500 +lsof -i :6500 # macOS / Linux +netstat -ano | findstr :6500 # Windows # 接続中インスタンス確認 u instances diff --git a/README.md b/README.md index 5098e47..9356144 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ [![Complexity](https://img.shields.io/badge/complexity-A%2FB-brightgreen)](https://github.com/bigdra50/unity-cli/actions/workflows/ci.yml) [![Maintainability](https://img.shields.io/badge/maintainability-A-brightgreen)](https://github.com/bigdra50/unity-cli/actions/workflows/ci.yml) [![Python](https://img.shields.io/badge/python-3.11%20%7C%203.12%20%7C%203.13-blue)](https://www.python.org/) +[![Platform](https://img.shields.io/badge/platform-macOS%20%7C%20Windows%20%7C%20Linux-lightgrey)](https://github.com/bigdra50/unity-cli) [![Unity](https://img.shields.io/badge/Unity-2022.3%2B-black?logo=unity)](https://unity.com/) [![openupm](https://img.shields.io/npm/v/com.bigdra50.unity-bridge?label=openupm®istry_uri=https://package.openupm.com)](https://openupm.com/packages/com.bigdra50.unity-bridge/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) @@ -125,6 +126,9 @@ u completion -s bash >> ~/.bashrc # Fish u completion -s fish > ~/.config/fish/completions/unity-cli.fish + +# PowerShell +u completion -s powershell >> $PROFILE ``` ### Open Project @@ -549,7 +553,8 @@ See [docs/protocol-spec.md](docs/protocol-spec.md) for details. ```bash # Check if Relay Server is running -lsof -i :6500 +lsof -i :6500 # macOS / Linux +netstat -ano | findstr :6500 # Windows # Check connected instances u instances diff --git a/TestProject/Assets/Scenes/SampleScene.unity b/TestProject/Assets/Scenes/SampleScene.unity index 53d7537..d3732e8 100644 --- a/TestProject/Assets/Scenes/SampleScene.unity +++ b/TestProject/Assets/Scenes/SampleScene.unity @@ -222,8 +222,8 @@ MonoBehaviour: m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3} - m_Name: - m_EditorClassIdentifier: + m_Name: + m_EditorClassIdentifier: m_RenderShadows: 1 m_RequiresDepthTextureOption: 2 m_RequiresOpaqueTextureOption: 2 @@ -284,7 +284,7 @@ MonoBehaviour: m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: c7aa501fcf147478b82d310cebf26faa, type: 3} - m_Name: + m_Name: m_EditorClassIdentifier: Assembly-CSharp::SampleHUDController --- !u!114 &334705904 MonoBehaviour: @@ -296,7 +296,7 @@ MonoBehaviour: m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 19102, guid: 0000000000000000e000000000000000, type: 0} - m_Name: + m_Name: m_EditorClassIdentifier: UnityEngine.dll::UnityEngine.UIElements.UIDocument m_PanelSettings: {fileID: 0} m_ParentUI: {fileID: 0} @@ -350,14 +350,14 @@ Light: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 410087039} m_Enabled: 1 - serializedVersion: 11 + serializedVersion: 12 m_Type: 1 m_Color: {r: 1, g: 1, b: 1, a: 1} m_Intensity: 2 m_Range: 10 m_SpotAngle: 30 m_InnerSpotAngle: 21.80208 - m_CookieSize: 10 + m_CookieSize2D: {x: 10, y: 10} m_Shadows: m_Type: 2 m_Resolution: -1 @@ -432,8 +432,8 @@ MonoBehaviour: m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3} - m_Name: - m_EditorClassIdentifier: + m_Name: + m_EditorClassIdentifier: m_UsePipelineSettings: 1 m_AdditionalLightsShadowResolutionTier: 2 m_CustomShadowLayers: 0 @@ -478,8 +478,8 @@ MonoBehaviour: m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 172515602e62fb746b5d573b38a5fe58, type: 3} - m_Name: - m_EditorClassIdentifier: + m_Name: + m_EditorClassIdentifier: m_IsGlobal: 1 priority: 0 blendDistance: 0 diff --git a/TestProject/Assets/Settings/Mobile_RPAsset.asset b/TestProject/Assets/Settings/Mobile_RPAsset.asset index ffcfaf0..fedee07 100644 --- a/TestProject/Assets/Settings/Mobile_RPAsset.asset +++ b/TestProject/Assets/Settings/Mobile_RPAsset.asset @@ -11,9 +11,9 @@ MonoBehaviour: m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: bf2edee5c58d82540a51f03df9d42094, type: 3} m_Name: Mobile_RPAsset - m_EditorClassIdentifier: - k_AssetVersion: 12 - k_AssetPreviousVersion: 12 + m_EditorClassIdentifier: + k_AssetVersion: 13 + k_AssetPreviousVersion: 13 m_RendererType: 1 m_RendererData: {fileID: 0} m_RendererDataList: @@ -53,6 +53,7 @@ MonoBehaviour: m_AdditionalLightsShadowResolutionTierHigh: 1024 m_ReflectionProbeBlending: 1 m_ReflectionProbeBoxProjection: 1 + m_ReflectionProbeAtlas: 1 m_ShadowDistance: 50 m_ShadowCascadeCount: 1 m_Cascade2Split: 0.25 @@ -78,11 +79,11 @@ MonoBehaviour: m_UseAdaptivePerformance: 1 m_ColorGradingMode: 0 m_ColorGradingLutSize: 32 + m_AllowPostProcessAlphaOutput: 0 m_UseFastSRGBLinearConversion: 1 m_SupportDataDrivenLensFlare: 1 m_SupportScreenSpaceLensFlare: 1 m_GPUResidentDrawerMode: 0 - m_UseLegacyLightmaps: 0 m_SmallMeshScreenPercentage: 0 m_GPUResidentDrawerEnableOcclusionCullingInCameras: 0 m_ShadowType: 1 @@ -98,7 +99,7 @@ MonoBehaviour: m_Values: [] obsoleteHasProbeVolumes: m_Keys: [] - m_Values: + m_Values: m_PrefilteringModeMainLightShadows: 3 m_PrefilteringModeAdditionalLight: 4 m_PrefilteringModeAdditionalLightShadows: 0 @@ -109,6 +110,7 @@ MonoBehaviour: m_PrefilterDebugKeywords: 1 m_PrefilterWriteRenderingLayers: 1 m_PrefilterHDROutput: 1 + m_PrefilterAlphaOutput: 0 m_PrefilterSSAODepthNormals: 1 m_PrefilterSSAOSourceDepthLow: 1 m_PrefilterSSAOSourceDepthMedium: 0 @@ -126,8 +128,14 @@ MonoBehaviour: m_PrefilterSoftShadowsQualityHigh: 1 m_PrefilterSoftShadows: 0 m_PrefilterScreenCoord: 1 + m_PrefilterScreenSpaceIrradiance: 0 m_PrefilterNativeRenderPass: 1 m_PrefilterUseLegacyLightmaps: 0 + m_PrefilterBicubicLightmapSampling: 0 + m_PrefilterReflectionProbeRotation: 0 + m_PrefilterReflectionProbeBlending: 0 + m_PrefilterReflectionProbeBoxProjection: 0 + m_PrefilterReflectionProbeAtlas: 0 m_ShaderVariantLogLevel: 0 m_ShadowCascades: 0 m_Textures: diff --git a/TestProject/Assets/Settings/PC_RPAsset.asset b/TestProject/Assets/Settings/PC_RPAsset.asset index 32a7075..9b2b046 100644 --- a/TestProject/Assets/Settings/PC_RPAsset.asset +++ b/TestProject/Assets/Settings/PC_RPAsset.asset @@ -11,9 +11,9 @@ MonoBehaviour: m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: bf2edee5c58d82540a51f03df9d42094, type: 3} m_Name: PC_RPAsset - m_EditorClassIdentifier: - k_AssetVersion: 12 - k_AssetPreviousVersion: 12 + m_EditorClassIdentifier: + k_AssetVersion: 13 + k_AssetPreviousVersion: 13 m_RendererType: 1 m_RendererData: {fileID: 0} m_RendererDataList: @@ -53,6 +53,7 @@ MonoBehaviour: m_AdditionalLightsShadowResolutionTierHigh: 1024 m_ReflectionProbeBlending: 1 m_ReflectionProbeBoxProjection: 1 + m_ReflectionProbeAtlas: 1 m_ShadowDistance: 50 m_ShadowCascadeCount: 4 m_Cascade2Split: 0.25 @@ -78,11 +79,11 @@ MonoBehaviour: m_UseAdaptivePerformance: 1 m_ColorGradingMode: 0 m_ColorGradingLutSize: 32 + m_AllowPostProcessAlphaOutput: 0 m_UseFastSRGBLinearConversion: 0 m_SupportDataDrivenLensFlare: 1 m_SupportScreenSpaceLensFlare: 1 m_GPUResidentDrawerMode: 0 - m_UseLegacyLightmaps: 0 m_SmallMeshScreenPercentage: 0 m_GPUResidentDrawerEnableOcclusionCullingInCameras: 0 m_ShadowType: 1 @@ -98,7 +99,7 @@ MonoBehaviour: m_Values: [] obsoleteHasProbeVolumes: m_Keys: [] - m_Values: + m_Values: m_PrefilteringModeMainLightShadows: 3 m_PrefilteringModeAdditionalLight: 4 m_PrefilteringModeAdditionalLightShadows: 0 @@ -109,6 +110,7 @@ MonoBehaviour: m_PrefilterDebugKeywords: 1 m_PrefilterWriteRenderingLayers: 0 m_PrefilterHDROutput: 1 + m_PrefilterAlphaOutput: 0 m_PrefilterSSAODepthNormals: 0 m_PrefilterSSAOSourceDepthLow: 1 m_PrefilterSSAOSourceDepthMedium: 1 @@ -126,8 +128,14 @@ MonoBehaviour: m_PrefilterSoftShadowsQualityHigh: 0 m_PrefilterSoftShadows: 0 m_PrefilterScreenCoord: 1 + m_PrefilterScreenSpaceIrradiance: 0 m_PrefilterNativeRenderPass: 1 m_PrefilterUseLegacyLightmaps: 0 + m_PrefilterBicubicLightmapSampling: 0 + m_PrefilterReflectionProbeRotation: 0 + m_PrefilterReflectionProbeBlending: 0 + m_PrefilterReflectionProbeBoxProjection: 0 + m_PrefilterReflectionProbeAtlas: 0 m_ShaderVariantLogLevel: 0 m_ShadowCascades: 0 m_Textures: diff --git a/TestProject/Assets/Settings/UniversalRenderPipelineGlobalSettings.asset b/TestProject/Assets/Settings/UniversalRenderPipelineGlobalSettings.asset index 75c6b8e..77b29c5 100644 --- a/TestProject/Assets/Settings/UniversalRenderPipelineGlobalSettings.asset +++ b/TestProject/Assets/Settings/UniversalRenderPipelineGlobalSettings.asset @@ -11,7 +11,7 @@ MonoBehaviour: m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: 2ec995e51a6e251468d2a3fd8a686257, type: 3} m_Name: UniversalRenderPipelineGlobalSettings - m_EditorClassIdentifier: + m_EditorClassIdentifier: m_ShaderStrippingSetting: m_Version: 0 m_ExportShaderVariants: 1 @@ -62,9 +62,14 @@ MonoBehaviour: - rid: 8078647796443643910 - rid: 8078647796443643911 - rid: 8078647796443643912 + - rid: 4376185446353862849 + - rid: 4376185446353862850 + - rid: 4376185446353862851 + - rid: 4376185446353862852 + - rid: 4376185446353862853 m_RuntimeSettings: m_List: [] - m_AssetVersion: 8 + m_AssetVersion: 10 m_ObsoleteDefaultVolumeProfile: {fileID: 0} m_RenderingLayerNames: - Light Layer default @@ -90,10 +95,45 @@ MonoBehaviour: m_Values: [] obsoleteHasProbeVolumes: m_Keys: [] - m_Values: + m_Values: references: version: 2 RefIds: + - rid: 4376185446353862849 + type: {class: RayTracingRenderPipelineResources, ns: UnityEngine.Rendering.UnifiedRayTracing, asm: Unity.UnifiedRayTracing.Runtime} + data: + m_Version: 1 + m_GeometryPoolKernels: {fileID: 7200000, guid: 98e3d58cae7210c4786f67f504c9e899, type: 3} + m_CopyBuffer: {fileID: 7200000, guid: 1b95b5dcf48d1914c9e1e7405c7660e3, type: 3} + m_CopyPositions: {fileID: 7200000, guid: 1ad53a96b58d3c3488dde4f14db1aaeb, type: 3} + m_BitHistogram: {fileID: 7200000, guid: 8670f7ce4b60cef43bed36148aa1b0a2, type: 3} + m_BlockReducePart: {fileID: 7200000, guid: 4e034cc8ea2635c4e9f063e5ddc7ea7a, type: 3} + m_BlockScan: {fileID: 7200000, guid: 4d6d5de35fa45ef4a92119397a045cc9, type: 3} + m_BuildHlbvh: {fileID: 7200000, guid: 2d70cd6be91bd7843a39a54b51c15b13, type: 3} + m_RestructureBvh: {fileID: 7200000, guid: 56641cb88dcb31a4398a4997ef7a7a8c, type: 3} + m_Scatter: {fileID: 7200000, guid: a2eaeefdac4637a44b734e85b7be9186, type: 3} + - rid: 4376185446353862850 + type: {class: OnTilePostProcessResource, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_Version: 0 + m_UberPostShader: {fileID: 4800000, guid: fe4f13c1004a07d4ea1e30bfd0326d9e, type: 3} + - rid: 4376185446353862851 + type: {class: URPTerrainShaderSetting, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_Version: 0 + m_IncludeTerrainShaders: 1 + - rid: 4376185446353862852 + type: {class: UniversalRenderPipelineRuntimeTerrainShaders, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} + data: + m_Version: 0 + m_TerrainDetailLit: {fileID: 4800000, guid: f6783ab646d374f94b199774402a5144, type: 3} + m_TerrainDetailGrassBillboard: {fileID: 4800000, guid: 29868e73b638e48ca99a19ea58c48d90, type: 3} + m_TerrainDetailGrass: {fileID: 4800000, guid: e507fdfead5ca47e8b9a768b51c291a1, type: 3} + - rid: 4376185446353862853 + type: {class: URPReflectionProbeSettings, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Universal.Runtime} + data: + version: 1 + useReflectionProbeRotation: 0 - rid: 6852985685364965376 type: {class: URPShaderStrippingSetting, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} data: @@ -135,9 +175,9 @@ MonoBehaviour: m_CoreBlitPS: {fileID: 4800000, guid: 93446b5c5339d4f00b85c159e1159b7c, type: 3} m_CoreBlitColorAndDepthPS: {fileID: 4800000, guid: d104b2fc1ca6445babb8e90b0758136b, type: 3} m_SamplingPS: {fileID: 4800000, guid: 04c410c9937594faa893a11dceb85f7e, type: 3} - m_TerrainDetailLit: {fileID: 4800000, guid: f6783ab646d374f94b199774402a5144, type: 3} - m_TerrainDetailGrassBillboard: {fileID: 4800000, guid: 29868e73b638e48ca99a19ea58c48d90, type: 3} - m_TerrainDetailGrass: {fileID: 4800000, guid: e507fdfead5ca47e8b9a768b51c291a1, type: 3} + m_TerrainDetailLit: {fileID: 0} + m_TerrainDetailGrassBillboard: {fileID: 0} + m_TerrainDetailGrass: {fileID: 0} - rid: 6852985685364965381 type: {class: UniversalRenderPipelineRuntimeTextures, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} data: @@ -155,11 +195,11 @@ MonoBehaviour: m_SpriteUnshadowShader: {fileID: 4800000, guid: de02b375720b5c445afe83cd483bedf3, type: 3} m_GeometryShadowShader: {fileID: 4800000, guid: 19349a0f9a7ed4c48a27445bcf92e5e1, type: 3} m_GeometryUnshadowShader: {fileID: 4800000, guid: 77774d9009bb81447b048c907d4c6273, type: 3} - m_FallOffLookup: {fileID: 2800000, guid: 5688ab254e4c0634f8d6c8e0792331ca, type: 3} m_CopyDepthPS: {fileID: 4800000, guid: d6dae50ee9e1bfa4db75f19f99355220, type: 3} m_DefaultLitMaterial: {fileID: 2100000, guid: a97c105638bdf8b4a8650670310a4cd3, type: 2} m_DefaultUnlitMaterial: {fileID: 2100000, guid: 9dfc825aed78fcd4ba02077103263b40, type: 2} m_DefaultMaskMaterial: {fileID: 2100000, guid: 15d0c3709176029428a0da2f8cecf0b5, type: 2} + m_DefaultMesh2DLitMaterial: {fileID: 2100000, guid: 9452ae1262a74094f8a68013fbcd1834, type: 2} - rid: 6852985685364965383 type: {class: UniversalRenderPipelineEditorMaterials, ns: UnityEngine.Rendering.Universal, asm: Unity.RenderPipelines.Universal.Runtime} data: @@ -232,7 +272,7 @@ MonoBehaviour: m_version: 0 m_IncludeReferencedInScenes: 0 m_IncludeAssetsByLabel: 0 - m_LabelToInclude: + m_LabelToInclude: - rid: 6852985685364965392 type: {class: ShaderStrippingSetting, ns: UnityEngine.Rendering, asm: Unity.RenderPipelines.Core.Runtime} data: diff --git a/TestProject/Assets/Tests/Editor/BridgeManagerAsyncTests.cs b/TestProject/Assets/Tests/Editor/BridgeManagerAsyncTests.cs index 61ff235..2d04749 100644 --- a/TestProject/Assets/Tests/Editor/BridgeManagerAsyncTests.cs +++ b/TestProject/Assets/Tests/Editor/BridgeManagerAsyncTests.cs @@ -1,10 +1,13 @@ using System; using System.Collections.Generic; +using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using Newtonsoft.Json.Linq; using NUnit.Framework; using UnityBridge; +using UnityEngine; +using UnityEngine.TestTools; namespace Game.Tests.Editor { @@ -43,6 +46,8 @@ public async Task ExecuteCommandOnMainThreadAsync_DispatcherThrows_SendsErrorVia // async Task なので await で例外ハンドリングを確認できる // 内部 catch で SendCommandErrorAsync が呼ばれるため、例外は伝播しない + BridgeLog.Enabled = true; + LogAssert.Expect(LogType.Error, new Regex("Command execution failed: InvalidOperationException - test error")); await manager.ExecuteCommandOnMainThreadAsync(args); Assert.That(sentErrors.Count, Is.EqualTo(1)); diff --git a/TestProject/Assets/Tests/Editor/SceneTest.cs b/TestProject/Assets/Tests/Editor/SceneTest.cs index e520d57..090b9da 100644 --- a/TestProject/Assets/Tests/Editor/SceneTest.cs +++ b/TestProject/Assets/Tests/Editor/SceneTest.cs @@ -1,6 +1,8 @@ using System.Collections.Generic; using Newtonsoft.Json.Linq; using NUnit.Framework; +using UnityBridge; +using UnityEditor.SceneManagement; using UnityEngine; using UnityEngine.SceneManagement; @@ -111,6 +113,30 @@ public void HandleCommand_Hierarchy_ItemsNeverExceedPageSize_VariousSizes(int pa Assert.That(items.Count, Is.LessThanOrEqualTo(pageSize)); } + [Test] + public void HandleCommand_Save_UntitledScene_ThrowsInvalidParams() + { + // Capture current scene layout to restore after the test + var sceneSetup = EditorSceneManager.GetSceneManagerSetup(); + + // NewScene(Single) replaces all open scenes with a fresh untitled scene, + // avoiding the "Cannot create additively with untitled scene unsaved" Unity constraint + EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Single); + + try + { + var ex = Assert.Throws(() => + Scene.HandleCommand(new JObject { ["action"] = "save" })); + + Assert.That(ex.Code, Is.EqualTo(ErrorCode.InvalidParams)); + } + finally + { + if (sceneSetup is { Length: > 0 }) + EditorSceneManager.RestoreSceneManagerSetup(sceneSetup); + } + } + private List CreateHierarchy(int rootCount, int childrenPerRoot) { var roots = new List(); diff --git a/TestProject/Packages/manifest.json b/TestProject/Packages/manifest.json index eb40b5e..575b347 100644 --- a/TestProject/Packages/manifest.json +++ b/TestProject/Packages/manifest.json @@ -1,6 +1,6 @@ { "dependencies": { - "com.bigdra50.unity-bridge": "file:/Volumes/CrucialX9/dev/github.com/bigdra50/unity-cli/UnityBridge", + "com.bigdra50.unity-bridge": "file:../../UnityBridge", "com.unity.ai.navigation": "2.0.9", "com.unity.ide.rider": "3.0.38", "com.unity.ide.visualstudio": "2.0.23", diff --git a/TestProject/Packages/packages-lock.json b/TestProject/Packages/packages-lock.json index d7c15f2..ae38418 100644 --- a/TestProject/Packages/packages-lock.json +++ b/TestProject/Packages/packages-lock.json @@ -1,7 +1,7 @@ { "dependencies": { "com.bigdra50.unity-bridge": { - "version": "file:/Volumes/CrucialX9/dev/github.com/bigdra50/unity-cli/UnityBridge", + "version": "file:../../UnityBridge", "depth": 0, "source": "local", "dependencies": { @@ -18,7 +18,7 @@ "url": "https://packages.unity.com" }, "com.unity.burst": { - "version": "1.8.24", + "version": "1.8.28", "depth": 2, "source": "registry", "dependencies": { @@ -28,11 +28,11 @@ "url": "https://packages.unity.com" }, "com.unity.collections": { - "version": "2.5.7", + "version": "2.6.2", "depth": 2, "source": "registry", "dependencies": { - "com.unity.burst": "1.8.19", + "com.unity.burst": "1.8.23", "com.unity.mathematics": "1.3.2", "com.unity.test-framework": "1.4.6", "com.unity.nuget.mono-cecil": "1.11.5", @@ -74,14 +74,14 @@ "url": "https://packages.unity.com" }, "com.unity.mathematics": { - "version": "1.3.2", + "version": "1.3.3", "depth": 2, "source": "registry", "dependencies": {}, "url": "https://packages.unity.com" }, "com.unity.multiplayer.center": { - "version": "1.0.0", + "version": "1.0.1", "depth": 0, "source": "builtin", "dependencies": { @@ -89,21 +89,21 @@ } }, "com.unity.nuget.mono-cecil": { - "version": "1.11.5", + "version": "1.11.6", "depth": 3, "source": "registry", "dependencies": {}, "url": "https://packages.unity.com" }, "com.unity.nuget.newtonsoft-json": { - "version": "3.2.1", + "version": "3.2.2", "depth": 1, "source": "registry", "dependencies": {}, "url": "https://packages.unity.com" }, "com.unity.render-pipelines.core": { - "version": "17.2.0", + "version": "17.3.0", "depth": 1, "source": "builtin", "dependencies": { @@ -113,17 +113,16 @@ "com.unity.collections": "2.4.3", "com.unity.modules.physics": "1.0.0", "com.unity.modules.terrain": "1.0.0", - "com.unity.modules.jsonserialize": "1.0.0", - "com.unity.rendering.light-transport": "1.0.1" + "com.unity.modules.jsonserialize": "1.0.0" } }, "com.unity.render-pipelines.universal": { - "version": "17.2.0", + "version": "17.3.0", "depth": 0, "source": "builtin", "dependencies": { - "com.unity.render-pipelines.core": "17.2.0", - "com.unity.shadergraph": "17.2.0", + "com.unity.render-pipelines.core": "17.3.0", + "com.unity.shadergraph": "17.3.0", "com.unity.render-pipelines.universal-config": "17.0.3" } }, @@ -135,29 +134,19 @@ "com.unity.render-pipelines.core": "17.0.3" } }, - "com.unity.rendering.light-transport": { - "version": "1.0.1", - "depth": 2, - "source": "builtin", - "dependencies": { - "com.unity.collections": "2.2.0", - "com.unity.mathematics": "1.2.4", - "com.unity.modules.terrain": "1.0.0" - } - }, "com.unity.searcher": { - "version": "4.9.3", + "version": "4.9.4", "depth": 2, "source": "registry", "dependencies": {}, "url": "https://packages.unity.com" }, "com.unity.shadergraph": { - "version": "17.2.0", + "version": "17.3.0", "depth": 1, "source": "builtin", "dependencies": { - "com.unity.render-pipelines.core": "17.2.0", + "com.unity.render-pipelines.core": "17.3.0", "com.unity.searcher": "4.9.3" } }, @@ -172,7 +161,7 @@ } }, "com.unity.test-framework.performance": { - "version": "3.1.0", + "version": "3.2.0", "depth": 3, "source": "registry", "dependencies": { diff --git a/TestProject/ProjectSettings/GraphicsSettings.asset b/TestProject/ProjectSettings/GraphicsSettings.asset index aa5a1c3..84b2182 100644 --- a/TestProject/ProjectSettings/GraphicsSettings.asset +++ b/TestProject/ProjectSettings/GraphicsSettings.asset @@ -36,10 +36,8 @@ GraphicsSettings: - {fileID: 10783, guid: 0000000000000000f000000000000000, type: 0} m_PreloadedShaders: [] m_PreloadShadersBatchTimeLimit: -1 - m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, - type: 0} - m_CustomRenderPipeline: {fileID: 11400000, guid: 4b83569d67af61e458304325a23e5dfd, - type: 2} + m_SpritesDefaultMaterial: {fileID: 10754, guid: 0000000000000000f000000000000000, type: 0} + m_CustomRenderPipeline: {fileID: 11400000, guid: 4b83569d67af61e458304325a23e5dfd, type: 2} m_TransparencySortMode: 0 m_TransparencySortAxis: {x: 0, y: 0, z: 1} m_DefaultRenderingPath: 1 @@ -60,8 +58,9 @@ GraphicsSettings: m_FogKeepExp2: 1 m_AlbedoSwatchInfos: [] m_RenderPipelineGlobalSettingsMap: - UnityEngine.Rendering.Universal.UniversalRenderPipeline: {fileID: 11400000, guid: 18dc0cd2c080841dea60987a38ce93fa, - type: 2} + UnityEngine.Rendering.Universal.UniversalRenderPipeline: {fileID: 11400000, guid: 18dc0cd2c080841dea60987a38ce93fa, type: 2} + m_ShaderBuildSettings: + keywordDeclarationOverrides: [] m_LightsUseLinearIntensity: 1 m_LightsUseColorTemperature: 1 m_LogWhenShaderIsCompiled: 0 diff --git a/TestProject/ProjectSettings/ProjectSettings.asset b/TestProject/ProjectSettings/ProjectSettings.asset index b87df8c..ccc4e47 100644 --- a/TestProject/ProjectSettings/ProjectSettings.asset +++ b/TestProject/ProjectSettings/ProjectSettings.asset @@ -70,6 +70,7 @@ PlayerSettings: androidStartInFullscreen: 1 androidRenderOutsideSafeArea: 1 androidUseSwappy: 0 + androidDisplayOptions: 1 androidBlitType: 0 androidResizeableActivity: 1 androidDefaultWindowWidth: 1920 @@ -175,10 +176,11 @@ PlayerSettings: tvOS: 0 overrideDefaultApplicationIdentifier: 1 AndroidBundleVersionCode: 1 - AndroidMinSdkVersion: 23 + AndroidMinSdkVersion: 25 AndroidTargetSdkVersion: 0 AndroidPreferredInstallLocation: 1 - aotOptions: + AndroidPreferredDataLocation: 1 + aotOptions: stripEngineCode: 1 iPhoneStrippingLevel: 0 iPhoneScriptCallOptimization: 0 @@ -192,11 +194,11 @@ PlayerSettings: VertexChannelCompressionMask: 4054 iPhoneSdkVersion: 988 iOSSimulatorArchitecture: 0 - iOSTargetOSVersionString: 13.0 + iOSTargetOSVersionString: 15.0 tvOSSdkVersion: 0 tvOSSimulatorArchitecture: 0 tvOSRequireExtendedGameController: 0 - tvOSTargetOSVersionString: 13.0 + tvOSTargetOSVersionString: 15.0 VisionOSSdkVersion: 0 VisionOSTargetOSVersionString: 1.0 uIPrerenderedIcon: 0 @@ -230,8 +232,8 @@ PlayerSettings: rgba: 0 iOSLaunchScreeniPadFillPct: 100 iOSLaunchScreeniPadSize: 100 - iOSLaunchScreenCustomStoryboardPath: - iOSLaunchScreeniPadCustomStoryboardPath: + iOSLaunchScreenCustomStoryboardPath: + iOSLaunchScreeniPadCustomStoryboardPath: iOSDeviceRequirements: [] iOSURLSchemes: [] macOSURLSchemes: [] @@ -242,10 +244,10 @@ PlayerSettings: metalCompileShaderBinary: 0 iOSRenderExtraFrameOnPause: 0 iosCopyPluginsCodeInsteadOfSymlink: 0 - appleDeveloperTeamID: - iOSManualSigningProvisioningProfileID: - tvOSManualSigningProvisioningProfileID: - VisionOSManualSigningProvisioningProfileID: + appleDeveloperTeamID: + iOSManualSigningProvisioningProfileID: + tvOSManualSigningProvisioningProfileID: + VisionOSManualSigningProvisioningProfileID: iOSManualSigningProvisioningProfileType: 0 tvOSManualSigningProvisioningProfileType: 0 VisionOSManualSigningProvisioningProfileType: 0 @@ -266,10 +268,11 @@ PlayerSettings: useCustomGradleSettingsTemplate: 0 useCustomProguardFile: 0 AndroidTargetArchitectures: 2 + AndroidAllowedArchitectures: -1 AndroidSplashScreenScale: 0 androidSplashScreen: {fileID: 0} - AndroidKeystoreName: - AndroidKeyaliasName: + AndroidKeystoreName: + AndroidKeyaliasName: AndroidEnableArmv9SecurityFeatures: 0 AndroidEnableArm64MTE: 0 AndroidBuildApkPerCpuArchitecture: 0 @@ -277,7 +280,7 @@ PlayerSettings: AndroidIsGame: 1 androidAppCategory: 3 useAndroidAppCategory: 1 - androidAppCategoryOther: + androidAppCategoryOther: AndroidEnableTango: 0 androidEnableBanner: 1 androidUseLowAccuracyLocation: 0 @@ -398,129 +401,129 @@ PlayerSettings: m_Width: 432 m_Height: 432 m_Kind: 2 - m_SubKind: + m_SubKind: - m_Textures: [] m_Width: 324 m_Height: 324 m_Kind: 2 - m_SubKind: + m_SubKind: - m_Textures: [] m_Width: 216 m_Height: 216 m_Kind: 2 - m_SubKind: + m_SubKind: - m_Textures: [] m_Width: 162 m_Height: 162 m_Kind: 2 - m_SubKind: + m_SubKind: - m_Textures: [] m_Width: 108 m_Height: 108 m_Kind: 2 - m_SubKind: + m_SubKind: - m_Textures: [] m_Width: 81 m_Height: 81 m_Kind: 2 - m_SubKind: + m_SubKind: - m_Textures: [] m_Width: 192 m_Height: 192 m_Kind: 1 - m_SubKind: + m_SubKind: - m_Textures: [] m_Width: 144 m_Height: 144 m_Kind: 1 - m_SubKind: + m_SubKind: - m_Textures: [] m_Width: 96 m_Height: 96 m_Kind: 1 - m_SubKind: + m_SubKind: - m_Textures: [] m_Width: 72 m_Height: 72 m_Kind: 1 - m_SubKind: + m_SubKind: - m_Textures: [] m_Width: 48 m_Height: 48 m_Kind: 1 - m_SubKind: + m_SubKind: - m_Textures: [] m_Width: 36 m_Height: 36 m_Kind: 1 - m_SubKind: + m_SubKind: - m_Textures: [] m_Width: 192 m_Height: 192 m_Kind: 0 - m_SubKind: + m_SubKind: - m_Textures: [] m_Width: 144 m_Height: 144 m_Kind: 0 - m_SubKind: + m_SubKind: - m_Textures: [] m_Width: 96 m_Height: 96 m_Kind: 0 - m_SubKind: + m_SubKind: - m_Textures: [] m_Width: 72 m_Height: 72 m_Kind: 0 - m_SubKind: + m_SubKind: - m_Textures: [] m_Width: 48 m_Height: 48 m_Kind: 0 - m_SubKind: + m_SubKind: - m_Textures: [] m_Width: 36 m_Height: 36 m_Kind: 0 - m_SubKind: + m_SubKind: - m_BuildTarget: tvOS m_Icons: - m_Textures: [] m_Width: 1280 m_Height: 768 m_Kind: 0 - m_SubKind: + m_SubKind: - m_Textures: [] m_Width: 800 m_Height: 480 m_Kind: 0 - m_SubKind: + m_SubKind: - m_Textures: [] m_Width: 400 m_Height: 240 m_Kind: 0 - m_SubKind: + m_SubKind: - m_Textures: [] m_Width: 4640 m_Height: 1440 m_Kind: 1 - m_SubKind: + m_SubKind: - m_Textures: [] m_Width: 2320 m_Height: 720 m_Kind: 1 - m_SubKind: + m_SubKind: - m_Textures: [] m_Width: 3840 m_Height: 1440 m_Kind: 1 - m_SubKind: + m_SubKind: - m_Textures: [] m_Width: 1920 m_Height: 720 m_Kind: 1 - m_SubKind: + m_SubKind: m_BuildTargetBatching: [] m_BuildTargetShaderSettings: [] m_BuildTargetGraphicsJobs: [] @@ -564,13 +567,13 @@ PlayerSettings: enableInternalProfiler: 0 logObjCUncaughtExceptions: 1 enableCrashReportAPI: 0 - cameraUsageDescription: - locationUsageDescription: - microphoneUsageDescription: - bluetoothUsageDescription: - macOSTargetOSVersion: 11.0 - switchNMETAOverride: - switchNetLibKey: + cameraUsageDescription: + locationUsageDescription: + microphoneUsageDescription: + bluetoothUsageDescription: + macOSTargetOSVersion: 12.0 + switchNMETAOverride: + switchNetLibKey: switchSocketMemoryPoolSize: 6144 switchSocketAllocatorPoolSize: 128 switchSocketConcurrencyLimit: 14 @@ -579,40 +582,40 @@ PlayerSettings: switchEnableFileSystemTrace: 0 switchLTOSetting: 0 switchApplicationID: 0x01004b9000490000 - switchNSODependencies: - switchCompilerFlags: - switchTitleNames_0: - switchTitleNames_1: - switchTitleNames_2: - switchTitleNames_3: - switchTitleNames_4: - switchTitleNames_5: - switchTitleNames_6: - switchTitleNames_7: - switchTitleNames_8: - switchTitleNames_9: - switchTitleNames_10: - switchTitleNames_11: - switchTitleNames_12: - switchTitleNames_13: - switchTitleNames_14: - switchTitleNames_15: - switchPublisherNames_0: - switchPublisherNames_1: - switchPublisherNames_2: - switchPublisherNames_3: - switchPublisherNames_4: - switchPublisherNames_5: - switchPublisherNames_6: - switchPublisherNames_7: - switchPublisherNames_8: - switchPublisherNames_9: - switchPublisherNames_10: - switchPublisherNames_11: - switchPublisherNames_12: - switchPublisherNames_13: - switchPublisherNames_14: - switchPublisherNames_15: + switchNSODependencies: + switchCompilerFlags: + switchTitleNames_0: + switchTitleNames_1: + switchTitleNames_2: + switchTitleNames_3: + switchTitleNames_4: + switchTitleNames_5: + switchTitleNames_6: + switchTitleNames_7: + switchTitleNames_8: + switchTitleNames_9: + switchTitleNames_10: + switchTitleNames_11: + switchTitleNames_12: + switchTitleNames_13: + switchTitleNames_14: + switchTitleNames_15: + switchPublisherNames_0: + switchPublisherNames_1: + switchPublisherNames_2: + switchPublisherNames_3: + switchPublisherNames_4: + switchPublisherNames_5: + switchPublisherNames_6: + switchPublisherNames_7: + switchPublisherNames_8: + switchPublisherNames_9: + switchPublisherNames_10: + switchPublisherNames_11: + switchPublisherNames_12: + switchPublisherNames_13: + switchPublisherNames_14: + switchPublisherNames_15: switchIcons_0: {fileID: 0} switchIcons_1: {fileID: 0} switchIcons_2: {fileID: 0} @@ -645,18 +648,18 @@ PlayerSettings: switchSmallIcons_13: {fileID: 0} switchSmallIcons_14: {fileID: 0} switchSmallIcons_15: {fileID: 0} - switchManualHTML: - switchAccessibleURLs: - switchLegalInformation: + switchManualHTML: + switchAccessibleURLs: + switchLegalInformation: switchMainThreadStackSize: 1048576 - switchPresenceGroupId: + switchPresenceGroupId: switchLogoHandling: 0 switchReleaseVersion: 0 switchDisplayVersion: 1.0.0 switchStartupUserAccount: 0 switchSupportedLanguagesMask: 0 switchLogoType: 0 - switchApplicationErrorCodeCategory: + switchApplicationErrorCodeCategory: switchUserAccountSaveDataSize: 0 switchUserAccountSaveDataJournalSize: 0 switchApplicationAttribute: 0 @@ -676,14 +679,14 @@ PlayerSettings: switchRatingsInt_10: 0 switchRatingsInt_11: 0 switchRatingsInt_12: 0 - switchLocalCommunicationIds_0: - switchLocalCommunicationIds_1: - switchLocalCommunicationIds_2: - switchLocalCommunicationIds_3: - switchLocalCommunicationIds_4: - switchLocalCommunicationIds_5: - switchLocalCommunicationIds_6: - switchLocalCommunicationIds_7: + switchLocalCommunicationIds_0: + switchLocalCommunicationIds_1: + switchLocalCommunicationIds_2: + switchLocalCommunicationIds_3: + switchLocalCommunicationIds_4: + switchLocalCommunicationIds_5: + switchLocalCommunicationIds_6: + switchLocalCommunicationIds_7: switchParentalControl: 0 switchAllowsScreenshot: 1 switchAllowsVideoCapturing: 1 @@ -715,35 +718,35 @@ PlayerSettings: switchRamDiskSpaceSize: 12 switchUpgradedPlayerSettingsToNMETA: 0 ps4NPAgeRating: 12 - ps4NPTitleSecret: - ps4NPTrophyPackPath: + ps4NPTitleSecret: + ps4NPTrophyPackPath: ps4ParentalLevel: 11 ps4ContentID: ED1633-NPXX51362_00-0000000000000000 ps4Category: 0 ps4MasterVersion: 01.00 ps4AppVersion: 01.00 ps4AppType: 0 - ps4ParamSfxPath: + ps4ParamSfxPath: ps4VideoOutPixelFormat: 0 ps4VideoOutInitialWidth: 1920 ps4VideoOutBaseModeInitialWidth: 1920 ps4VideoOutReprojectionRate: 60 - ps4PronunciationXMLPath: - ps4PronunciationSIGPath: - ps4BackgroundImagePath: - ps4StartupImagePath: - ps4StartupImagesFolder: - ps4IconImagesFolder: - ps4SaveDataImagePath: - ps4SdkOverride: - ps4BGMPath: - ps4ShareFilePath: - ps4ShareOverlayImagePath: - ps4PrivacyGuardImagePath: - ps4ExtraSceSysFile: - ps4NPtitleDatPath: + ps4PronunciationXMLPath: + ps4PronunciationSIGPath: + ps4BackgroundImagePath: + ps4StartupImagePath: + ps4StartupImagesFolder: + ps4IconImagesFolder: + ps4SaveDataImagePath: + ps4SdkOverride: + ps4BGMPath: + ps4ShareFilePath: + ps4ShareOverlayImagePath: + ps4PrivacyGuardImagePath: + ps4ExtraSceSysFile: + ps4NPtitleDatPath: ps4RemotePlayKeyAssignment: -1 - ps4RemotePlayKeyMappingDir: + ps4RemotePlayKeyMappingDir: ps4PlayTogetherPlayerCount: 0 ps4EnterButtonAssignment: 2 ps4ApplicationParam1: 0 @@ -771,9 +774,9 @@ PlayerSettings: ps4ScriptOptimizationLevel: 2 ps4Audio3dVirtualSpeakerCount: 14 ps4attribCpuUsage: 0 - ps4PatchPkgPath: - ps4PatchLatestPkgPath: - ps4PatchChangeinfoPath: + ps4PatchPkgPath: + ps4PatchLatestPkgPath: + ps4PatchChangeinfoPath: ps4PatchDayOne: 0 ps4attribUserManagement: 0 ps4attribMoveSupport: 0 @@ -789,19 +792,19 @@ PlayerSettings: ps4attribEyeToEyeDistanceSettingVR: 0 ps4IncludedModules: [] ps4attribVROutputEnabled: 0 - monoEnv: + monoEnv: splashScreenBackgroundSourceLandscape: {fileID: 0} splashScreenBackgroundSourcePortrait: {fileID: 0} blurSplashScreenBackground: 1 - spritePackerPolicy: + spritePackerPolicy: webGLMemorySize: 32 webGLExceptionSupport: 1 webGLNameFilesAsHashes: 0 webGLShowDiagnostics: 0 webGLDataCaching: 1 webGLDebugSymbols: 0 - webGLEmscriptenArgs: - webGLModulesDirectory: + webGLEmscriptenArgs: + webGLModulesDirectory: webGLTemplate: APPLICATION:Default webGLAnalyzeBuildSize: 0 webGLUseEmbeddedResources: 0 @@ -835,7 +838,7 @@ PlayerSettings: suppressCommonWarnings: 1 allowUnsafeCode: 0 useDeterministicCompilation: 1 - additionalIl2CppArgs: + additionalIl2CppArgs: scriptingRuntimeVersion: 1 gcIncremental: 1 gcWBarrierValidation: 0 @@ -844,15 +847,15 @@ PlayerSettings: m_RenderingPath: 1 m_MobileRenderingPath: 1 metroPackageName: Test - metroPackageVersion: - metroCertificatePath: - metroCertificatePassword: - metroCertificateSubject: - metroCertificateIssuer: + metroPackageVersion: + metroCertificatePath: + metroCertificatePassword: + metroCertificateSubject: + metroCertificateIssuer: metroCertificateNotAfter: 0000000000000000 metroApplicationDescription: Test wsaImages: {} - metroTileShortName: + metroTileShortName: metroTileShowName: 0 metroMediumTileShowName: 0 metroLargeTileShowName: 0 @@ -867,23 +870,23 @@ PlayerSettings: syncCapabilities: 0 platformCapabilities: {} metroTargetDeviceFamilies: {} - metroFTAName: + metroFTAName: metroFTAFileTypes: [] - metroProtocolName: - vcxProjDefaultLanguage: - XboxOneProductId: - XboxOneUpdateKey: - XboxOneSandboxId: - XboxOneContentId: - XboxOneTitleId: - XboxOneSCId: - XboxOneGameOsOverridePath: - XboxOnePackagingOverridePath: - XboxOneAppManifestOverridePath: + metroProtocolName: + vcxProjDefaultLanguage: + XboxOneProductId: + XboxOneUpdateKey: + XboxOneSandboxId: + XboxOneContentId: + XboxOneTitleId: + XboxOneSCId: + XboxOneGameOsOverridePath: + XboxOnePackagingOverridePath: + XboxOneAppManifestOverridePath: XboxOneVersion: 1.0.0.0 XboxOnePackageEncryption: 0 XboxOnePackageUpdateGranularity: 2 - XboxOneDescription: + XboxOneDescription: XboxOneLanguage: - enus XboxOneCapability: [] @@ -896,36 +899,36 @@ PlayerSettings: XboxOneAllowedProductIds: [] XboxOnePersistentLocalStorageSize: 0 XboxOneXTitleMemory: 8 - XboxOneOverrideIdentityName: - XboxOneOverrideIdentityPublisher: + XboxOneOverrideIdentityName: + XboxOneOverrideIdentityPublisher: vrEditorSettings: {} cloudServicesEnabled: {} luminIcon: - m_Name: - m_ModelFolderPath: - m_PortalFolderPath: + m_Name: + m_ModelFolderPath: + m_PortalFolderPath: luminCert: - m_CertPath: + m_CertPath: m_SignPackage: 1 luminIsChannelApp: 0 luminVersion: m_VersionCode: 1 - m_VersionName: - hmiPlayerDataPath: + m_VersionName: + hmiPlayerDataPath: hmiForceSRGBBlit: 1 embeddedLinuxEnableGamepadInput: 0 - hmiCpuConfiguration: + hmiCpuConfiguration: hmiLogStartupTiming: 0 - qnxGraphicConfPath: + qnxGraphicConfPath: apiCompatibilityLevel: 6 captureStartupLogs: {} activeInputHandler: 1 windowsGamepadBackendHint: 0 - cloudProjectId: + cloudProjectId: framebufferDepthMemorylessMode: 0 qualitySettingsNames: [] - projectName: - organizationId: + projectName: + organizationId: cloudEnabled: 0 legacyClampBlendShapeWeights: 0 hmiLoadingImage: {fileID: 0} @@ -935,3 +938,5 @@ PlayerSettings: androidVulkanDenyFilterList: [] androidVulkanAllowFilterList: [] androidVulkanDeviceFilterListAsset: {fileID: 0} + d3d12DeviceFilterListAsset: {fileID: 0} + allowedHttpConnections: 3 diff --git a/TestProject/ProjectSettings/ShaderGraphSettings.asset b/TestProject/ProjectSettings/ShaderGraphSettings.asset index 386cc22..ce8c243 100644 --- a/TestProject/ProjectSettings/ShaderGraphSettings.asset +++ b/TestProject/ProjectSettings/ShaderGraphSettings.asset @@ -10,8 +10,8 @@ MonoBehaviour: m_Enabled: 1 m_EditorHideFlags: 0 m_Script: {fileID: 11500000, guid: de02f9e1d18f588468e474319d09a723, type: 3} - m_Name: - m_EditorClassIdentifier: + m_Name: + m_EditorClassIdentifier: shaderVariantLimit: 128 overrideShaderVariantLimit: 0 customInterpolatorErrorThreshold: 32 diff --git a/UnityBridge/Editor/Helpers/BridgeStatusFile.cs b/UnityBridge/Editor/Helpers/BridgeStatusFile.cs index 0751776..2428598 100644 --- a/UnityBridge/Editor/Helpers/BridgeStatusFile.cs +++ b/UnityBridge/Editor/Helpers/BridgeStatusFile.cs @@ -2,6 +2,7 @@ using System.IO; using System.Security.Cryptography; using System.Text; +using System.Threading; using Newtonsoft.Json; namespace UnityBridge.Helpers @@ -84,7 +85,7 @@ public static void WriteStatus( relay_host = relayHost, relay_port = relayPort, timestamp = DateTime.UtcNow.ToString("O"), - seq = ++_seq + seq = Interlocked.Increment(ref _seq) }; var json = JsonConvert.SerializeObject(payload); diff --git a/UnityBridge/Editor/RelayServerLauncher.cs b/UnityBridge/Editor/RelayServerLauncher.cs index b2ef618..5053aab 100644 --- a/UnityBridge/Editor/RelayServerLauncher.cs +++ b/UnityBridge/Editor/RelayServerLauncher.cs @@ -105,28 +105,101 @@ private void DetectPaths() #endif } + /// + /// Extract numeric version from Python directory name (e.g. "Python312" → 312). + /// Returns 0 for unparseable names so they sort last. + /// + private static int ExtractPythonVersion(string dirName) + { + // Strip "Python" prefix and parse remainder as integer + if (dirName.StartsWith("Python", StringComparison.OrdinalIgnoreCase) + && int.TryParse(dirName.Substring(6), out var version)) + { + return version; + } + return 0; + } + + private static string[] _cachedSearchPaths; + + /// + /// Platform-specific search paths for common binary locations. + /// Results are cached after the first call. + /// + private static string[] GetPlatformSearchPaths() + { + if (_cachedSearchPaths != null) + return _cachedSearchPaths; + + var homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + + if (Application.platform == RuntimePlatform.WindowsEditor) + { + var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); + var appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); + + var pythonPaths = new System.Collections.Generic.List(); + + // Discover installed Python versions dynamically + try + { + var pythonBase = Path.Combine(localAppData, "Programs", "Python"); + if (Directory.Exists(pythonBase)) + { + var dirs = Directory.GetDirectories(pythonBase, "Python*"); + // Sort by extracted version number (descending) to prefer newest + System.Array.Sort(dirs, (a, b) => + { + var verA = ExtractPythonVersion(Path.GetFileName(a)); + var verB = ExtractPythonVersion(Path.GetFileName(b)); + return verB.CompareTo(verA); + }); + foreach (var dir in dirs) + { + var scripts = Path.Combine(dir, "Scripts"); + if (Directory.Exists(scripts)) + pythonPaths.Add(scripts); + } + } + } + catch (Exception ex) when (ex is IOException or UnauthorizedAccessException) + { + BridgeLog.Warn($"Error scanning Python directories: {ex.Message}"); + } + + var paths = new System.Collections.Generic.List(pythonPaths); + paths.Add(Path.Combine(appData, "Python", "Scripts")); + paths.Add(Path.Combine(homeDir, ".local", "bin")); + paths.Add(Path.Combine(homeDir, ".cargo", "bin")); + + _cachedSearchPaths = paths.ToArray(); + } + else + { + _cachedSearchPaths = new[] + { + "/opt/homebrew/bin", + "/usr/local/bin", + "/usr/bin", + "/bin", + Path.Combine(homeDir, ".local", "bin"), + Path.Combine(homeDir, ".cargo", "bin"), + }; + } + + return _cachedSearchPaths; + } + /// /// Build augmented PATH that includes common binary locations. /// Unity GUI app has limited PATH, so we need to add common paths explicitly. /// private static string BuildAugmentedPath() { - var homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); - var additionalPaths = new[] - { - "/opt/homebrew/bin", // Homebrew on Apple Silicon - "/usr/local/bin", // Homebrew on Intel / common binaries - "/usr/bin", - "/bin", - Path.Combine(homeDir, ".local", "bin"), // pip --user, uv - Path.Combine(homeDir, ".cargo", "bin") // Rust/cargo installs - }; - + var additionalPaths = GetPlatformSearchPaths(); var currentPath = Environment.GetEnvironmentVariable("PATH") ?? ""; - - return Application.platform == RuntimePlatform.WindowsEditor - ? string.Join(";", additionalPaths) + ";" + currentPath - : string.Join(":", additionalPaths) + ":" + currentPath; + var separator = Application.platform == RuntimePlatform.WindowsEditor ? ";" : ":"; + return string.Join(separator, additionalPaths) + separator + currentPath; } /// @@ -155,56 +228,117 @@ private static int GetProcessIdForPort(int port) { try { - var psi = new ProcessStartInfo - { - FileName = "/usr/sbin/lsof", - Arguments = $"-i :{port} -t", - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = true, - CreateNoWindow = true - }; +#if UNITY_EDITOR_WIN + return GetProcessIdForPortWindows(port); +#else + return GetProcessIdForPortUnix(port); +#endif + } + catch (Exception ex) + { + BridgeLog.Warn($"Error checking port {port}: {ex.Message}"); + return -1; + } + } + +#if UNITY_EDITOR_WIN + private static int GetProcessIdForPortWindows(int port) + { + var psi = new ProcessStartInfo + { + FileName = "netstat", + Arguments = "-ano", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true + }; - using var process = Process.Start(psi); - if (process == null) return -1; + using var process = Process.Start(psi); + if (process == null) return -1; - var output = process.StandardOutput.ReadToEnd().Trim(); - process.WaitForExit(5000); + var output = process.StandardOutput.ReadToEnd(); + if (!process.WaitForExit(5000)) + { + try { process.Kill(); } catch { /* best effort */ } + } - if (process.ExitCode == 0 && !string.IsNullOrEmpty(output)) + var portSuffix = $":{port}"; + foreach (var line in output.Split('\n')) + { + var trimmed = line.Trim(); + if (!trimmed.StartsWith("TCP", StringComparison.OrdinalIgnoreCase)) + continue; + if (!trimmed.Contains(portSuffix)) + continue; + + var parts = trimmed.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + // Format: TCP + if (parts.Length < 5) + continue; + + var colonIdx = parts[1].LastIndexOf(':'); + if (colonIdx < 0 || parts[1].Substring(colonIdx + 1) != port.ToString()) + continue; + + if (parts[^2].Equals("LISTENING", StringComparison.OrdinalIgnoreCase) + && int.TryParse(parts[^1], out var pid)) { - // lsof -t returns PID(s), take the first one - var firstLine = output.Split('\n')[0].Trim(); - if (int.TryParse(firstLine, out var pid)) - { - return pid; - } + return pid; } } - catch (Exception ex) + + return -1; + } +#else + private static int GetProcessIdForPortUnix(int port) + { + var psi = new ProcessStartInfo { - BridgeLog.Warn($"Error checking port {port}: {ex.Message}"); + FileName = "/usr/sbin/lsof", + Arguments = $"-i :{port} -t", + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + CreateNoWindow = true + }; + + using var process = Process.Start(psi); + if (process == null) return -1; + + var output = process.StandardOutput.ReadToEnd().Trim(); + if (!process.WaitForExit(5000)) + { + try { process.Kill(); } catch { /* best effort */ } + } + + if (process.ExitCode == 0 && !string.IsNullOrEmpty(output)) + { + var firstLine = output.Split('\n')[0].Trim(); + if (int.TryParse(firstLine, out var pid)) + { + return pid; + } } return -1; } +#endif private static void KillProcess(int pid) { try { - var psi = new ProcessStartInfo + using var process = Process.GetProcessById(pid); + if (!process.HasExited) { - FileName = "/bin/kill", - Arguments = $"-9 {pid}", - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = true, - CreateNoWindow = true - }; - - using var process = Process.Start(psi); - process?.WaitForExit(3000); + process.Kill(); + process.WaitForExit(3000); + } + } + catch (ArgumentException) + { + // Process already exited } catch (Exception ex) { @@ -214,17 +348,8 @@ private static void KillProcess(int pid) private static string FindExecutable(string name) { - // First check augmented paths directly - var homeDir = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); - var searchPaths = new[] - { - "/opt/homebrew/bin", - "/usr/local/bin", - "/usr/bin", - "/bin", - Path.Combine(homeDir, ".local", "bin"), - Path.Combine(homeDir, ".cargo", "bin") - }; + // First check platform-specific search paths + var searchPaths = GetPlatformSearchPaths(); foreach (var basePath in searchPaths) { diff --git a/UnityBridge/Editor/Tools/Scene.cs b/UnityBridge/Editor/Tools/Scene.cs index d30cf78..4832c1e 100644 --- a/UnityBridge/Editor/Tools/Scene.cs +++ b/UnityBridge/Editor/Tools/Scene.cs @@ -208,6 +208,13 @@ private static JObject SaveScene(JObject parameters) var path = parameters["path"]?.Value(); var scene = SceneManager.GetActiveScene(); + if (string.IsNullOrEmpty(path) && string.IsNullOrEmpty(scene.path)) + { + throw new ProtocolException( + ErrorCode.InvalidParams, + "Scene has no path. Specify '--path' to save to a new location."); + } + var saved = !string.IsNullOrEmpty(path) ? EditorSceneManager.SaveScene(scene, path) : EditorSceneManager.SaveScene(scene); diff --git a/UnityBridge/Editor/Tools/Tests.cs b/UnityBridge/Editor/Tools/Tests.cs index ddc4f10..d2d8d47 100644 --- a/UnityBridge/Editor/Tools/Tests.cs +++ b/UnityBridge/Editor/Tools/Tests.cs @@ -511,7 +511,8 @@ public void TestFinished(ITestResultAdaptor result) if (result.HasChildren) return; TestsFinished++; - switch (result.ResultState) + var resultStatus = result.ResultState.Split(':')[0]; + switch (resultStatus) { case "Passed": Passed++; diff --git a/relay/server.py b/relay/server.py index 94ec4aa..d246bbf 100644 --- a/relay/server.py +++ b/relay/server.py @@ -12,6 +12,7 @@ import logging import os import signal +import sys from logging.handlers import RotatingFileHandler from pathlib import Path from typing import Any @@ -112,6 +113,8 @@ def __init__( self._relay_version = "" self._server: asyncio.Server | None = None self._running = False + self._stop_lock = asyncio.Lock() + self._stopped = False self._pending_commands: dict[str, asyncio.Future[dict[str, Any]]] = {} self._heartbeat_tasks: dict[str, asyncio.Task] = {} # Single Outstanding PING: track pending PONG per instance @@ -135,33 +138,52 @@ async def start(self) -> None: await self._server.serve_forever() async def stop(self) -> None: - """Stop the relay server""" - logger.info("Stopping Relay Server...") - self._running = False - - # Cancel all heartbeat tasks - for task in self._heartbeat_tasks.values(): - task.cancel() - self._heartbeat_tasks.clear() + """Stop the relay server (idempotent, concurrency-safe). - # Cancel pending commands - for future in self._pending_commands.values(): - if not future.done(): - future.cancel() - self._pending_commands.clear() + Uses ``_stop_lock`` to serialize concurrent calls (e.g. signal handler + and ``finally`` block). Each cleanup step is individually guarded so + that a partial failure does not prevent subsequent resources from being + released. + """ + async with self._stop_lock: + if self._stopped: + return + logger.info("Stopping Relay Server...") + self._running = False + + # Cancel all heartbeat tasks + for task in self._heartbeat_tasks.values(): + task.cancel() + self._heartbeat_tasks.clear() + + # Cancel pending commands + for future in self._pending_commands.values(): + if not future.done(): + future.cancel() + self._pending_commands.clear() - # Close all instances - await self.registry.close_all() + # Close all instances + try: + await self.registry.close_all() + except Exception: + logger.exception("Error closing instances") - # Stop cache cleanup - await self.request_cache.stop() + # Stop cache cleanup + try: + await self.request_cache.stop() + except Exception: + logger.exception("Error stopping request cache") - # Close server - if self._server: - self._server.close() - await self._server.wait_closed() + # Close server + if self._server: + try: + self._server.close() + await self._server.wait_closed() + except Exception: + logger.exception("Error closing server") - logger.info("Relay Server stopped") + self._stopped = True + logger.info("Relay Server stopped") async def _handle_connection( self, @@ -723,22 +745,39 @@ async def run_server( reload_grace_period_ms=reload_grace_period_ms, ) - loop = asyncio.get_event_loop() - - # Setup signal handlers - for sig in (signal.SIGINT, signal.SIGTERM): - loop.add_signal_handler(sig, lambda: asyncio.create_task(server.stop())) + if sys.platform != "win32": + loop = asyncio.get_running_loop() + for sig in (signal.SIGINT, signal.SIGTERM): + loop.add_signal_handler(sig, lambda: asyncio.create_task(server.stop())) try: await server.start() except asyncio.CancelledError: pass + finally: + await server.stop() def _resolve_log_dir() -> Path: - """Resolve log directory from XDG_STATE_HOME (evaluated at call time).""" - state_home = os.environ.get("XDG_STATE_HOME") or (Path.home() / ".local" / "state") - return Path(state_home) / "unity-cli" / "logs" + """Resolve log directory (evaluated at call time). + + Priority: + 1. XDG_STATE_HOME (explicit override, all platforms) + 2. Windows: %LOCALAPPDATA%/unity-cli/logs + 3. Unix: ~/.local/state/unity-cli/logs + """ + env_override = os.environ.get("XDG_STATE_HOME") + if env_override: + return Path(env_override) / "unity-cli" / "logs" + + if sys.platform == "win32": + local_app_data = os.environ.get("LOCALAPPDATA") + if not local_app_data: + local_app_data = str(Path.home() / "AppData" / "Local") + return Path(local_app_data) / "unity-cli" / "logs" + + state_home = Path.home() / ".local" / "state" + return state_home / "unity-cli" / "logs" def get_log_path() -> Path: diff --git a/tests/test_relay_logging.py b/tests/test_relay_logging.py index 183859f..b4ee328 100644 --- a/tests/test_relay_logging.py +++ b/tests/test_relay_logging.py @@ -3,6 +3,7 @@ from __future__ import annotations import logging +import sys from collections.abc import Generator from logging.handlers import RotatingFileHandler from pathlib import Path @@ -57,15 +58,31 @@ def test_debug_flag_overrides_env_var(self, monkeypatch: pytest.MonkeyPatch) -> class TestResolveLogDir: - def test_default_path(self, monkeypatch: pytest.MonkeyPatch) -> None: + @pytest.mark.skipif(sys.platform == "win32", reason="Unix-specific test") + def test_default_path_unix(self, monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.delenv("XDG_STATE_HOME", raising=False) log_dir = _resolve_log_dir() assert str(log_dir).endswith(".local/state/unity-cli/logs") - def test_xdg_state_home(self, monkeypatch: pytest.MonkeyPatch) -> None: - monkeypatch.setenv("XDG_STATE_HOME", "/tmp/test-xdg-state") + @pytest.mark.skipif(sys.platform != "win32", reason="Windows-specific test") + def test_default_path_windows_with_localappdata(self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None: + monkeypatch.delenv("XDG_STATE_HOME", raising=False) + monkeypatch.setenv("LOCALAPPDATA", str(tmp_path)) + log_dir = _resolve_log_dir() + assert log_dir == tmp_path / "unity-cli" / "logs" + + @pytest.mark.skipif(sys.platform != "win32", reason="Windows-specific test") + def test_default_path_windows_without_localappdata(self, monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.delenv("XDG_STATE_HOME", raising=False) + monkeypatch.delenv("LOCALAPPDATA", raising=False) + log_dir = _resolve_log_dir() + assert str(log_dir).endswith(str(Path("AppData", "Local", "unity-cli", "logs"))) + + def test_xdg_state_home(self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None: + test_state = tmp_path / "xdg-state" + monkeypatch.setenv("XDG_STATE_HOME", str(test_state)) log_dir = _resolve_log_dir() - assert log_dir == Path("/tmp/test-xdg-state/unity-cli/logs") + assert log_dir == test_state / "unity-cli" / "logs" class TestGetLogPath: @@ -74,9 +91,10 @@ def test_returns_relay_log(self) -> None: assert path.name == "relay.log" assert "unity-cli" in str(path) - def test_respects_xdg(self, monkeypatch: pytest.MonkeyPatch) -> None: - monkeypatch.setenv("XDG_STATE_HOME", "/tmp/test-xdg") - assert get_log_path() == Path("/tmp/test-xdg/unity-cli/logs/relay.log") + def test_respects_xdg(self, monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None: + test_state = tmp_path / "xdg" + monkeypatch.setenv("XDG_STATE_HOME", str(test_state)) + assert get_log_path() == test_state / "unity-cli" / "logs" / "relay.log" class TestSetupLogging: @@ -107,8 +125,10 @@ def test_creates_log_dir_and_handlers(self, tmp_path: Path, monkeypatch: pytest. assert root.level == logging.DEBUG def test_falls_back_to_stderr_on_permission_error(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: - # Point to a path that cannot be created - monkeypatch.setenv("XDG_STATE_HOME", "/proc/nonexistent") + # Use a file as a directory to trigger OSError (cross-platform) + blocker = tmp_path / "blocker" + blocker.write_text("block") + monkeypatch.setenv("XDG_STATE_HOME", str(blocker / "nested")) _setup_logging(logging.INFO) root = logging.getLogger() diff --git a/unity_cli/cli/commands/completion.py b/unity_cli/cli/commands/completion.py index cf81152..6ebec15 100644 --- a/unity_cli/cli/commands/completion.py +++ b/unity_cli/cli/commands/completion.py @@ -29,6 +29,24 @@ "fish": """complete -c u -f -a "(env _TYPER_COMPLETE_ARGS=(commandline -cp) _U_COMPLETE=complete_fish u)" complete -c unity -f -a "(env _TYPER_COMPLETE_ARGS=(commandline -cp) _U_COMPLETE=complete_fish unity)" complete -c unity-cli -f -a "(env _TYPER_COMPLETE_ARGS=(commandline -cp) _U_COMPLETE=complete_fish unity-cli)" +""", + "powershell": """Register-ArgumentCompleter -Native -CommandName u,unity,'unity-cli' -ScriptBlock { + param($wordToComplete, $commandAst, $cursorPosition) + $cmd = $commandAst.CommandElements[0].Value + $env:_TYPER_COMPLETE_ARGS = $commandAst.ToString() + $env:_U_COMPLETE = "complete_powershell" + try { + & $cmd | ForEach-Object { + $parts = $_ -split ':::', 2 + $text = $parts[0] + $desc = if ($parts.Count -ge 2) { $parts[1] } else { $text } + [System.Management.Automation.CompletionResult]::new($text, $text, 'ParameterValue', $desc) + } + } finally { + Remove-Item Env:_TYPER_COMPLETE_ARGS -ErrorAction SilentlyContinue + Remove-Item Env:_U_COMPLETE -ErrorAction SilentlyContinue + } +} """, } @@ -38,7 +56,7 @@ def register(app: typer.Typer) -> None: def completion( shell: Annotated[ str | None, - typer.Option("--shell", "-s", help="Shell type: zsh, bash, fish"), + typer.Option("--shell", "-s", help="Shell type: zsh, bash, fish, powershell"), ] = None, ) -> None: """Generate shell completion script. @@ -47,8 +65,10 @@ def completion( u completion -s zsh > ~/.zsh/completions/_unity-cli u completion -s bash >> ~/.bashrc u completion -s fish > ~/.config/fish/completions/unity-cli.fish + u completion -s powershell >> $PROFILE """ import os + import sys # Auto-detect shell if not specified if shell is None: @@ -59,13 +79,13 @@ def completion( shell = "bash" elif "fish" in shell_env: shell = "fish" + elif os.environ.get("PSModulePath") or sys.platform == "win32": # noqa: SIM112 + shell = "powershell" else: - shell = "zsh" # Default to zsh + shell = "zsh" shell = shell.lower() if shell not in _COMPLETION_SCRIPTS: - import sys - if is_no_color(): print(f"Unsupported shell: {shell}", file=sys.stderr) print(f"Supported shells: {', '.join(_COMPLETION_SCRIPTS.keys())}", file=sys.stderr) diff --git a/unity_cli/hub/paths.py b/unity_cli/hub/paths.py index 3ab9ad4..a4d071a 100644 --- a/unity_cli/hub/paths.py +++ b/unity_cli/hub/paths.py @@ -35,11 +35,14 @@ def _get_platform_hub_candidates() -> list[Path]: ] elif sys.platform == "win32": localappdata = os.environ.get("LOCALAPPDATA", "") + programfiles_x86 = os.environ.get("ProgramFiles(x86)", "") # noqa: SIM112 candidates = [ Path(r"C:\Program Files\Unity Hub\Unity Hub.exe"), ] + if programfiles_x86: + candidates.append(Path(programfiles_x86) / "Unity Hub" / "Unity Hub.exe") if localappdata: - candidates.append(Path(localappdata) / "Programs/Unity Hub/Unity Hub.exe") + candidates.append(Path(localappdata) / "Programs" / "Unity Hub" / "Unity Hub.exe") return candidates else: # Linux return [