update libs
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0a52c1c4a2b7caa458af5b9a212b80a5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,55 @@
|
||||
using AssetStoreTools.Utility;
|
||||
using AssetStoreTools.Validator.UI.Data.Serialization;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace AssetStoreTools.Validator.Services
|
||||
{
|
||||
internal class CachingService : ICachingService
|
||||
{
|
||||
public bool GetCachedValidatorStateData(out ValidatorStateData stateData)
|
||||
{
|
||||
return GetCachedValidatorStateData(Constants.RootProjectPath, out stateData);
|
||||
}
|
||||
|
||||
public bool GetCachedValidatorStateData(string projectPath, out ValidatorStateData stateData)
|
||||
{
|
||||
stateData = null;
|
||||
if (!CacheUtil.GetFileFromProjectPersistentCache(projectPath, Constants.Cache.ValidationResultFile, out var filePath))
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
var serializerSettings = new JsonSerializerSettings()
|
||||
{
|
||||
ContractResolver = ValidatorStateDataContractResolver.Instance,
|
||||
TypeNameHandling = TypeNameHandling.Auto,
|
||||
Converters = new List<JsonConverter>() { new StringEnumConverter() }
|
||||
};
|
||||
|
||||
stateData = JsonConvert.DeserializeObject<ValidatorStateData>(File.ReadAllText(filePath, Encoding.UTF8), serializerSettings);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void CacheValidatorStateData(ValidatorStateData stateData)
|
||||
{
|
||||
var serializerSettings = new JsonSerializerSettings()
|
||||
{
|
||||
ContractResolver = ValidatorStateDataContractResolver.Instance,
|
||||
Formatting = Formatting.Indented,
|
||||
TypeNameHandling = TypeNameHandling.Auto,
|
||||
Converters = new List<JsonConverter>() { new StringEnumConverter() }
|
||||
};
|
||||
|
||||
CacheUtil.CreateFileInPersistentCache(Constants.Cache.ValidationResultFile, JsonConvert.SerializeObject(stateData, serializerSettings), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b2d545f659acb4343bf485ffb20ecf72
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 115
|
||||
packageName: Asset Store Publishing Tools
|
||||
packageVersion: 12.0.1
|
||||
assetPath: Packages/com.unity.asset-store-tools/Editor/Validator/Scripts/Services/CachingService/CachingService.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,11 @@
|
||||
using AssetStoreTools.Validator.UI.Data.Serialization;
|
||||
|
||||
namespace AssetStoreTools.Validator.Services
|
||||
{
|
||||
internal interface ICachingService : IValidatorService
|
||||
{
|
||||
void CacheValidatorStateData(ValidatorStateData stateData);
|
||||
bool GetCachedValidatorStateData(out ValidatorStateData stateData);
|
||||
bool GetCachedValidatorStateData(string projectPath, out ValidatorStateData stateData);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a8a3e36c133848447b043a91e709c63e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 115
|
||||
packageName: Asset Store Publishing Tools
|
||||
packageVersion: 12.0.1
|
||||
assetPath: Packages/com.unity.asset-store-tools/Editor/Validator/Scripts/Services/CachingService/ICachingService.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,26 @@
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace AssetStoreTools.Previews.Services
|
||||
{
|
||||
internal class PreviewDatabaseContractResolver : DefaultContractResolver
|
||||
{
|
||||
private static PreviewDatabaseContractResolver _instance;
|
||||
public static PreviewDatabaseContractResolver Instance => _instance ?? (_instance = new PreviewDatabaseContractResolver());
|
||||
|
||||
private NamingStrategy _namingStrategy;
|
||||
|
||||
private PreviewDatabaseContractResolver()
|
||||
{
|
||||
_namingStrategy = new SnakeCaseNamingStrategy();
|
||||
}
|
||||
|
||||
protected override string ResolvePropertyName(string propertyName)
|
||||
{
|
||||
var resolvedName = _namingStrategy.GetPropertyName(propertyName, false);
|
||||
if (resolvedName.StartsWith("_"))
|
||||
return resolvedName.Substring(1);
|
||||
|
||||
return resolvedName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aee615e9aaf50fb4f989cd4698e8947e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 115
|
||||
packageName: Asset Store Publishing Tools
|
||||
packageVersion: 12.0.1
|
||||
assetPath: Packages/com.unity.asset-store-tools/Editor/Validator/Scripts/Services/CachingService/PreviewDatabaseContractResolver.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,4 @@
|
||||
namespace AssetStoreTools.Validator.Services
|
||||
{
|
||||
internal interface IValidatorService { }
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 075953f4ab4a65d4fae6e891360df0d0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 115
|
||||
packageName: Asset Store Publishing Tools
|
||||
packageVersion: 12.0.1
|
||||
assetPath: Packages/com.unity.asset-store-tools/Editor/Validator/Scripts/Services/IValidatorService.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 184dcfbfe1d21454fa8cf49f1c637871
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ed0af5acc22551645ae4cb7d75bd1c36
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,18 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AssetStoreTools.Validator.Services.Validation
|
||||
{
|
||||
internal interface IAssetUtilityService : IValidatorService
|
||||
{
|
||||
IEnumerable<string> GetAssetPathsFromAssets(string[] searchPaths, AssetType type);
|
||||
IEnumerable<T> GetObjectsFromAssets<T>(string[] searchPaths, AssetType type) where T : Object;
|
||||
IEnumerable<Object> GetObjectsFromAssets(string[] searchPaths, AssetType type);
|
||||
string ObjectToAssetPath(Object obj);
|
||||
T AssetPathToObject<T>(string assetPath) where T : Object;
|
||||
Object AssetPathToObject(string assetPath);
|
||||
AssetImporter GetAssetImporter(string assetPath);
|
||||
AssetImporter GetAssetImporter(Object asset);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d28c5ea40f4c9954bae02804e416b898
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 115
|
||||
packageName: Asset Store Publishing Tools
|
||||
packageVersion: 12.0.1
|
||||
assetPath: Packages/com.unity.asset-store-tools/Editor/Validator/Scripts/Services/Validation/Abstractions/IAssetUtilityService.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace AssetStoreTools.Validator.Services.Validation
|
||||
{
|
||||
internal interface IFileSignatureUtilityService : IValidatorService
|
||||
{
|
||||
ArchiveType GetArchiveType(string filePath);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 609c423482ecf8844a71166b4ef49cb6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 115
|
||||
packageName: Asset Store Publishing Tools
|
||||
packageVersion: 12.0.1
|
||||
assetPath: Packages/com.unity.asset-store-tools/Editor/Validator/Scripts/Services/Validation/Abstractions/IFileSignatureUtilityService.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AssetStoreTools.Validator.Services.Validation
|
||||
{
|
||||
internal interface IMeshUtilityService : IValidatorService
|
||||
{
|
||||
IEnumerable<Mesh> GetCustomMeshesInObject(GameObject obj);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: acde6f9b97c9cac4b88a84aa9001a0fc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 115
|
||||
packageName: Asset Store Publishing Tools
|
||||
packageVersion: 12.0.1
|
||||
assetPath: Packages/com.unity.asset-store-tools/Editor/Validator/Scripts/Services/Validation/Abstractions/IMeshUtilityService.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AssetStoreTools.Validator.Services.Validation
|
||||
{
|
||||
internal interface IModelUtilityService : IValidatorService
|
||||
{
|
||||
Dictionary<Object, List<LogEntry>> GetImportLogs(params Object[] models);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 91f6bacccdfecb84fb5ab0ba384353b4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 115
|
||||
packageName: Asset Store Publishing Tools
|
||||
packageVersion: 12.0.1
|
||||
assetPath: Packages/com.unity.asset-store-tools/Editor/Validator/Scripts/Services/Validation/Abstractions/IModelUtilityService.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,13 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace AssetStoreTools.Validator.Services.Validation
|
||||
{
|
||||
internal interface ISceneUtilityService : IValidatorService
|
||||
{
|
||||
string CurrentScenePath { get; }
|
||||
|
||||
Scene OpenScene(string scenePath);
|
||||
GameObject[] GetRootGameObjects();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cf5ef331063e5aa4e95dfe3eadedf9af
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 115
|
||||
packageName: Asset Store Publishing Tools
|
||||
packageVersion: 12.0.1
|
||||
assetPath: Packages/com.unity.asset-store-tools/Editor/Validator/Scripts/Services/Validation/Abstractions/ISceneUtilityService.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace AssetStoreTools.Validator.Services.Validation
|
||||
{
|
||||
internal interface IScriptUtilityService : IValidatorService
|
||||
{
|
||||
IReadOnlyDictionary<MonoScript, IList<(string Name, string Namespace)>> GetTypeNamespacesFromScriptAssets(IList<MonoScript> monoScripts);
|
||||
IReadOnlyDictionary<Object, IList<Type>> GetTypesFromAssemblies(IList<Object> assemblies);
|
||||
IReadOnlyDictionary<MonoScript, IList<Type>> GetTypesFromScriptAssets(IList<MonoScript> monoScripts);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e0a9f88d37222e4428853b6d3d00b1bd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 115
|
||||
packageName: Asset Store Publishing Tools
|
||||
packageVersion: 12.0.1
|
||||
assetPath: Packages/com.unity.asset-store-tools/Editor/Validator/Scripts/Services/Validation/Abstractions/IScriptUtilityService.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,216 @@
|
||||
using AssetStoreTools.Utility;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Compilation;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace AssetStoreTools.Validator.Services.Validation
|
||||
{
|
||||
internal class AssetUtilityService : IAssetUtilityService
|
||||
{
|
||||
public IEnumerable<string> GetAssetPathsFromAssets(string[] searchPaths, AssetType type)
|
||||
{
|
||||
string filter = string.Empty;
|
||||
string[] extensions = null;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
// General Types
|
||||
case AssetType.All:
|
||||
filter = "";
|
||||
break;
|
||||
case AssetType.Prefab:
|
||||
filter = "t:prefab";
|
||||
break;
|
||||
case AssetType.Material:
|
||||
filter = "t:material";
|
||||
break;
|
||||
case AssetType.Model:
|
||||
filter = "t:model";
|
||||
break;
|
||||
case AssetType.Scene:
|
||||
filter = "t:scene";
|
||||
break;
|
||||
case AssetType.Texture:
|
||||
filter = "t:texture";
|
||||
break;
|
||||
case AssetType.Video:
|
||||
filter = "t:VideoClip";
|
||||
break;
|
||||
// Specific Types
|
||||
case AssetType.LossyAudio:
|
||||
filter = "t:AudioClip";
|
||||
extensions = new[] { ".mp3", ".ogg" };
|
||||
break;
|
||||
case AssetType.NonLossyAudio:
|
||||
filter = "t:AudioClip";
|
||||
extensions = new[] { ".wav", ".aif", ".aiff" };
|
||||
break;
|
||||
case AssetType.JavaScript:
|
||||
filter = "t:TextAsset";
|
||||
extensions = new[] { ".js" };
|
||||
break;
|
||||
case AssetType.Mixamo:
|
||||
filter = "t:model";
|
||||
extensions = new[] { ".fbx" };
|
||||
break;
|
||||
case AssetType.JPG:
|
||||
filter = "t:texture";
|
||||
extensions = new[] { ".jpg", "jpeg" };
|
||||
break;
|
||||
case AssetType.Executable:
|
||||
filter = string.Empty;
|
||||
extensions = new[] { ".exe", ".bat", ".msi", ".apk" };
|
||||
break;
|
||||
case AssetType.Documentation:
|
||||
filter = string.Empty;
|
||||
extensions = new[] { ".txt", ".pdf", ".html", ".rtf", ".md" };
|
||||
break;
|
||||
case AssetType.SpeedTree:
|
||||
filter = string.Empty;
|
||||
extensions = new[] { ".spm", ".srt", ".stm", ".scs", ".sfc", ".sme", ".st" };
|
||||
break;
|
||||
case AssetType.Shader:
|
||||
filter = string.Empty;
|
||||
extensions = new[] { ".shader", ".shadergraph", ".raytrace", ".compute" };
|
||||
break;
|
||||
case AssetType.MonoScript:
|
||||
filter = "t:script";
|
||||
extensions = new[] { ".cs" };
|
||||
break;
|
||||
case AssetType.UnityPackage:
|
||||
filter = string.Empty;
|
||||
extensions = new[] { ".unitypackage" };
|
||||
break;
|
||||
case AssetType.PrecompiledAssembly:
|
||||
var assemblyPaths = GetPrecompiledAssemblies(searchPaths);
|
||||
return assemblyPaths;
|
||||
default:
|
||||
return Array.Empty<string>();
|
||||
}
|
||||
|
||||
var guids = AssetDatabase.FindAssets(filter, searchPaths);
|
||||
var paths = guids.Select(AssetDatabase.GUIDToAssetPath);
|
||||
|
||||
if (extensions != null)
|
||||
paths = paths.Where(x => extensions.Any(x.ToLower().EndsWith));
|
||||
|
||||
if (type == AssetType.Mixamo)
|
||||
paths = paths.Where(IsMixamoFbx);
|
||||
|
||||
paths = paths.Distinct();
|
||||
return paths;
|
||||
}
|
||||
|
||||
public IEnumerable<T> GetObjectsFromAssets<T>(string[] searchPaths, AssetType type) where T : Object
|
||||
{
|
||||
var paths = GetAssetPathsFromAssets(searchPaths, type);
|
||||
#if !AB_BUILDER
|
||||
var objects = paths.Select(AssetDatabase.LoadAssetAtPath<T>).Where(x => x != null);
|
||||
#else
|
||||
var objects = new AssetEnumerator<T>(paths);
|
||||
#endif
|
||||
return objects;
|
||||
}
|
||||
|
||||
public IEnumerable<Object> GetObjectsFromAssets(string[] searchPaths, AssetType type)
|
||||
{
|
||||
return GetObjectsFromAssets<Object>(searchPaths, type);
|
||||
}
|
||||
|
||||
private IEnumerable<string> GetPrecompiledAssemblies(string[] searchPaths)
|
||||
{
|
||||
// Note - for packages, Compilation Pipeline returns full paths, as they appear on disk, not Asset Database
|
||||
var allDllPaths = CompilationPipeline.GetPrecompiledAssemblyPaths(CompilationPipeline.PrecompiledAssemblySources.UserAssembly);
|
||||
var rootProjectPath = Application.dataPath.Substring(0, Application.dataPath.Length - "Assets".Length);
|
||||
var packages = PackageUtility.GetAllLocalPackages();
|
||||
|
||||
var result = new List<string>();
|
||||
foreach (var dllPath in allDllPaths)
|
||||
{
|
||||
var absoluteDllPath = Path.GetFullPath(dllPath).Replace("\\", "/");
|
||||
foreach (var validationPath in searchPaths)
|
||||
{
|
||||
var absoluteValidationPath = Path.GetFullPath(validationPath).Replace("\\", "/");
|
||||
if (absoluteDllPath.StartsWith(absoluteValidationPath))
|
||||
{
|
||||
int pathSeparatorLength = 1;
|
||||
if (absoluteDllPath.StartsWith(Application.dataPath))
|
||||
{
|
||||
var adbPath = $"Assets/{absoluteDllPath.Remove(0, Application.dataPath.Length + pathSeparatorLength)}";
|
||||
result.Add(adbPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
// For non-Asset folder paths (i.e. local and embedded packages), convert disk path to ADB path
|
||||
var package = packages.FirstOrDefault(x => dllPath.StartsWith(x.resolvedPath.Replace('\\', '/')));
|
||||
|
||||
if (package == null)
|
||||
continue;
|
||||
|
||||
var dllPathInPackage = absoluteDllPath.Remove(0, Path.GetFullPath(package.resolvedPath).Length + pathSeparatorLength);
|
||||
var adbPath = $"Packages/{package.name}/{dllPathInPackage}";
|
||||
|
||||
result.Add(adbPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool IsMixamoFbx(string fbxPath)
|
||||
{
|
||||
// Location of Mixamo Header, this is located in every mixamo fbx file exported
|
||||
//const int mixamoHeader = 0x4c0 + 2; // < this is the original location from A$ Tools, unsure if Mixamo file headers were changed since then
|
||||
const int mixamoHeader = 1622;
|
||||
// Length of Mixamo header
|
||||
const int length = 0xa;
|
||||
|
||||
var fs = new FileStream(fbxPath, FileMode.Open);
|
||||
// Check if length is further than
|
||||
if (fs.Length < mixamoHeader)
|
||||
return false;
|
||||
|
||||
byte[] buffer = new byte[length];
|
||||
using (BinaryReader reader = new BinaryReader(fs))
|
||||
{
|
||||
reader.BaseStream.Seek(mixamoHeader, SeekOrigin.Begin);
|
||||
reader.Read(buffer, 0, length);
|
||||
}
|
||||
|
||||
string result = System.Text.Encoding.ASCII.GetString(buffer);
|
||||
return result.Contains("Mixamo");
|
||||
}
|
||||
|
||||
public string ObjectToAssetPath(Object obj)
|
||||
{
|
||||
return AssetDatabase.GetAssetPath(obj);
|
||||
}
|
||||
|
||||
public T AssetPathToObject<T>(string assetPath) where T : Object
|
||||
{
|
||||
return AssetDatabase.LoadAssetAtPath<T>(assetPath);
|
||||
}
|
||||
|
||||
public Object AssetPathToObject(string assetPath)
|
||||
{
|
||||
return AssetPathToObject<Object>(assetPath);
|
||||
}
|
||||
|
||||
public AssetImporter GetAssetImporter(string assetPath)
|
||||
{
|
||||
return AssetImporter.GetAtPath(assetPath);
|
||||
}
|
||||
|
||||
public AssetImporter GetAssetImporter(Object asset)
|
||||
{
|
||||
return GetAssetImporter(ObjectToAssetPath(asset));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9634968648d355c47b7cb12aead7abab
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 115
|
||||
packageName: Asset Store Publishing Tools
|
||||
packageVersion: 12.0.1
|
||||
assetPath: Packages/com.unity.asset-store-tools/Editor/Validator/Scripts/Services/Validation/AssetUtilityService.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8dcc2f4da0b6cea4ab4733ebf32edab4
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace AssetStoreTools.Validator.Services.Validation
|
||||
{
|
||||
internal enum ArchiveType
|
||||
{
|
||||
None,
|
||||
TarGz,
|
||||
Zip,
|
||||
Rar,
|
||||
Tar,
|
||||
TarZip,
|
||||
Bz2,
|
||||
LZip,
|
||||
SevenZip,
|
||||
GZip,
|
||||
QuickZip,
|
||||
Xz,
|
||||
Wim
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4061cb7aed3883346a66494c23e2e77b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 115
|
||||
packageName: Asset Store Publishing Tools
|
||||
packageVersion: 12.0.1
|
||||
assetPath: Packages/com.unity.asset-store-tools/Editor/Validator/Scripts/Services/Validation/Data/ArchiveType.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace AssetStoreTools.Validator.Services.Validation
|
||||
{
|
||||
internal class AssetEnumerator<T> : IEnumerator<T>, IEnumerable<T> where T : Object
|
||||
{
|
||||
public const int Capacity = 32;
|
||||
|
||||
private Queue<string> _pathQueue;
|
||||
private Queue<T> _loadedAssetQueue;
|
||||
|
||||
private T _currentElement;
|
||||
|
||||
public AssetEnumerator(IEnumerable<string> paths)
|
||||
{
|
||||
_pathQueue = new Queue<string>(paths);
|
||||
_loadedAssetQueue = new Queue<T>();
|
||||
}
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
bool hasPathsButHasNoAssets = _pathQueue.Count != 0 && _loadedAssetQueue.Count == 0;
|
||||
if (hasPathsButHasNoAssets)
|
||||
{
|
||||
LoadMore();
|
||||
}
|
||||
|
||||
bool dequeued = false;
|
||||
if (_loadedAssetQueue.Count != 0)
|
||||
{
|
||||
_currentElement = _loadedAssetQueue.Dequeue();
|
||||
dequeued = true;
|
||||
}
|
||||
|
||||
return dequeued;
|
||||
}
|
||||
|
||||
private void LoadMore()
|
||||
{
|
||||
int limit = Capacity;
|
||||
while (limit > 0 && _pathQueue.Count != 0)
|
||||
{
|
||||
string path = _pathQueue.Dequeue();
|
||||
T asset = AssetDatabase.LoadAssetAtPath<T>(path);
|
||||
if (asset != null)
|
||||
{
|
||||
_loadedAssetQueue.Enqueue(asset);
|
||||
limit--;
|
||||
}
|
||||
}
|
||||
|
||||
// Unload other loose asset references
|
||||
EditorUtility.UnloadUnusedAssetsImmediate();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
throw new NotSupportedException("Asset Enumerator cannot be reset.");
|
||||
}
|
||||
|
||||
public T Current => _currentElement;
|
||||
|
||||
object IEnumerator.Current => Current;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// No need to dispose
|
||||
}
|
||||
|
||||
IEnumerator<T> IEnumerable<T>.GetEnumerator()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
public IEnumerator GetEnumerator()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0859579889cc56f4aa26eb863a1487b9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 115
|
||||
packageName: Asset Store Publishing Tools
|
||||
packageVersion: 12.0.1
|
||||
assetPath: Packages/com.unity.asset-store-tools/Editor/Validator/Scripts/Services/Validation/Data/AssetEnumerator.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,25 @@
|
||||
namespace AssetStoreTools.Validator.Services.Validation
|
||||
{
|
||||
internal enum AssetType
|
||||
{
|
||||
All,
|
||||
Documentation,
|
||||
Executable,
|
||||
JPG,
|
||||
JavaScript,
|
||||
LossyAudio,
|
||||
Material,
|
||||
Mixamo,
|
||||
Model,
|
||||
MonoScript,
|
||||
NonLossyAudio,
|
||||
PrecompiledAssembly,
|
||||
Prefab,
|
||||
Scene,
|
||||
Shader,
|
||||
SpeedTree,
|
||||
Texture,
|
||||
UnityPackage,
|
||||
Video
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b81d00d4ed0a7da4289d4d6248ef9d34
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 115
|
||||
packageName: Asset Store Publishing Tools
|
||||
packageVersion: 12.0.1
|
||||
assetPath: Packages/com.unity.asset-store-tools/Editor/Validator/Scripts/Services/Validation/Data/AssetType.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,10 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace AssetStoreTools.Validator.Services.Validation
|
||||
{
|
||||
internal class LogEntry
|
||||
{
|
||||
public string Message;
|
||||
public LogType Severity;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a1e81104d6b0f4c449ee57503c3b6669
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 115
|
||||
packageName: Asset Store Publishing Tools
|
||||
packageVersion: 12.0.1
|
||||
assetPath: Packages/com.unity.asset-store-tools/Editor/Validator/Scripts/Services/Validation/Data/LogEntry.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,78 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AssetStoreTools.Validator.Services.Validation
|
||||
{
|
||||
internal class FileSignatureUtilityService : IFileSignatureUtilityService
|
||||
{
|
||||
private class FileSignature
|
||||
{
|
||||
public byte[] SignatureBytes;
|
||||
public int Offset;
|
||||
|
||||
public FileSignature(byte[] signatureBytes, int offset)
|
||||
{
|
||||
SignatureBytes = signatureBytes;
|
||||
Offset = offset;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Dictionary<FileSignature, ArchiveType> ArchiveSignatures = new Dictionary<FileSignature, ArchiveType>
|
||||
{
|
||||
{ new FileSignature(new byte[] { 0x1f, 0x8b }, 0), ArchiveType.TarGz },
|
||||
{ new FileSignature(new byte[] { 0x50, 0x4b, 0x03, 0x04 }, 0), ArchiveType.Zip },
|
||||
{ new FileSignature(new byte[] { 0x50, 0x4b, 0x05, 0x06 }, 0), ArchiveType.Zip }, // Empty Zip Archive
|
||||
{ new FileSignature(new byte[] { 0x50, 0x4b, 0x07, 0x08 }, 0), ArchiveType.Zip }, // Spanned Zip Archive
|
||||
|
||||
{ new FileSignature(new byte[] { 0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 }, 0), ArchiveType.Rar }, // RaR v1.50+
|
||||
{ new FileSignature(new byte[] { 0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x01, 0x00 }, 0), ArchiveType.Rar }, // RaR v5.00+
|
||||
{ new FileSignature(new byte[] { 0x75, 0x73, 0x74, 0x61, 0x72, 0x00, 0x30, 0x30 }, 257), ArchiveType.Tar },
|
||||
{ new FileSignature(new byte[] { 0x75, 0x73, 0x74, 0x61, 0x72, 0x20, 0x20, 0x00 }, 257), ArchiveType.Tar },
|
||||
{ new FileSignature(new byte[] { 0x1f, 0x9d }, 0), ArchiveType.TarZip }, // TarZip LZW algorithm
|
||||
{ new FileSignature(new byte[] { 0x1f, 0xa0 }, 0), ArchiveType.TarZip }, // TarZip LZH algorithm
|
||||
{ new FileSignature(new byte[] { 0x42, 0x5a, 0x68 }, 0), ArchiveType.Bz2 },
|
||||
{ new FileSignature(new byte[] { 0x4c, 0x5a, 0x49, 0x50 }, 0), ArchiveType.LZip },
|
||||
{ new FileSignature(new byte[] { 0x37, 0x7a, 0xbc, 0xaf, 0x27, 0x1c }, 0), ArchiveType.SevenZip },
|
||||
{ new FileSignature(new byte[] { 0x1f, 0x8b }, 0), ArchiveType.GZip },
|
||||
{ new FileSignature(new byte[] { 0x52, 0x53, 0x56, 0x4b, 0x44, 0x41, 0x54, 0x41 }, 0), ArchiveType.QuickZip },
|
||||
{ new FileSignature(new byte[] { 0xfd, 0x37, 0x7a, 0x58, 0x5a, 0x00 }, 0), ArchiveType.Xz },
|
||||
{ new FileSignature(new byte[] { 0x4D, 0x53, 0x57, 0x49, 0x4D, 0x00, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x00, 0x00 }, 0), ArchiveType.Wim }
|
||||
};
|
||||
|
||||
public ArchiveType GetArchiveType(string filePath)
|
||||
{
|
||||
if (!File.Exists(filePath))
|
||||
return ArchiveType.None;
|
||||
|
||||
try
|
||||
{
|
||||
using (FileStream stream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
foreach (var kvp in ArchiveSignatures)
|
||||
{
|
||||
var fileSignature = kvp.Key;
|
||||
var archiveType = kvp.Value;
|
||||
|
||||
if (stream.Length < fileSignature.SignatureBytes.Length)
|
||||
continue;
|
||||
|
||||
var bytes = new byte[fileSignature.SignatureBytes.Length];
|
||||
stream.Seek(fileSignature.Offset, SeekOrigin.Begin);
|
||||
stream.Read(bytes, 0, bytes.Length);
|
||||
|
||||
if (fileSignature.SignatureBytes.SequenceEqual(bytes.Take(fileSignature.SignatureBytes.Length)))
|
||||
return archiveType;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (DirectoryNotFoundException)
|
||||
{
|
||||
Debug.LogWarning($"File '{filePath}' exists, but could not be opened for reading. Please make sure the project path lengths are not too long for the Operating System");
|
||||
}
|
||||
|
||||
return ArchiveType.None;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 695ed79ad88c3b44b8ae41b650ebe16c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 115
|
||||
packageName: Asset Store Publishing Tools
|
||||
packageVersion: 12.0.1
|
||||
assetPath: Packages/com.unity.asset-store-tools/Editor/Validator/Scripts/Services/Validation/FileSignatureUtilityService.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,26 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AssetStoreTools.Validator.Services.Validation
|
||||
{
|
||||
internal class MeshUtilityService : IMeshUtilityService
|
||||
{
|
||||
public IEnumerable<Mesh> GetCustomMeshesInObject(GameObject obj)
|
||||
{
|
||||
var meshes = new List<Mesh>();
|
||||
|
||||
var meshFilters = obj.GetComponentsInChildren<MeshFilter>(true);
|
||||
var skinnedMeshes = obj.GetComponentsInChildren<SkinnedMeshRenderer>(true);
|
||||
|
||||
meshes.AddRange(meshFilters.Select(m => m.sharedMesh));
|
||||
meshes.AddRange(skinnedMeshes.Select(m => m.sharedMesh));
|
||||
|
||||
meshes = meshes.Where(m => AssetDatabase.GetAssetPath(m).StartsWith("Assets/") ||
|
||||
AssetDatabase.GetAssetPath(m).StartsWith("Packages/")).ToList();
|
||||
|
||||
return meshes;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 307f5dd7be983e246adbda52ac50ecf3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 115
|
||||
packageName: Asset Store Publishing Tools
|
||||
packageVersion: 12.0.1
|
||||
assetPath: Packages/com.unity.asset-store-tools/Editor/Validator/Scripts/Services/Validation/MeshUtilityService.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,147 @@
|
||||
#if !UNITY_2022_2_OR_NEWER
|
||||
using System;
|
||||
using System.Reflection;
|
||||
#endif
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
#if UNITY_2022_2_OR_NEWER
|
||||
using UnityEditor.AssetImporters;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace AssetStoreTools.Validator.Services.Validation
|
||||
{
|
||||
internal class ModelUtilityService : IModelUtilityService
|
||||
{
|
||||
private IAssetUtilityService _assetUtility;
|
||||
|
||||
#if !UNITY_2022_2_OR_NEWER
|
||||
// Rig fields
|
||||
private const string RigImportWarningsField = "m_RigImportWarnings";
|
||||
private const string RigImportErrorsField = "m_RigImportErrors";
|
||||
|
||||
// Animation fields
|
||||
private const string AnimationImportWarningsField = "m_AnimationImportWarnings";
|
||||
private const string AnimationImportErrorsField = "m_AnimationImportErrors";
|
||||
|
||||
private static Editor _modelImporterEditor = null;
|
||||
#endif
|
||||
|
||||
public ModelUtilityService(IAssetUtilityService assetUtility)
|
||||
{
|
||||
_assetUtility = assetUtility;
|
||||
}
|
||||
|
||||
public Dictionary<Object, List<LogEntry>> GetImportLogs(params Object[] models)
|
||||
{
|
||||
#if UNITY_2022_2_OR_NEWER
|
||||
return GetImportLogsDefault(models);
|
||||
#else
|
||||
return GetImportLogsLegacy(models);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_2022_2_OR_NEWER
|
||||
private Dictionary<Object, List<LogEntry>> GetImportLogsDefault(params Object[] models)
|
||||
{
|
||||
var modelsWithLogs = new Dictionary<Object, List<LogEntry>>();
|
||||
|
||||
foreach (var model in models)
|
||||
{
|
||||
var modelLogs = new List<LogEntry>();
|
||||
|
||||
var importLog = AssetImporter.GetImportLog(_assetUtility.ObjectToAssetPath(model));
|
||||
|
||||
if (importLog == null)
|
||||
continue;
|
||||
|
||||
var entries = importLog.logEntries.Where(x => x.flags.HasFlag(ImportLogFlags.Warning) || x.flags.HasFlag(ImportLogFlags.Error));
|
||||
foreach (var entry in entries)
|
||||
{
|
||||
var severity = entry.flags.HasFlag(ImportLogFlags.Error) ? LogType.Error : LogType.Warning;
|
||||
modelLogs.Add(new LogEntry() { Message = entry.message, Severity = severity });
|
||||
}
|
||||
|
||||
if (modelLogs.Count > 0)
|
||||
modelsWithLogs.Add(model, modelLogs);
|
||||
}
|
||||
|
||||
return modelsWithLogs;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !UNITY_2022_2_OR_NEWER
|
||||
private Dictionary<Object, List<LogEntry>> GetImportLogsLegacy(params Object[] models)
|
||||
{
|
||||
var modelsWithLogs = new Dictionary<Object, List<LogEntry>>();
|
||||
|
||||
foreach (var model in models)
|
||||
{
|
||||
var modelLogs = new List<LogEntry>();
|
||||
|
||||
// Load the Model Importer
|
||||
var modelImporter = _assetUtility.GetAssetImporter(model) as ModelImporter;
|
||||
|
||||
var editorAssembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(x => x.GetName().Name.Equals("UnityEditor"));
|
||||
|
||||
var modelImporterEditorType = editorAssembly.GetType("UnityEditor.ModelImporterEditor");
|
||||
|
||||
// Load its Model Importer Editor
|
||||
Editor.CreateCachedEditorWithContext(new Object[] { modelImporter }, model, modelImporterEditorType, ref _modelImporterEditor);
|
||||
|
||||
// Find the base type
|
||||
var modelImporterEditorTypeBase = _modelImporterEditor.GetType().BaseType;
|
||||
|
||||
// Get the tabs value
|
||||
var tabsArrayType = modelImporterEditorTypeBase.GetRuntimeProperties().FirstOrDefault(x => x.Name == "tabs");
|
||||
var tabsArray = (Array)tabsArrayType.GetValue(_modelImporterEditor);
|
||||
|
||||
// Get the tabs (Model | Rig | Animation | Materials)
|
||||
var rigTab = tabsArray.GetValue(1);
|
||||
var animationTab = tabsArray.GetValue(2);
|
||||
|
||||
var rigErrorsCheckSuccess = CheckFieldForSerializedProperty(rigTab, RigImportErrorsField, out var rigErrors);
|
||||
var rigWarningsCheckSuccess = CheckFieldForSerializedProperty(rigTab, RigImportWarningsField, out var rigWarnings);
|
||||
var animationErrorsCheckSuccess = CheckFieldForSerializedProperty(animationTab, AnimationImportErrorsField, out var animationErrors);
|
||||
var animationWarningsCheckSuccess = CheckFieldForSerializedProperty(animationTab, AnimationImportWarningsField, out var animationWarnings);
|
||||
|
||||
if (!rigErrorsCheckSuccess || !rigWarningsCheckSuccess || !animationErrorsCheckSuccess || !animationWarningsCheckSuccess)
|
||||
UnityEngine.Debug.LogWarning($"An error was encountered when checking import logs for model '{model.name}'");
|
||||
|
||||
if (!string.IsNullOrEmpty(rigWarnings))
|
||||
modelLogs.Add(new LogEntry() { Message = rigWarnings, Severity = LogType.Warning });
|
||||
if (!string.IsNullOrEmpty(rigErrors))
|
||||
modelLogs.Add(new LogEntry() { Message = rigErrors, Severity = LogType.Error });
|
||||
if (!string.IsNullOrEmpty(animationWarnings))
|
||||
modelLogs.Add(new LogEntry() { Message = animationWarnings, Severity = LogType.Warning });
|
||||
if (!string.IsNullOrEmpty(animationErrors))
|
||||
modelLogs.Add(new LogEntry() { Message = animationErrors, Severity = LogType.Error });
|
||||
|
||||
if (modelLogs.Count > 0)
|
||||
modelsWithLogs.Add(model, modelLogs);
|
||||
}
|
||||
|
||||
return modelsWithLogs;
|
||||
}
|
||||
|
||||
private static bool CheckFieldForSerializedProperty(object source, string propertyName, out string message)
|
||||
{
|
||||
message = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
var propertyType = source.GetType().GetRuntimeFields().FirstOrDefault(x => x.Name.Equals(propertyName, StringComparison.OrdinalIgnoreCase));
|
||||
var propertyValue = propertyType.GetValue(source) as SerializedProperty;
|
||||
message = propertyValue.stringValue;
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c50ca4c87e66f1b478279e5d1db4a08e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 115
|
||||
packageName: Asset Store Publishing Tools
|
||||
packageVersion: 12.0.1
|
||||
assetPath: Packages/com.unity.asset-store-tools/Editor/Validator/Scripts/Services/Validation/ModelUtilityService.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,26 @@
|
||||
using UnityEditor;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace AssetStoreTools.Validator.Services.Validation
|
||||
{
|
||||
internal class SceneUtilityService : ISceneUtilityService
|
||||
{
|
||||
public string CurrentScenePath => SceneManager.GetActiveScene().path;
|
||||
|
||||
public Scene OpenScene(string scenePath)
|
||||
{
|
||||
EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo();
|
||||
if (string.IsNullOrEmpty(scenePath) || AssetDatabase.LoadAssetAtPath<SceneAsset>(scenePath) == null)
|
||||
return EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects);
|
||||
else
|
||||
return EditorSceneManager.OpenScene(scenePath);
|
||||
}
|
||||
|
||||
public GameObject[] GetRootGameObjects()
|
||||
{
|
||||
return SceneManager.GetSceneByPath(CurrentScenePath).GetRootGameObjects();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 53e8deb0ebfb7ea47956f3a859580cd4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 115
|
||||
packageName: Asset Store Publishing Tools
|
||||
packageVersion: 12.0.1
|
||||
assetPath: Packages/com.unity.asset-store-tools/Editor/Validator/Scripts/Services/Validation/SceneUtilityService.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,658 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEditor;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace AssetStoreTools.Validator.Services.Validation
|
||||
{
|
||||
internal class ScriptUtilityService : IScriptUtilityService
|
||||
{
|
||||
private const int ScriptTimeoutMs = 10000;
|
||||
private const string IgnoredAssemblyCharacters = "!@#$%^*&()-+=[]{}\\|;:'\",.<>/?";
|
||||
|
||||
/// <summary>
|
||||
/// For a given list of script assets, retrieves a list of types and their namespaces
|
||||
/// </summary>
|
||||
/// <param name="monoScripts"></param>
|
||||
/// <returns>A dictionary mapping each script asset with a list of its types.
|
||||
/// The type tuple contains a name (e.g. <i>class MyClass</i>) and its namespace (e.g. <i>MyNamespace</i>)
|
||||
/// </returns>
|
||||
public IReadOnlyDictionary<MonoScript, IList<(string Name, string Namespace)>> GetTypeNamespacesFromScriptAssets(IList<MonoScript> monoScripts)
|
||||
{
|
||||
var typesAndNamespaces = new Dictionary<MonoScript, IList<(string Name, string Namespace)>>();
|
||||
var typeInfos = GetTypeInfosFromScriptAssets(monoScripts);
|
||||
|
||||
foreach (var kvp in typeInfos)
|
||||
{
|
||||
var namespacesInScript = new List<(string Name, string Namespace)>();
|
||||
foreach (var typeInfo in kvp.Value)
|
||||
{
|
||||
bool isValidType = typeInfo.TypeName == ScriptParser.TypeName.Class || typeInfo.TypeName == ScriptParser.TypeName.Struct ||
|
||||
typeInfo.TypeName == ScriptParser.TypeName.Interface || typeInfo.TypeName == ScriptParser.TypeName.Enum;
|
||||
|
||||
if (isValidType)
|
||||
namespacesInScript.Add(($"{typeInfo.TypeName.ToString().ToLower()} {typeInfo.Name}", typeInfo.Namespace));
|
||||
}
|
||||
|
||||
typesAndNamespaces.Add(kvp.Key, namespacesInScript);
|
||||
}
|
||||
|
||||
return typesAndNamespaces;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scans the given precompiled assembly assets to retrieve a list of their contained types
|
||||
/// </summary>
|
||||
/// <param name="assemblies"></param>
|
||||
/// <returns>A dictionary mapping each precompiled assembly asset with a list of <see cref="Type"> System.Type </see> objects.</returns>
|
||||
public IReadOnlyDictionary<Object, IList<Type>> GetTypesFromAssemblies(IList<Object> assemblies)
|
||||
{
|
||||
var dllPaths = assemblies.ToDictionary(t => AssetDatabase.GetAssetPath(t), t => t);
|
||||
var types = new ConcurrentDictionary<Object, IList<Type>>();
|
||||
var failedDllPaths = new ConcurrentBag<string>();
|
||||
|
||||
var allAssemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
|
||||
Parallel.ForEach(dllPaths.Keys,
|
||||
(assemblyPath) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var assembly = allAssemblies.FirstOrDefault(x => Path.GetFullPath(x.Location).Equals(Path.GetFullPath(assemblyPath), StringComparison.OrdinalIgnoreCase));
|
||||
if (assembly == null)
|
||||
return;
|
||||
|
||||
var assemblyTypes = assembly.GetTypes().Where(x => !IgnoredAssemblyCharacters.Any(c => x.Name.Contains(c))).ToList();
|
||||
types.TryAdd(dllPaths[assemblyPath], assemblyTypes);
|
||||
}
|
||||
catch
|
||||
{
|
||||
failedDllPaths.Add(assemblyPath);
|
||||
}
|
||||
});
|
||||
|
||||
if (failedDllPaths.Count > 0)
|
||||
{
|
||||
var message = new StringBuilder("The following precompiled assemblies could not be checked:");
|
||||
foreach (var path in failedDllPaths)
|
||||
message.Append($"\n{path}");
|
||||
UnityEngine.Debug.LogWarning(message);
|
||||
}
|
||||
|
||||
// Types are sorted randomly due to parallelism, therefore need to be sorted before returning
|
||||
var sortedTypes = dllPaths.Where(x => types.ContainsKey(x.Value))
|
||||
.Select(x => new KeyValuePair<Object, IList<Type>>(x.Value, types[x.Value]))
|
||||
.ToDictionary(t => t.Key, t => t.Value);
|
||||
|
||||
return sortedTypes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scans the given script assets to retrieve a list of their contained types
|
||||
/// </summary>
|
||||
/// <param name="monoScripts"></param>
|
||||
/// <returns>A dictionary mapping each precompiled assembly asset with a list of <see cref="Type"> System.Type </see> objects.</returns>
|
||||
public IReadOnlyDictionary<MonoScript, IList<Type>> GetTypesFromScriptAssets(IList<MonoScript> monoScripts)
|
||||
{
|
||||
var realTypes = new Dictionary<MonoScript, IList<Type>>();
|
||||
var typeInfos = GetTypeInfosFromScriptAssets(monoScripts);
|
||||
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
|
||||
foreach (var kvp in typeInfos)
|
||||
{
|
||||
var realTypesInScript = new List<Type>();
|
||||
foreach (var typeInfo in kvp.Value)
|
||||
{
|
||||
bool isValidType = typeInfo.TypeName == ScriptParser.TypeName.Class || typeInfo.TypeName == ScriptParser.TypeName.Struct ||
|
||||
typeInfo.TypeName == ScriptParser.TypeName.Interface || typeInfo.TypeName == ScriptParser.TypeName.Enum;
|
||||
|
||||
if (isValidType)
|
||||
{
|
||||
var realType = assemblies.Where(a => a.GetType(typeInfo.GetReflectionFriendlyFullName()) != null)
|
||||
.Select(a => a.GetType(typeInfo.GetReflectionFriendlyFullName())).FirstOrDefault();
|
||||
if (realType != null)
|
||||
realTypesInScript.Add(realType);
|
||||
}
|
||||
}
|
||||
|
||||
realTypes.Add(kvp.Key, realTypesInScript);
|
||||
}
|
||||
|
||||
return realTypes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Scans the given MonoScript assets to retrieve a list of their contained types
|
||||
/// </summary>
|
||||
/// <param name="monoScripts"></param>
|
||||
/// <returns>A dictionary mapping each script asset with a list of <see cref="TypeInfo"> TypeInfo </see> objects. </returns>
|
||||
private IReadOnlyDictionary<MonoScript, IList<ScriptParser.BlockInfo>> GetTypeInfosFromScriptAssets(IList<MonoScript> monoScripts)
|
||||
{
|
||||
var types = new ConcurrentDictionary<MonoScript, IList<ScriptParser.BlockInfo>>();
|
||||
var monoScriptContents = new Dictionary<MonoScript, string>();
|
||||
var failedScripts = new ConcurrentBag<MonoScript>();
|
||||
|
||||
// A separate dictionary is needed because MonoScript contents cannot be accessed outside of the main thread
|
||||
foreach (var kvp in monoScripts)
|
||||
monoScriptContents.Add(kvp, kvp.text);
|
||||
|
||||
var tasks = new List<Tuple<Task, CancellationTokenSource>>();
|
||||
|
||||
try
|
||||
{
|
||||
foreach (var kvp in monoScriptContents)
|
||||
{
|
||||
var cancellationTokenSource = new CancellationTokenSource(ScriptTimeoutMs);
|
||||
|
||||
var task = Task.Run(() =>
|
||||
{
|
||||
var parsingTask = new ScriptParser(cancellationTokenSource.Token);
|
||||
var parsed = parsingTask.GetTypesInScript(kvp.Value, out IList<ScriptParser.BlockInfo> parsedTypes);
|
||||
if (parsed)
|
||||
types.TryAdd(kvp.Key, parsedTypes);
|
||||
else
|
||||
failedScripts.Add(kvp.Key);
|
||||
});
|
||||
|
||||
tasks.Add(new Tuple<Task, CancellationTokenSource>(task, cancellationTokenSource));
|
||||
}
|
||||
|
||||
foreach (var t in tasks)
|
||||
t.Item1.Wait();
|
||||
}
|
||||
finally
|
||||
{
|
||||
foreach (var t in tasks)
|
||||
t.Item2.Dispose();
|
||||
}
|
||||
|
||||
if (failedScripts.Count > 0)
|
||||
{
|
||||
var message = new StringBuilder("The following scripts could not be checked:");
|
||||
foreach (var s in failedScripts)
|
||||
message.Append($"\n{AssetDatabase.GetAssetPath(s)}");
|
||||
UnityEngine.Debug.LogWarning(message);
|
||||
}
|
||||
|
||||
// Types are sorted randomly due to parallelism, therefore need to be sorted before returning
|
||||
var sortedTypes = monoScriptContents.Where(x => types.ContainsKey(x.Key))
|
||||
.Select(x => new KeyValuePair<MonoScript, IList<ScriptParser.BlockInfo>>(x.Key, types[x.Key]))
|
||||
.ToDictionary(t => t.Key, t => t.Value);
|
||||
|
||||
return sortedTypes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A simple script parser class to detect types declared within a script
|
||||
/// </summary>
|
||||
private class ScriptParser
|
||||
{
|
||||
/// <summary>
|
||||
/// Types that can be identified by the script parser
|
||||
/// </summary>
|
||||
public enum TypeName
|
||||
{
|
||||
Undefined,
|
||||
Namespace,
|
||||
Class,
|
||||
Struct,
|
||||
Interface,
|
||||
Enum,
|
||||
IdentationStart,
|
||||
IdentationEnd
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A class containing information about each block of a C# script
|
||||
/// </summary>
|
||||
/// <remarks> A block in this context is defined as script text that is contained within curly brackets.
|
||||
/// If it's a type, it may have a preceding name and a namespace
|
||||
/// </remarks>
|
||||
public class BlockInfo
|
||||
{
|
||||
public TypeName TypeName = TypeName.Undefined;
|
||||
public string Name = string.Empty;
|
||||
public string FullName = string.Empty;
|
||||
public string Namespace = string.Empty;
|
||||
public int FoundIndex;
|
||||
public int StartIndex;
|
||||
|
||||
public BlockInfo ParentBlock;
|
||||
|
||||
public string GetReflectionFriendlyFullName()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(FullName);
|
||||
for (int i = sb.Length - 1; i >= Namespace.Length + 1; i--)
|
||||
if (sb[i] == '.')
|
||||
sb[i] = '+';
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private CancellationToken _token;
|
||||
|
||||
public ScriptParser(CancellationToken token)
|
||||
{
|
||||
_token = token;
|
||||
}
|
||||
|
||||
public bool GetTypesInScript(string text, out IList<BlockInfo> types)
|
||||
{
|
||||
types = null;
|
||||
|
||||
try
|
||||
{
|
||||
var sanitized = SanitizeScript(text);
|
||||
types = ScanForTypes(sanitized);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private string SanitizeScript(string source)
|
||||
{
|
||||
var sb = new StringBuilder(source);
|
||||
|
||||
// Remove comments and strings
|
||||
sb = RemoveStringsAndComments(sb);
|
||||
|
||||
// Replace newlines with spaces
|
||||
sb.Replace("\r", " ").Replace("\n", " ");
|
||||
|
||||
// Space out the brackets
|
||||
sb.Replace("{", " { ").Replace("}", " } ");
|
||||
|
||||
// Insert a space at the start for more convenient parsing
|
||||
sb.Insert(0, " ");
|
||||
|
||||
// Remove repeating spaces
|
||||
var sanitized = Regex.Replace(sb.ToString(), @"\s{2,}", " ");
|
||||
|
||||
return sanitized;
|
||||
}
|
||||
|
||||
private StringBuilder RemoveStringsAndComments(StringBuilder sb)
|
||||
{
|
||||
void CheckStringIdentifiers(int index, out bool isVerbatim, out bool isInterpolated)
|
||||
{
|
||||
isVerbatim = false;
|
||||
isInterpolated = false;
|
||||
|
||||
string precedingChars = string.Empty;
|
||||
for (int i = index - 1; i >= 0; i--)
|
||||
{
|
||||
if (sb[i] == ' ')
|
||||
break;
|
||||
precedingChars += sb[i];
|
||||
}
|
||||
|
||||
if (precedingChars.Contains("@"))
|
||||
isVerbatim = true;
|
||||
if (precedingChars.Contains("$"))
|
||||
isInterpolated = true;
|
||||
}
|
||||
|
||||
bool IsRegion(int index)
|
||||
{
|
||||
if (sb.Length - index < "#region".Length)
|
||||
return false;
|
||||
if (sb[index] == '#' && sb[index + 1] == 'r' && sb[index + 2] == 'e' && sb[index + 3] == 'g' && sb[index + 4] == 'i' &&
|
||||
sb[index + 5] == 'o' && sb[index + 6] == 'n')
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
var removeRanges = new List<Tuple<int, int>>();
|
||||
|
||||
for (int i = 0; i < sb.Length; i++)
|
||||
{
|
||||
_token.ThrowIfCancellationRequested();
|
||||
|
||||
// Comment code
|
||||
if (sb[i] == '/')
|
||||
{
|
||||
if (sb[i + 1] == '/')
|
||||
{
|
||||
for (int j = i + 1; j < sb.Length; j++)
|
||||
{
|
||||
_token.ThrowIfCancellationRequested();
|
||||
if (sb[j] == '\n' || j == sb.Length - 1)
|
||||
{
|
||||
removeRanges.Add(new Tuple<int, int>(i, j - i + 1));
|
||||
i = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (sb[i + 1] == '*')
|
||||
{
|
||||
for (int j = i + 2; j < sb.Length; j++)
|
||||
{
|
||||
_token.ThrowIfCancellationRequested();
|
||||
if (sb[j] == '/' && sb[j - 1] == '*')
|
||||
{
|
||||
removeRanges.Add(new Tuple<int, int>(i, j - i + 1));
|
||||
i = j + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Char code
|
||||
else if (sb[i] == '\'')
|
||||
{
|
||||
for (int j = i + 1; j < sb.Length; j++)
|
||||
{
|
||||
_token.ThrowIfCancellationRequested();
|
||||
if (sb[j] == '\'')
|
||||
{
|
||||
if (sb[j - 1] == '\\')
|
||||
{
|
||||
int slashCount = 0;
|
||||
int k = j - 1;
|
||||
while (sb[k--] == '\\')
|
||||
slashCount++;
|
||||
if (slashCount % 2 != 0)
|
||||
continue;
|
||||
}
|
||||
removeRanges.Add(new Tuple<int, int>(i, j - i + 1));
|
||||
i = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// String code
|
||||
else if (sb[i] == '"')
|
||||
{
|
||||
if (sb[i - 1] == '\'' && sb[i + 1] == '\'' || (sb[i - 2] == '\'' && sb[i - 1] == '\\' && sb[i + 1] == '\''))
|
||||
continue;
|
||||
|
||||
CheckStringIdentifiers(i, out bool isVerbatim, out bool isInterpolated);
|
||||
|
||||
var bracketCount = 0;
|
||||
bool interpolationEnd = true;
|
||||
for (int j = i + 1; j < sb.Length; j++)
|
||||
{
|
||||
_token.ThrowIfCancellationRequested();
|
||||
if (isInterpolated && (sb[j] == '{' || sb[j] == '}'))
|
||||
{
|
||||
if (sb[j] == '{')
|
||||
{
|
||||
if (sb[j + 1] != '{')
|
||||
bracketCount++;
|
||||
else
|
||||
j += 1;
|
||||
}
|
||||
else if (sb[j] == '}')
|
||||
{
|
||||
if (sb[j + 1] != '}')
|
||||
bracketCount--;
|
||||
else
|
||||
j += 1;
|
||||
}
|
||||
|
||||
if (bracketCount == 0)
|
||||
interpolationEnd = true;
|
||||
else
|
||||
interpolationEnd = false;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sb[j] == '\"')
|
||||
{
|
||||
if (isVerbatim)
|
||||
{
|
||||
if (sb[j + 1] != '\"')
|
||||
{
|
||||
if (!isInterpolated || isInterpolated && interpolationEnd == true)
|
||||
{
|
||||
removeRanges.Add(new Tuple<int, int>(i, j - i + 1));
|
||||
i = j + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
j += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool endOfComment = false;
|
||||
if (sb[j - 1] != '\\')
|
||||
endOfComment = true;
|
||||
else
|
||||
{
|
||||
int slashCount = 0;
|
||||
int k = j - 1;
|
||||
while (sb[k--] == '\\')
|
||||
slashCount++;
|
||||
if (slashCount % 2 == 0)
|
||||
endOfComment = true;
|
||||
}
|
||||
|
||||
if (!isInterpolated && endOfComment || (isInterpolated && interpolationEnd && endOfComment))
|
||||
{
|
||||
removeRanges.Add(new Tuple<int, int>(i, j - i + 1));
|
||||
i = j + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Region code
|
||||
else if (IsRegion(i))
|
||||
{
|
||||
i += "#region".Length;
|
||||
for (int j = i; j < sb.Length; j++)
|
||||
{
|
||||
_token.ThrowIfCancellationRequested();
|
||||
if (sb[j] == '\n')
|
||||
{
|
||||
removeRanges.Add(new Tuple<int, int>(i, j - i + 1));
|
||||
i = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = removeRanges.Count - 1; i >= 0; i--)
|
||||
sb = sb.Remove(removeRanges[i].Item1, removeRanges[i].Item2);
|
||||
|
||||
return sb;
|
||||
}
|
||||
|
||||
private IList<BlockInfo> ScanForTypes(string script)
|
||||
{
|
||||
var typeList = new SortedList<int, BlockInfo>();
|
||||
BlockInfo currentActiveBlock = new BlockInfo();
|
||||
|
||||
int i = 0;
|
||||
|
||||
BlockInfo nextNamespace = null;
|
||||
BlockInfo nextClass = null;
|
||||
BlockInfo nextStruct = null;
|
||||
BlockInfo nextInterface = null;
|
||||
BlockInfo nextEnum = null;
|
||||
|
||||
while (i < script.Length)
|
||||
{
|
||||
_token.ThrowIfCancellationRequested();
|
||||
if (nextNamespace == null)
|
||||
nextNamespace = FindNextTypeBlock(script, i, TypeName.Namespace);
|
||||
if (nextClass == null)
|
||||
nextClass = FindNextTypeBlock(script, i, TypeName.Class);
|
||||
if (nextStruct == null)
|
||||
nextStruct = FindNextTypeBlock(script, i, TypeName.Struct);
|
||||
if (nextInterface == null)
|
||||
nextInterface = FindNextTypeBlock(script, i, TypeName.Interface);
|
||||
if (nextEnum == null)
|
||||
nextEnum = FindNextTypeBlock(script, i, TypeName.Enum);
|
||||
|
||||
var nextIdentationIncrease = FindNextTypeBlock(script, i, TypeName.IdentationStart);
|
||||
var nextIdentationDecrease = FindNextTypeBlock(script, i, TypeName.IdentationEnd);
|
||||
|
||||
if (!TryFindClosestBlock(out var closestBlock, nextNamespace, nextClass,
|
||||
nextStruct, nextInterface, nextEnum, nextIdentationIncrease, nextIdentationDecrease))
|
||||
break;
|
||||
|
||||
switch (closestBlock)
|
||||
{
|
||||
case var _ when closestBlock == nextIdentationIncrease:
|
||||
closestBlock.ParentBlock = currentActiveBlock;
|
||||
currentActiveBlock = closestBlock;
|
||||
break;
|
||||
case var _ when closestBlock == nextIdentationDecrease:
|
||||
if (currentActiveBlock.TypeName != TypeName.Undefined)
|
||||
typeList.Add(currentActiveBlock.StartIndex, currentActiveBlock);
|
||||
currentActiveBlock = currentActiveBlock.ParentBlock;
|
||||
break;
|
||||
case var _ when closestBlock == nextNamespace:
|
||||
closestBlock.Namespace = currentActiveBlock.TypeName == TypeName.Namespace ? currentActiveBlock.FullName : currentActiveBlock.Namespace;
|
||||
closestBlock.FullName = string.IsNullOrEmpty(currentActiveBlock.FullName) ? closestBlock.Name : $"{currentActiveBlock.FullName}.{closestBlock.Name}";
|
||||
closestBlock.ParentBlock = currentActiveBlock;
|
||||
currentActiveBlock = closestBlock;
|
||||
nextNamespace = null;
|
||||
break;
|
||||
case var _ when closestBlock == nextClass:
|
||||
case var _ when closestBlock == nextStruct:
|
||||
case var _ when closestBlock == nextInterface:
|
||||
case var _ when closestBlock == nextEnum:
|
||||
closestBlock.FullName = string.IsNullOrEmpty(currentActiveBlock.FullName) ? closestBlock.Name : $"{currentActiveBlock.FullName}.{closestBlock.Name}";
|
||||
closestBlock.Namespace = currentActiveBlock.TypeName == TypeName.Namespace ? currentActiveBlock.FullName : currentActiveBlock.Namespace;
|
||||
closestBlock.ParentBlock = currentActiveBlock;
|
||||
currentActiveBlock = closestBlock;
|
||||
switch (closestBlock)
|
||||
{
|
||||
case var _ when closestBlock == nextClass:
|
||||
nextClass = null;
|
||||
break;
|
||||
case var _ when closestBlock == nextStruct:
|
||||
nextStruct = null;
|
||||
break;
|
||||
case var _ when closestBlock == nextInterface:
|
||||
nextInterface = null;
|
||||
break;
|
||||
case var _ when closestBlock == nextEnum:
|
||||
nextEnum = null;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
i = closestBlock.StartIndex;
|
||||
}
|
||||
|
||||
return typeList.Select(x => x.Value).ToList();
|
||||
}
|
||||
|
||||
private bool TryFindClosestBlock(out BlockInfo closestBlock, params BlockInfo[] blocks)
|
||||
{
|
||||
closestBlock = null;
|
||||
for (int i = 0; i < blocks.Length; i++)
|
||||
{
|
||||
if (blocks[i].FoundIndex == -1)
|
||||
continue;
|
||||
|
||||
if (closestBlock == null || closestBlock.FoundIndex > blocks[i].FoundIndex)
|
||||
closestBlock = blocks[i];
|
||||
}
|
||||
|
||||
return closestBlock != null;
|
||||
}
|
||||
|
||||
private BlockInfo FindNextTypeBlock(string text, int startIndex, TypeName blockType)
|
||||
{
|
||||
string typeKeyword;
|
||||
switch (blockType)
|
||||
{
|
||||
case TypeName.Namespace:
|
||||
typeKeyword = "namespace";
|
||||
break;
|
||||
case TypeName.Class:
|
||||
typeKeyword = "class";
|
||||
break;
|
||||
case TypeName.Struct:
|
||||
typeKeyword = "struct";
|
||||
break;
|
||||
case TypeName.Interface:
|
||||
typeKeyword = "interface";
|
||||
break;
|
||||
case TypeName.Enum:
|
||||
typeKeyword = "enum";
|
||||
break;
|
||||
case TypeName.IdentationStart:
|
||||
var identationStart = text.IndexOf("{", startIndex);
|
||||
return new BlockInfo() { FoundIndex = identationStart, StartIndex = identationStart + 1, TypeName = TypeName.Undefined };
|
||||
case TypeName.IdentationEnd:
|
||||
var identationEnd = text.IndexOf("}", startIndex);
|
||||
return new BlockInfo() { FoundIndex = identationEnd, StartIndex = identationEnd + 1, TypeName = TypeName.Undefined };
|
||||
default:
|
||||
throw new ArgumentException("Invalid block type provided");
|
||||
}
|
||||
|
||||
int start = -1;
|
||||
int blockStart = -1;
|
||||
string name = string.Empty;
|
||||
while (startIndex < text.Length)
|
||||
{
|
||||
_token.ThrowIfCancellationRequested();
|
||||
start = text.IndexOf($" {typeKeyword} ", startIndex);
|
||||
if (start == -1)
|
||||
return new BlockInfo { FoundIndex = -1 };
|
||||
|
||||
// Check if the caught type keyword matches the type definition
|
||||
var openingBracket = text.IndexOf("{", start);
|
||||
if (openingBracket == -1)
|
||||
return new BlockInfo { FoundIndex = -1 };
|
||||
|
||||
var declaration = text.Substring(start, openingBracket - start);
|
||||
var split = declaration.Split(' ');
|
||||
|
||||
// Namespace detection
|
||||
if (typeKeyword == "namespace")
|
||||
{
|
||||
// Expected result: [null] [namespace] [null]
|
||||
if (split.Length == 4)
|
||||
{
|
||||
name = split[2];
|
||||
blockStart = openingBracket + 1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
startIndex = openingBracket + 1;
|
||||
}
|
||||
// Class, Interface, Struct, Enum detection
|
||||
else
|
||||
{
|
||||
// Expected result: [null] [keywordName] [typeName] ... [null]
|
||||
// Skip any keywords that only contains [null] [keywordName] [null]
|
||||
if (split.Length != 3)
|
||||
{
|
||||
name = split[2];
|
||||
blockStart = openingBracket + 1;
|
||||
break;
|
||||
}
|
||||
else
|
||||
startIndex = openingBracket + 1;
|
||||
}
|
||||
}
|
||||
|
||||
var info = new BlockInfo() { FoundIndex = start, StartIndex = blockStart, Name = name, TypeName = blockType };
|
||||
return info;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9db4298044e2add44bc3aa6ba898d7c3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 115
|
||||
packageName: Asset Store Publishing Tools
|
||||
packageVersion: 12.0.1
|
||||
assetPath: Packages/com.unity.asset-store-tools/Editor/Validator/Scripts/Services/Validation/ScriptUtilityService.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,24 @@
|
||||
using AssetStoreTools.Utility;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
|
||||
namespace AssetStoreTools.Validator.Services
|
||||
{
|
||||
internal class ValidatorServiceProvider : ServiceProvider<IValidatorService>
|
||||
{
|
||||
public static ValidatorServiceProvider Instance => _instance ?? (_instance = new ValidatorServiceProvider());
|
||||
private static ValidatorServiceProvider _instance;
|
||||
|
||||
private ValidatorServiceProvider() { }
|
||||
|
||||
protected override void RegisterServices()
|
||||
{
|
||||
Register<ICachingService, CachingService>();
|
||||
Register<IAssetUtilityService, AssetUtilityService>();
|
||||
Register<IFileSignatureUtilityService, FileSignatureUtilityService>();
|
||||
Register<IMeshUtilityService, MeshUtilityService>();
|
||||
Register<IModelUtilityService, ModelUtilityService>();
|
||||
Register<ISceneUtilityService, SceneUtilityService>();
|
||||
Register<IScriptUtilityService, ScriptUtilityService>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47ac495c61171824abb2b72b1b7ef676
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 115
|
||||
packageName: Asset Store Publishing Tools
|
||||
packageVersion: 12.0.1
|
||||
assetPath: Packages/com.unity.asset-store-tools/Editor/Validator/Scripts/Services/ValidatorServiceProvider.cs
|
||||
uploadId: 724584
|
||||
Reference in New Issue
Block a user