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;
}