From 5043781ebf9b25542c4b635b547ca0c7b61dd207 Mon Sep 17 00:00:00 2001 From: mkc1370 Date: Thu, 3 Nov 2022 20:20:46 +0900 Subject: [PATCH] Added support for paths within editable Packages to UnityPath --- .../UniGLTF/Runtime/UniGLTF/IO/UnityPath.cs | 154 +++++++++++++----- Assets/UniGLTF/Tests/UniGLTF/UniGLTFTests.cs | 36 +++- .../Editor/Format/vrmAssetPostprocessor.cs | 6 +- .../VrmMeshIntegratorWizard.cs | 4 +- Assets/VRM10/Editor/Vrm10ExportDialog.cs | 2 +- Assets/VRM10/Editor/Vrm10InstanceEditor.cs | 4 +- 6 files changed, 152 insertions(+), 54 deletions(-) diff --git a/Assets/UniGLTF/Runtime/UniGLTF/IO/UnityPath.cs b/Assets/UniGLTF/Runtime/UniGLTF/IO/UnityPath.cs index 5e3d312c6..c7cffbb75 100644 --- a/Assets/UniGLTF/Runtime/UniGLTF/IO/UnityPath.cs +++ b/Assets/UniGLTF/Runtime/UniGLTF/IO/UnityPath.cs @@ -2,20 +2,27 @@ using System; using System.IO; using UnityEngine; using System.Collections.Generic; +using System.Linq; #if UNITY_EDITOR using UnityEditor; +using UnityEditor.PackageManager; +using PackageInfo = UnityEditor.PackageManager.PackageInfo; #endif namespace UniGLTF { /// - /// relative path from Unity project root. - /// For AssetDatabase. + /// Manage paths that can be handled by AssetDatabase + /// Supports Assets or editable Package + /// + /// note : Use '\' instead of '/' to delimit folders /// public struct UnityPath { +#if UNITY_EDITOR #region UnityPath + public string Value { get; @@ -32,18 +39,66 @@ namespace UniGLTF get { return Value == null; } } - public bool IsUnderAssetsFolder + /// + /// If under Assets or under an editable Package return true + /// + public bool IsUnderWritableFolder { get { - if (IsNull) + if (IsNull) return false; + + if (PathType == PathType.Assets) return true; + + if (PathType == PathType.Packages) { - return false; + var split = Value.Split('/'); + if (split.Length <= 1) return false; + + var packageDirectory = $"{split[0]}/{split[1]}"; + if (!Directory.Exists(packageDirectory)) return false; + + var packageInfo = GetPackageInfo(packageDirectory); + if (packageInfo == null) return false; + + // Local and Embedded packages are editable + if (packageInfo.source == PackageSource.Local + || packageInfo.source == PackageSource.Embedded) return true; } - return Value == "Assets" || Value.FastStartsWith("Assets/"); + + return false; } } + /// + /// Recursively check if path is included in local packages + /// + /// + /// + private static PackageInfo GetPackageInfo(string path) + { + if (string.IsNullOrWhiteSpace(path)) return null; + + var packageInfo = PackageList.Find(x => x.resolvedPath == path || x.assetPath == path); + if (packageInfo != null) + { + return packageInfo; + } + + return GetPackageInfo(Path.GetDirectoryName(path)); + } + + /// + /// List of packages loaded in unity + /// + private static readonly List PackageList + = AssetDatabase.FindAssets("package") + .Select(AssetDatabase.GUIDToAssetPath) + .Where(x => AssetDatabase.LoadAssetAtPath(x) != null) + .Select(PackageInfo.FindForAssetPath) + .Where(x => x != null) + .ToList(); + public bool IsStreamingAsset { get @@ -92,6 +147,29 @@ namespace UniGLTF return !string.IsNullOrEmpty(Value); } } + + public PathType PathType + { + get + { + if (string.IsNullOrEmpty(Value)) return PathType.Unsuported; + + var directory = Path.GetDirectoryName(Value); + if (string.IsNullOrEmpty(directory)) return PathType.Unsuported; + + var rootDirectoryName = directory.Split(Path.DirectorySeparatorChar); + + switch (rootDirectoryName[0]) + { + case "Assets": + return PathType.Assets; + case "Packages": + return PathType.Packages; + default: + return PathType.Unsuported; + } + } + } static readonly char[] EscapeChars = new char[] { @@ -127,7 +205,7 @@ namespace UniGLTF } else { - return new UnityPath(Value + "/" + name); + return new UnityPath($"{Value}/{name}"); } } @@ -176,7 +254,7 @@ namespace UniGLTF /// public UnityPath GetAssetFolder(string suffix) { - if (!IsUnderAssetsFolder) + if (!IsUnderWritableFolder) { throw new NotImplementedException(); } @@ -201,14 +279,14 @@ namespace UniGLTF /// public static UnityPath FromUnityPath(string unityPath) { - if (String.IsNullOrEmpty(unityPath)) + if (String.IsNullOrEmpty(unityPath) || unityPath == ".") { return new UnityPath { Value = "" }; } - return FromFullpath(Path.GetFullPath(unityPath)); + return new UnityPath(unityPath); } #endregion @@ -226,14 +304,6 @@ namespace UniGLTF } } - static string AssetFullPath - { - get - { - return BaseFullPath + "/Assets"; - } - } - public string FullPath { get @@ -242,7 +312,7 @@ namespace UniGLTF { throw new NotImplementedException(); } - return Path.Combine(BaseFullPath, Value).Replace("\\", "/"); + return Path.GetFullPath(Value).Replace("\\", "/"); } } @@ -271,24 +341,24 @@ namespace UniGLTF if (fullPath == BaseFullPath) { - return new UnityPath - { - Value = "" - }; + return new UnityPath(""); } - else if (fullPath.FastStartsWith(BaseFullPath + "/")) + + if (fullPath.FastStartsWith($"{BaseFullPath}/Assets")) { return new UnityPath(fullPath.Substring(BaseFullPath.Length + 1)); } - else - { - return default(UnityPath); - } - } - public static bool IsUnderAssetFolder(string fullPath) - { - return fullPath.Replace("\\", "/").FastStartsWith(AssetFullPath); + var packageInfo = GetPackageInfo(fullPath); + if (packageInfo != null) + { + var packagePath = packageInfo.assetPath; + var fileName = fullPath.Substring(packageInfo.resolvedPath.Length + 1); + var relativePath = $"{packagePath}/{fileName}"; + return new UnityPath(relativePath); + } + + return default(UnityPath); } #endregion @@ -336,7 +406,6 @@ namespace UniGLTF } } -#if UNITY_EDITOR public T GetImporter() where T : AssetImporter { return AssetImporter.GetAtPath(Value) as T; @@ -354,7 +423,7 @@ namespace UniGLTF public void ImportAsset() { - if (!IsUnderAssetsFolder) + if (!IsUnderWritableFolder) { throw new NotImplementedException(); } @@ -389,7 +458,7 @@ namespace UniGLTF public UnityEngine.Object[] GetSubAssets() { - if (!IsUnderAssetsFolder) + if (!IsUnderWritableFolder) { throw new NotImplementedException(); } @@ -399,7 +468,7 @@ namespace UniGLTF public void CreateAsset(UnityEngine.Object o) { - if (!IsUnderAssetsFolder) + if (!IsUnderWritableFolder) { throw new NotImplementedException(); } @@ -421,7 +490,7 @@ namespace UniGLTF public void AddObjectToAsset(UnityEngine.Object o) { - if (!IsUnderAssetsFolder) + if (!IsUnderWritableFolder) { throw new NotImplementedException(); } @@ -431,7 +500,7 @@ namespace UniGLTF public T LoadAsset() where T : UnityEngine.Object { - if (!IsUnderAssetsFolder) + if (!IsUnderWritableFolder) { throw new NotImplementedException(); } @@ -441,7 +510,7 @@ namespace UniGLTF public UnityPath GenerateUniqueAssetPath() { - if (!IsUnderAssetsFolder) + if (!IsUnderWritableFolder) { throw new NotImplementedException(); } @@ -450,4 +519,11 @@ namespace UniGLTF } #endif } + + public enum PathType + { + Assets, + Packages, + Unsuported, + } } diff --git a/Assets/UniGLTF/Tests/UniGLTF/UniGLTFTests.cs b/Assets/UniGLTF/Tests/UniGLTF/UniGLTFTests.cs index 3bbc9856f..c424eb7f7 100644 --- a/Assets/UniGLTF/Tests/UniGLTF/UniGLTFTests.cs +++ b/Assets/UniGLTF/Tests/UniGLTF/UniGLTFTests.cs @@ -163,19 +163,41 @@ namespace UniGLTF { var root = UnityPath.FromUnityPath("."); Assert.IsFalse(root.IsNull); - Assert.IsFalse(root.IsUnderAssetsFolder); + Assert.IsFalse(root.IsUnderWritableFolder); Assert.AreEqual(UnityPath.FromUnityPath("."), root); var assets = UnityPath.FromUnityPath("Assets"); Assert.IsFalse(assets.IsNull); - Assert.IsTrue(assets.IsUnderAssetsFolder); + Assert.IsFalse(assets.IsUnderWritableFolder); - var rootChild = root.Child("Assets"); - Assert.AreEqual(assets, rootChild); + var rootChildAssets = root.Child("Assets"); + Assert.AreEqual(assets, rootChildAssets); - var assetsChild = assets.Child("Hoge"); - var hoge = UnityPath.FromUnityPath("Assets/Hoge"); - Assert.AreEqual(assetsChild, hoge); + var assetsChildHoge = assets.Child("Hoge"); + var assetsHoge = UnityPath.FromUnityPath("Assets/Hoge"); + Assert.IsTrue(assetsChildHoge.IsUnderWritableFolder); + Assert.IsTrue(assetsHoge.IsUnderWritableFolder); + Assert.AreEqual(assetsChildHoge, assetsHoge); + + + var packages = UnityPath.FromUnityPath("Packages"); + Assert.IsFalse(packages.IsNull); + Assert.IsFalse(packages.IsUnderWritableFolder); + + var rootChildPackages = root.Child("Packages"); + Assert.AreEqual(packages, rootChildPackages); + + var packagesChildNUnit = packages.Child("com.unity.ext.nunit"); + var packagesNUnit = UnityPath.FromUnityPath("Packages/com.unity.ext.nunit"); + Assert.IsFalse(packages.IsUnderWritableFolder); + Assert.IsFalse(packagesNUnit.IsUnderWritableFolder); + Assert.AreEqual(packagesChildNUnit, packagesNUnit); + + var packagesChildHoge = packages.Child("Hoge"); + var packagesHoge = UnityPath.FromUnityPath("Packages/Hoge"); + Assert.IsFalse(packagesChildHoge.IsUnderWritableFolder); + Assert.IsFalse(packagesHoge.IsUnderWritableFolder); + Assert.AreEqual(packagesChildHoge, packagesHoge); //var children = root.TraverseDir().ToArray(); } diff --git a/Assets/VRM/Editor/Format/vrmAssetPostprocessor.cs b/Assets/VRM/Editor/Format/vrmAssetPostprocessor.cs index e099b5416..8c99c71e9 100644 --- a/Assets/VRM/Editor/Format/vrmAssetPostprocessor.cs +++ b/Assets/VRM/Editor/Format/vrmAssetPostprocessor.cs @@ -41,7 +41,7 @@ namespace VRM static void ImportVrm(UnityPath vrmPath) { - if (!vrmPath.IsUnderAssetsFolder) + if (!vrmPath.IsUnderWritableFolder) { throw new Exception(); } @@ -53,9 +53,9 @@ namespace VRM public static void ImportVrmAndCreatePrefab(string vrmPath, UnityPath prefabPath) { - if (!prefabPath.IsUnderAssetsFolder) + if (!prefabPath.IsUnderWritableFolder) { - Debug.LogWarningFormat("out of asset path: {0}", prefabPath); + Debug.LogWarningFormat("out of Asset or writable Packages folder: {0}", prefabPath); return; } diff --git a/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs b/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs index 5d39f105c..1d43b2103 100644 --- a/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs +++ b/Assets/VRM/Editor/SkinnedMeshUtility/VrmMeshIntegratorWizard.cs @@ -263,9 +263,9 @@ namespace VRM // 新規で作成されるアセットはすべてこのフォルダの中に作る。上書きチェックはしない var assetFolder = EditorUtility.SaveFolderPanel("select asset save folder", Path.GetDirectoryName(folder), "VrmIntegrated"); var unityPath = UniGLTF.UnityPath.FromFullpath(assetFolder); - if (!unityPath.IsUnderAssetsFolder) + if (!unityPath.IsUnderWritableFolder) { - EditorUtility.DisplayDialog("asset folder", "Target folder must be in the `Assets` folder", "cancel"); + EditorUtility.DisplayDialog("asset folder", "Target folder must be in the Assets or writable Packages folder", "cancel"); return; } assetFolder = unityPath.Value; diff --git a/Assets/VRM10/Editor/Vrm10ExportDialog.cs b/Assets/VRM10/Editor/Vrm10ExportDialog.cs index 2650292df..957877c1f 100644 --- a/Assets/VRM10/Editor/Vrm10ExportDialog.cs +++ b/Assets/VRM10/Editor/Vrm10ExportDialog.cs @@ -288,7 +288,7 @@ namespace UniVRM10 Debug.Log("exportedBytes: " + exportedBytes.Length); var assetPath = UniGLTF.UnityPath.FromFullpath(path); - if (assetPath.IsUnderAssetsFolder) + if (assetPath.IsUnderWritableFolder) { // asset folder 内。import を発動 assetPath.ImportAsset(); diff --git a/Assets/VRM10/Editor/Vrm10InstanceEditor.cs b/Assets/VRM10/Editor/Vrm10InstanceEditor.cs index 6ecb86115..a2778556b 100644 --- a/Assets/VRM10/Editor/Vrm10InstanceEditor.cs +++ b/Assets/VRM10/Editor/Vrm10InstanceEditor.cs @@ -20,9 +20,9 @@ namespace UniVRM10 return null; } var unityPath = UnityPath.FromFullpath(path); - if (!unityPath.IsUnderAssetsFolder) + if (!unityPath.IsUnderWritableFolder) { - EditorUtility.DisplayDialog("error", "The specified path is not inside of Assets/", "OK"); + EditorUtility.DisplayDialog("error", "The specified path is not inside of Assets or writable Packages", "OK"); return null; }