update libs
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ecfb23f95f16d2347a4063411aad8063
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,64 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityObject = UnityEngine.Object;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class CheckAnimationClips : ITestScript
|
||||
{
|
||||
private static readonly string[] InvalidNames = new[] { "Take 001" };
|
||||
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
|
||||
public CheckAnimationClips(GenericTestConfig config, IAssetUtilityService assetUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
var badModels = new Dictionary<UnityObject, List<UnityObject>>();
|
||||
var models = _assetUtility.GetObjectsFromAssets<UnityObject>(_config.ValidationPaths, AssetType.Model);
|
||||
|
||||
foreach (var model in models)
|
||||
{
|
||||
var badClips = new List<UnityObject>();
|
||||
var clips = AssetDatabase.LoadAllAssetsAtPath(_assetUtility.ObjectToAssetPath(model));
|
||||
foreach (var clip in clips)
|
||||
{
|
||||
if (InvalidNames.Any(x => x.ToLower().Equals(clip.name.ToLower())))
|
||||
{
|
||||
badClips.Add(clip);
|
||||
}
|
||||
}
|
||||
|
||||
if (badClips.Count > 0)
|
||||
badModels.Add(model, badClips);
|
||||
}
|
||||
|
||||
if (badModels.Count > 0)
|
||||
{
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following models have animation clips with invalid names. Animation clip names should be unique and reflective of the animation itself");
|
||||
foreach (var kvp in badModels)
|
||||
{
|
||||
result.AddMessage(_assetUtility.ObjectToAssetPath(kvp.Key), null, kvp.Value.ToArray());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.AddMessage("No animation clips with invalid names were found!");
|
||||
result.Status = TestResultStatus.Pass;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7a28985886f182c4bacc89a44777c742
|
||||
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/Test Methods/Generic/CheckAnimationClips.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,128 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class CheckAudioClipping : ITestScript
|
||||
{
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
|
||||
public CheckAudioClipping(GenericTestConfig config, IAssetUtilityService assetUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
// How many peaks above threshold are required for Audio Clips to be considered clipping
|
||||
const int TOLERANCE = 2;
|
||||
// Min. amount of consecutive samples above threshold required for peak detection
|
||||
const int PEAK_STEPS = 1;
|
||||
// Clipping threshold. More lenient here than Submission Guidelines (-0.3db) due to the problematic nature of
|
||||
// correctly determining how sensitive the audio clipping flagging should be, as well as to account for any
|
||||
// distortion introduced when AudioClips are compresssed after importing to Unity.
|
||||
const float THRESHOLD = -0.05f;
|
||||
// Samples for 16-bit audio files
|
||||
const float S16b = 32767f;
|
||||
float clippingThreshold = (S16b - (S16b / (2 * Mathf.Log10(1 / S16b)) * THRESHOLD)) / S16b;
|
||||
TestResult result = new TestResult();
|
||||
var clippingAudioClips = new Dictionary<AudioClip, string>();
|
||||
|
||||
var losslessAudioClips = _assetUtility.GetObjectsFromAssets(_config.ValidationPaths, AssetType.NonLossyAudio).Select(x => x as AudioClip).ToList();
|
||||
foreach (var clip in losslessAudioClips)
|
||||
{
|
||||
var path = AssetDatabase.GetAssetPath(clip.GetInstanceID());
|
||||
|
||||
if (IsClipping(clip, TOLERANCE, PEAK_STEPS, clippingThreshold))
|
||||
clippingAudioClips.Add(clip, path);
|
||||
}
|
||||
|
||||
var lossyAudioClips = _assetUtility.GetObjectsFromAssets(_config.ValidationPaths, AssetType.LossyAudio).Select(x => x as AudioClip).ToList();
|
||||
foreach (var clip in lossyAudioClips)
|
||||
{
|
||||
var path = AssetDatabase.GetAssetPath(clip.GetInstanceID());
|
||||
|
||||
if (IsClipping(clip, TOLERANCE, PEAK_STEPS, clippingThreshold))
|
||||
clippingAudioClips.Add(clip, path);
|
||||
}
|
||||
|
||||
if (clippingAudioClips.Count > 0)
|
||||
{
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following AudioClips are clipping or are very close to 0db ceiling. Please ensure your exported audio files have at least 0.3db of headroom (should peak at no more than -0.3db):", null, clippingAudioClips.Select(x => x.Key).ToArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("No clipping audio files were detected.");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool IsClipping(AudioClip clip, int tolerance, int peakTolerance, float clippingThreshold)
|
||||
{
|
||||
if (DetectNumPeaksAboveThreshold(clip, peakTolerance, clippingThreshold) >= tolerance)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private int DetectNumPeaksAboveThreshold(AudioClip clip, int peakTolerance, float clippingThreshold)
|
||||
{
|
||||
float[] samples = new float[clip.samples * clip.channels];
|
||||
var data = clip.GetData(samples, 0);
|
||||
|
||||
float[] samplesLeft = samples.Where((s, i) => i % 2 == 0).ToArray();
|
||||
float[] samplesRight = samples.Where((s, i) => i % 2 == 1).ToArray();
|
||||
|
||||
int peaks = 0;
|
||||
|
||||
peaks = GetPeaksInChannel(samplesLeft, peakTolerance, clippingThreshold) +
|
||||
GetPeaksInChannel(samplesRight, peakTolerance, clippingThreshold);
|
||||
|
||||
return peaks;
|
||||
}
|
||||
|
||||
private int GetPeaksInChannel(float[] samples, int peakTolerance, float clippingThreshold)
|
||||
{
|
||||
int peaks = 0;
|
||||
bool evalPeak = false;
|
||||
int peakSteps = 0;
|
||||
int step = 0;
|
||||
|
||||
while (step < samples.Length)
|
||||
{
|
||||
if (Mathf.Abs(samples[step]) >= clippingThreshold && evalPeak)
|
||||
{
|
||||
peakSteps++;
|
||||
}
|
||||
|
||||
if (Mathf.Abs(samples[step]) >= clippingThreshold && !evalPeak)
|
||||
{
|
||||
evalPeak = true;
|
||||
peakSteps++;
|
||||
}
|
||||
|
||||
if (Mathf.Abs(samples[step]) < clippingThreshold && evalPeak)
|
||||
{
|
||||
evalPeak = false;
|
||||
if (peakSteps >= peakTolerance)
|
||||
peaks++;
|
||||
peakSteps = 0;
|
||||
}
|
||||
|
||||
step++;
|
||||
}
|
||||
|
||||
return peaks;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f604db0353da0cb46bb048f5cd37186f
|
||||
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/Test Methods/Generic/CheckAudioClipping.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,55 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class CheckColliders : ITestScript
|
||||
{
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
private IMeshUtilityService _meshUtility;
|
||||
|
||||
public CheckColliders(GenericTestConfig config, IAssetUtilityService assetUtility, IMeshUtilityService meshUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
_meshUtility = meshUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var prefabs = _assetUtility.GetObjectsFromAssets<GameObject>(_config.ValidationPaths, AssetType.Prefab);
|
||||
var badPrefabs = new List<GameObject>();
|
||||
|
||||
foreach (var p in prefabs)
|
||||
{
|
||||
var meshes = _meshUtility.GetCustomMeshesInObject(p);
|
||||
|
||||
if (!p.isStatic || !meshes.Any())
|
||||
continue;
|
||||
|
||||
var colliders = p.GetComponentsInChildren<Collider>(true);
|
||||
if (!colliders.Any())
|
||||
badPrefabs.Add(p);
|
||||
}
|
||||
|
||||
if (badPrefabs.Count == 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("All found prefabs have colliders!");
|
||||
return result;
|
||||
}
|
||||
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following prefabs contain meshes, but colliders were not found", null, badPrefabs.ToArray());
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 308b3d7b7a883b949a14f47cfd5c7ebe
|
||||
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/Test Methods/Generic/CheckColliders.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,121 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityObject = UnityEngine.Object;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class CheckCompressedFiles : ITestScript
|
||||
{
|
||||
private enum ArchiveResult
|
||||
{
|
||||
Allowed,
|
||||
NotAllowed,
|
||||
TarGzWithIssues,
|
||||
ZipWithIssues
|
||||
}
|
||||
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
private IFileSignatureUtilityService _fileSignatureUtility;
|
||||
|
||||
public CheckCompressedFiles(GenericTestConfig config, IAssetUtilityService assetUtility, IFileSignatureUtilityService fileSignatureUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
_fileSignatureUtility = fileSignatureUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var checkedArchives = new Dictionary<UnityObject, ArchiveResult>();
|
||||
|
||||
// Retrieving assets via GetObjectsFromAssets() is insufficient because
|
||||
// archives might be renamed and not use the expected extension
|
||||
var allAssetPaths = _assetUtility.GetAssetPathsFromAssets(_config.ValidationPaths, AssetType.All);
|
||||
|
||||
foreach (var assetPath in allAssetPaths)
|
||||
{
|
||||
ArchiveType archiveType;
|
||||
if ((archiveType = _fileSignatureUtility.GetArchiveType(assetPath)) == ArchiveType.None)
|
||||
continue;
|
||||
|
||||
var archiveObj = _assetUtility.AssetPathToObject(assetPath);
|
||||
|
||||
switch (archiveType)
|
||||
{
|
||||
case ArchiveType.TarGz:
|
||||
if (assetPath.ToLower().EndsWith(".unitypackage"))
|
||||
checkedArchives.Add(archiveObj, ArchiveResult.Allowed);
|
||||
else
|
||||
checkedArchives.Add(archiveObj, ArchiveResult.TarGzWithIssues);
|
||||
break;
|
||||
case ArchiveType.Zip:
|
||||
if (FileNameContainsKeyword(assetPath, "source") && assetPath.ToLower().EndsWith(".zip"))
|
||||
checkedArchives.Add(archiveObj, ArchiveResult.Allowed);
|
||||
else
|
||||
checkedArchives.Add(archiveObj, ArchiveResult.ZipWithIssues);
|
||||
break;
|
||||
default:
|
||||
checkedArchives.Add(archiveObj, ArchiveResult.NotAllowed);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (checkedArchives.Count == 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("No archives were found in the package content!");
|
||||
return result;
|
||||
}
|
||||
|
||||
if (checkedArchives.Any(x => x.Value == ArchiveResult.Allowed))
|
||||
{
|
||||
result.Status = TestResultStatus.Warning;
|
||||
result.AddMessage("The following archives of allowed format were found in the package content.\n" +
|
||||
"Please make sure they adhere to the nested archive guidelines:", null,
|
||||
checkedArchives.Where(x => x.Value == ArchiveResult.Allowed).Select(x => x.Key).ToArray());
|
||||
}
|
||||
|
||||
if (checkedArchives.Any(x => x.Value == ArchiveResult.TarGzWithIssues))
|
||||
{
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following .gz archives were found in the package content.\n" +
|
||||
"<22> Gz archives are only allowed in form of '.unitypackage' files", null,
|
||||
checkedArchives.Where(x => x.Value == ArchiveResult.TarGzWithIssues).Select(x => x.Key).ToArray());
|
||||
}
|
||||
|
||||
if (checkedArchives.Any(x => x.Value == ArchiveResult.ZipWithIssues))
|
||||
{
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following .zip archives were found in the package content.\n" +
|
||||
"<22> Zip archives should contain the keyword 'source' in the file name", null,
|
||||
checkedArchives.Where(x => x.Value == ArchiveResult.ZipWithIssues).Select(x => x.Key).ToArray());
|
||||
}
|
||||
|
||||
if (checkedArchives.Any(x => x.Value == ArchiveResult.NotAllowed))
|
||||
{
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following archives are using formats that are not allowed:", null,
|
||||
checkedArchives.Where(x => x.Value == ArchiveResult.NotAllowed).Select(x => x.Key).ToArray());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool FileNameContainsKeyword(string filePath, string keyword)
|
||||
{
|
||||
var fileInfo = new FileInfo(filePath);
|
||||
|
||||
if (!fileInfo.Exists)
|
||||
return false;
|
||||
|
||||
return fileInfo.Name.Remove(fileInfo.Name.Length - fileInfo.Extension.Length).ToLower().Contains(keyword.ToLower());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 84b23febe0d923842aef73b95da5f25b
|
||||
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/Test Methods/Generic/CheckCompressedFiles.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,46 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class CheckEmptyPrefabs : ITestScript
|
||||
{
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
|
||||
public CheckEmptyPrefabs(GenericTestConfig config, IAssetUtilityService assetUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var prefabs = _assetUtility.GetObjectsFromAssets<GameObject>(_config.ValidationPaths, AssetType.Prefab);
|
||||
var badPrefabs = new List<GameObject>();
|
||||
|
||||
foreach (var p in prefabs)
|
||||
{
|
||||
if (p.GetComponents<Component>().Length == 1 && p.transform.childCount == 0)
|
||||
badPrefabs.Add(p);
|
||||
}
|
||||
|
||||
if (badPrefabs.Count == 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("No empty prefabs were found!");
|
||||
return result;
|
||||
}
|
||||
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following prefabs are empty", null, badPrefabs.ToArray());
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8055bed9373283e4793463b90b42f08f
|
||||
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/Test Methods/Generic/CheckEmptyPrefabs.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,153 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityObject = UnityEngine.Object;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class CheckFileMenuNames : ITestScript
|
||||
{
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
private IScriptUtilityService _scriptUtility;
|
||||
|
||||
public CheckFileMenuNames(GenericTestConfig config, IAssetUtilityService assetUtility, IScriptUtilityService scriptUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
_scriptUtility = scriptUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic |
|
||||
BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly;
|
||||
|
||||
#region Scripts
|
||||
|
||||
var scripts = _assetUtility.GetObjectsFromAssets<MonoScript>(_config.ValidationPaths, AssetType.MonoScript).ToArray();
|
||||
var scriptTypes = _scriptUtility.GetTypesFromScriptAssets(scripts);
|
||||
var affectedScripts = new Dictionary<MonoScript, List<string>>();
|
||||
|
||||
foreach (var kvp in scriptTypes)
|
||||
{
|
||||
var badMethods = new List<string>();
|
||||
foreach (var type in kvp.Value)
|
||||
{
|
||||
foreach (var method in type.GetMethods(bindingFlags))
|
||||
{
|
||||
var attributes = method.GetCustomAttributes<MenuItem>().ToList();
|
||||
if (attributes.Count == 0)
|
||||
continue;
|
||||
|
||||
var badAttributes = attributes.Where(x => !IsValidMenuItem(x.menuItem)).ToList();
|
||||
if (badAttributes.Count > 0)
|
||||
badMethods.Add($"{string.Join("\n", badAttributes.Select(x => $"\'{x.menuItem}\'"))}\n(for method '{method.Name}')\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (badMethods.Count > 0)
|
||||
affectedScripts.Add(kvp.Key, badMethods);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Precompiled Assemblies
|
||||
|
||||
var assemblies = _assetUtility.GetObjectsFromAssets(_config.ValidationPaths, AssetType.PrecompiledAssembly).ToArray();
|
||||
var assemblyTypes = _scriptUtility.GetTypesFromAssemblies(assemblies);
|
||||
var affectedAssemblies = new Dictionary<UnityObject, List<string>>();
|
||||
|
||||
foreach (var kvp in assemblyTypes)
|
||||
{
|
||||
var badMethods = new List<string>();
|
||||
foreach (var type in kvp.Value)
|
||||
{
|
||||
foreach (var method in type.GetMethods(bindingFlags))
|
||||
{
|
||||
var attributes = method.GetCustomAttributes<MenuItem>().ToList();
|
||||
if (attributes.Count == 0)
|
||||
continue;
|
||||
|
||||
var badAttributes = attributes.Where(x => !IsValidMenuItem(x.menuItem)).ToList();
|
||||
if (badAttributes.Count > 0)
|
||||
badMethods.Add($"{string.Join("\n", badAttributes.Select(x => (x as MenuItem).menuItem))}\n(Method '{method.Name}')\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (badMethods.Count > 0)
|
||||
affectedAssemblies.Add(kvp.Key, badMethods);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
if (affectedScripts.Count > 0 || affectedAssemblies.Count > 0)
|
||||
{
|
||||
if (affectedScripts.Count > 0)
|
||||
{
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following scripts contain invalid MenuItem names:");
|
||||
foreach (var kvp in affectedScripts)
|
||||
{
|
||||
var message = string.Empty;
|
||||
foreach (var type in kvp.Value)
|
||||
message += type + "\n";
|
||||
|
||||
message = message.Remove(message.Length - "\n".Length);
|
||||
result.AddMessage(message, null, kvp.Key);
|
||||
}
|
||||
}
|
||||
|
||||
if (affectedAssemblies.Count > 0)
|
||||
{
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following assemblies contain invalid MenuItem names:");
|
||||
foreach (var kvp in affectedAssemblies)
|
||||
{
|
||||
var message = string.Empty;
|
||||
foreach (var type in kvp.Value)
|
||||
message += type + "\n";
|
||||
|
||||
message = message.Remove(message.Length - "\n".Length);
|
||||
result.AddMessage(message, null, kvp.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("No MenuItems with invalid names were found!");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool IsValidMenuItem(string menuItemName)
|
||||
{
|
||||
var acceptableMenuItems = new string[]
|
||||
{
|
||||
"File",
|
||||
"Edit",
|
||||
"Assets",
|
||||
"GameObject",
|
||||
"Component",
|
||||
"Window",
|
||||
"Help",
|
||||
"CONTEXT",
|
||||
"Tools"
|
||||
};
|
||||
|
||||
menuItemName = menuItemName.Replace("\\", "/");
|
||||
if (acceptableMenuItems.Any(x => menuItemName.ToLower().StartsWith($"{x.ToLower()}/")))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d8e3b12ecc1fcd74d9a9f8d2b549fc63
|
||||
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/Test Methods/Generic/CheckFileMenuNames.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,79 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Data.MessageActions;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class CheckLODs : ITestScript
|
||||
{
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
|
||||
public CheckLODs(GenericTestConfig config, IAssetUtilityService assetUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var prefabs = _assetUtility.GetObjectsFromAssets<GameObject>(_config.ValidationPaths, AssetType.Prefab);
|
||||
var badPrefabs = new Dictionary<GameObject, List<MeshFilter>>();
|
||||
|
||||
foreach (var p in prefabs)
|
||||
{
|
||||
var meshFilters = p.GetComponentsInChildren<MeshFilter>(true);
|
||||
var badMeshFilters = new List<MeshFilter>();
|
||||
var lodGroups = p.GetComponentsInChildren<LODGroup>(true);
|
||||
|
||||
foreach (var mf in meshFilters)
|
||||
{
|
||||
if (mf.name.Contains("LOD") && !IsPartOfLodGroup(mf, lodGroups))
|
||||
badMeshFilters.Add(mf);
|
||||
}
|
||||
|
||||
if (badMeshFilters.Count > 0)
|
||||
badPrefabs.Add(p, badMeshFilters);
|
||||
}
|
||||
|
||||
if (badPrefabs.Count == 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("All found prefabs are meeting the LOD requirements!");
|
||||
return result;
|
||||
}
|
||||
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following prefabs do not meet the LOD requirements");
|
||||
|
||||
foreach (var p in badPrefabs)
|
||||
{
|
||||
var resultList = new List<Object>();
|
||||
resultList.Add(p.Key);
|
||||
resultList.AddRange(p.Value);
|
||||
result.AddMessage($"{p.Key.name}.prefab", new OpenAssetAction(p.Key), resultList.ToArray());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool IsPartOfLodGroup(MeshFilter mf, LODGroup[] lodGroups)
|
||||
{
|
||||
foreach (var lodGroup in lodGroups)
|
||||
{
|
||||
// If MeshFilter is a child/deep child of a LodGroup AND is referenced in this LOD group - it is valid
|
||||
if (mf.transform.IsChildOf(lodGroup.transform) &&
|
||||
lodGroup.GetLODs().Any(lod => lod.renderers.Any(renderer => renderer != null && renderer.gameObject == mf.gameObject)))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 43b2158602f87704fa7b91561cfc8678
|
||||
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/Test Methods/Generic/CheckLODs.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,77 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEditor;
|
||||
using UnityObject = UnityEngine.Object;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class CheckLineEndings : ITestScript
|
||||
{
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
|
||||
public CheckLineEndings(GenericTestConfig config, IAssetUtilityService assetUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var scripts = _assetUtility.GetObjectsFromAssets<MonoScript>(_config.ValidationPaths, AssetType.MonoScript);
|
||||
|
||||
var affectedScripts = new ConcurrentBag<UnityObject>();
|
||||
var scriptContents = new ConcurrentDictionary<MonoScript, string>();
|
||||
|
||||
// A separate dictionary is needed because MonoScript contents cannot be accessed outside of the main thread
|
||||
foreach (var s in scripts)
|
||||
if (s != null)
|
||||
scriptContents.TryAdd(s, s.text);
|
||||
|
||||
Parallel.ForEach(scriptContents, (s) =>
|
||||
{
|
||||
if (HasInconsistentLineEndings(s.Value))
|
||||
affectedScripts.Add(s.Key);
|
||||
});
|
||||
|
||||
if (affectedScripts.Count > 0)
|
||||
{
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following scripts have inconsistent line endings:", null, affectedScripts.ToArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("No scripts with inconsistent line endings were found!");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool HasInconsistentLineEndings(string text)
|
||||
{
|
||||
int crlfEndings = 0;
|
||||
int lfEndings = 0;
|
||||
|
||||
var split = text.Split(new[] { "\n" }, StringSplitOptions.None);
|
||||
for (int i = 0; i < split.Length; i++)
|
||||
{
|
||||
var line = split[i];
|
||||
if (line.EndsWith("\r"))
|
||||
crlfEndings++;
|
||||
else if (i != split.Length - 1)
|
||||
lfEndings++;
|
||||
}
|
||||
|
||||
if (crlfEndings > 0 && lfEndings > 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 85885005d1c594f42826de3555e98365
|
||||
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/Test Methods/Generic/CheckLineEndings.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,106 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class CheckMeshPrefabs : ITestScript
|
||||
{
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
private IMeshUtilityService _meshUtility;
|
||||
|
||||
public CheckMeshPrefabs(GenericTestConfig config, IAssetUtilityService assetUtility, IMeshUtilityService meshUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
_meshUtility = meshUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var usedModelPaths = new List<string>();
|
||||
var prefabs = _assetUtility.GetObjectsFromAssets<GameObject>(_config.ValidationPaths, AssetType.Prefab);
|
||||
var missingMeshReferencePrefabs = new List<GameObject>();
|
||||
|
||||
// Get all meshes in existing prefabs and check if prefab has missing mesh references
|
||||
foreach (var p in prefabs)
|
||||
{
|
||||
var meshes = _meshUtility.GetCustomMeshesInObject(p);
|
||||
foreach (var mesh in meshes)
|
||||
{
|
||||
string meshPath = _assetUtility.ObjectToAssetPath(mesh);
|
||||
usedModelPaths.Add(meshPath);
|
||||
}
|
||||
|
||||
if (HasMissingMeshReferences(p))
|
||||
missingMeshReferencePrefabs.Add(p);
|
||||
}
|
||||
|
||||
// Get all meshes in existing models
|
||||
var allModelPaths = GetAllModelMeshPaths(_config.ValidationPaths);
|
||||
|
||||
// Get the list of meshes without prefabs
|
||||
List<string> unusedModels = allModelPaths.Except(usedModelPaths).ToList();
|
||||
|
||||
if (unusedModels.Count == 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("All found prefabs have meshes!");
|
||||
return result;
|
||||
}
|
||||
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
var models = unusedModels.Select(_assetUtility.AssetPathToObject).ToArray();
|
||||
result.AddMessage("The following models do not have associated prefabs", null, models);
|
||||
|
||||
if (missingMeshReferencePrefabs.Count > 0)
|
||||
result.AddMessage("The following prefabs have missing mesh references", null, missingMeshReferencePrefabs.ToArray());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private IEnumerable<string> GetAllModelMeshPaths(string[] validationPaths)
|
||||
{
|
||||
var models = _assetUtility.GetObjectsFromAssets(validationPaths, AssetType.Model);
|
||||
var paths = new List<string>();
|
||||
|
||||
foreach (var o in models)
|
||||
{
|
||||
var m = (GameObject)o;
|
||||
var modelPath = _assetUtility.ObjectToAssetPath(m);
|
||||
var assetImporter = _assetUtility.GetAssetImporter(modelPath);
|
||||
if (assetImporter is UnityEditor.ModelImporter modelImporter)
|
||||
{
|
||||
var clips = modelImporter.clipAnimations.Count();
|
||||
var meshes = _meshUtility.GetCustomMeshesInObject(m);
|
||||
|
||||
// Only add if the model has meshes and no clips
|
||||
if (meshes.Any() && clips == 0)
|
||||
paths.Add(modelPath);
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
private bool HasMissingMeshReferences(GameObject go)
|
||||
{
|
||||
var meshes = go.GetComponentsInChildren<MeshFilter>(true);
|
||||
var skinnedMeshes = go.GetComponentsInChildren<SkinnedMeshRenderer>(true);
|
||||
|
||||
if (meshes.Length == 0 && skinnedMeshes.Length == 0)
|
||||
return false;
|
||||
|
||||
if (meshes.Any(x => x.sharedMesh == null) || skinnedMeshes.Any(x => x.sharedMesh == null))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3c3d0d642ac6a6a48aa124a93dae3734
|
||||
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/Test Methods/Generic/CheckMeshPrefabs.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,66 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class CheckMissingComponentsinAssets : ITestScript
|
||||
{
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
|
||||
public CheckMissingComponentsinAssets(GenericTestConfig config, IAssetUtilityService assetUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var assets = GetAllAssetsWithMissingComponents(_config.ValidationPaths);
|
||||
|
||||
if (assets.Length == 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("No assets have missing components!");
|
||||
return result;
|
||||
}
|
||||
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following assets contain missing components", null, assets);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private GameObject[] GetAllAssetsWithMissingComponents(string[] validationPaths)
|
||||
{
|
||||
var missingReferenceAssets = new List<GameObject>();
|
||||
var prefabObjects = _assetUtility.GetObjectsFromAssets<GameObject>(validationPaths, AssetType.Prefab);
|
||||
|
||||
foreach (var p in prefabObjects)
|
||||
{
|
||||
if (p != null && IsMissingReference(p))
|
||||
missingReferenceAssets.Add(p);
|
||||
}
|
||||
|
||||
return missingReferenceAssets.ToArray();
|
||||
}
|
||||
|
||||
private bool IsMissingReference(GameObject asset)
|
||||
{
|
||||
var components = asset.GetComponentsInChildren<Component>();
|
||||
|
||||
foreach (var c in components)
|
||||
{
|
||||
if (!c)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 22d8f814e2363e34ea220736a4042728
|
||||
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/Test Methods/Generic/CheckMissingComponentsinAssets.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,93 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Data.MessageActions;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using SceneAsset = UnityEditor.SceneAsset;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class CheckMissingComponentsinScenes : ITestScript
|
||||
{
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
private ISceneUtilityService _sceneUtility;
|
||||
|
||||
public CheckMissingComponentsinScenes(GenericTestConfig config, IAssetUtilityService assetUtility, ISceneUtilityService sceneUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
_sceneUtility = sceneUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var originalScenePath = _sceneUtility.CurrentScenePath;
|
||||
|
||||
var scenePaths = _assetUtility.GetAssetPathsFromAssets(_config.ValidationPaths, AssetType.Scene);
|
||||
foreach (var scenePath in scenePaths)
|
||||
{
|
||||
var missingComponentGOs = GetMissingComponentGOsInScene(scenePath);
|
||||
|
||||
if (missingComponentGOs.Count == 0)
|
||||
continue;
|
||||
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
var message = $"GameObjects with missing components or prefab references found in {scenePath}.\n\nClick this message to open the Scene and see the affected GameObjects:";
|
||||
result.AddMessage(message, new OpenAssetAction(_assetUtility.AssetPathToObject<SceneAsset>(scenePath)), missingComponentGOs.ToArray());
|
||||
}
|
||||
|
||||
_sceneUtility.OpenScene(originalScenePath);
|
||||
|
||||
if (result.Status == TestResultStatus.Undefined)
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("No missing components were found!");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<GameObject> GetMissingComponentGOsInScene(string path)
|
||||
{
|
||||
var missingComponentGOs = new List<GameObject>();
|
||||
|
||||
var scene = _sceneUtility.OpenScene(path);
|
||||
|
||||
if (!scene.IsValid())
|
||||
{
|
||||
Debug.LogWarning("Unable to get Scene in " + path);
|
||||
return new List<GameObject>();
|
||||
}
|
||||
|
||||
var rootObjects = scene.GetRootGameObjects();
|
||||
|
||||
foreach (var obj in rootObjects)
|
||||
{
|
||||
missingComponentGOs.AddRange(GetMissingComponentGOs(obj));
|
||||
}
|
||||
|
||||
return missingComponentGOs;
|
||||
}
|
||||
|
||||
private List<GameObject> GetMissingComponentGOs(GameObject root)
|
||||
{
|
||||
var missingComponentGOs = new List<GameObject>();
|
||||
var rootComponents = root.GetComponents<Component>();
|
||||
|
||||
if (UnityEditor.PrefabUtility.GetPrefabInstanceStatus(root) == UnityEditor.PrefabInstanceStatus.MissingAsset || rootComponents.Any(c => !c))
|
||||
{
|
||||
missingComponentGOs.Add(root);
|
||||
}
|
||||
|
||||
foreach (Transform child in root.transform)
|
||||
missingComponentGOs.AddRange(GetMissingComponentGOs(child.gameObject));
|
||||
|
||||
return missingComponentGOs;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 511e76d0ebcb23d40a7b49dda0e2980f
|
||||
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/Test Methods/Generic/CheckMissingComponentsinScenes.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,64 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityObject = UnityEngine.Object;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class CheckModelImportLogs : ITestScript
|
||||
{
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
private IModelUtilityService _modelUtility;
|
||||
|
||||
public CheckModelImportLogs(GenericTestConfig config, IAssetUtilityService assetUtility, IModelUtilityService modelUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
_modelUtility = modelUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var models = _assetUtility.GetObjectsFromAssets<UnityObject>(_config.ValidationPaths, AssetType.Model);
|
||||
var importLogs = _modelUtility.GetImportLogs(models.ToArray());
|
||||
|
||||
var warningModels = new List<UnityObject>();
|
||||
var errorModels = new List<UnityObject>();
|
||||
|
||||
foreach (var kvp in importLogs)
|
||||
{
|
||||
if (kvp.Value.Any(x => x.Severity == UnityEngine.LogType.Error))
|
||||
errorModels.Add(kvp.Key);
|
||||
if (kvp.Value.Any(x => x.Severity == UnityEngine.LogType.Warning))
|
||||
warningModels.Add(kvp.Key);
|
||||
}
|
||||
|
||||
if (warningModels.Count > 0 || errorModels.Count > 0)
|
||||
{
|
||||
if (warningModels.Count > 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Warning;
|
||||
result.AddMessage("The following models contain import warnings:", null, warningModels.ToArray());
|
||||
}
|
||||
|
||||
if (errorModels.Count > 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Warning;
|
||||
result.AddMessage("The following models contain import errors:", null, errorModels.ToArray());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("No issues were detected when importing your models!");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 98f3ec209166855408eaf4abe5bff591
|
||||
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/Test Methods/Generic/CheckModelImportLogs.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,71 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class CheckModelOrientation : ITestScript
|
||||
{
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
private IMeshUtilityService _meshUtility;
|
||||
|
||||
public CheckModelOrientation(GenericTestConfig config, IAssetUtilityService assetUtility, IMeshUtilityService meshUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
_meshUtility = meshUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var models = _assetUtility.GetObjectsFromAssets<GameObject>(_config.ValidationPaths, AssetType.Model);
|
||||
var badModels = new List<GameObject>();
|
||||
|
||||
foreach (var m in models)
|
||||
{
|
||||
var meshes = _meshUtility.GetCustomMeshesInObject(m);
|
||||
var assetImporter = _assetUtility.GetAssetImporter(m);
|
||||
|
||||
if (!(assetImporter is UnityEditor.ModelImporter modelImporter))
|
||||
continue;
|
||||
|
||||
var clips = modelImporter.clipAnimations.Length;
|
||||
|
||||
// Only check if the model has meshes and no clips
|
||||
if (!meshes.Any() || clips != 0)
|
||||
continue;
|
||||
|
||||
Transform[] transforms = m.GetComponentsInChildren<Transform>(true);
|
||||
|
||||
foreach (var t in transforms)
|
||||
{
|
||||
var hasMeshComponent = t.TryGetComponent<MeshFilter>(out _) || t.TryGetComponent<SkinnedMeshRenderer>(out _);
|
||||
|
||||
if (t.localRotation == Quaternion.identity || !hasMeshComponent)
|
||||
continue;
|
||||
|
||||
badModels.Add(m);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (badModels.Count == 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("All found models are facing the right way!");
|
||||
return result;
|
||||
}
|
||||
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following models have incorrect rotation", null, badModels.ToArray());
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 56cdcdc41a80fbc46b5b2b83ec8d66d7
|
||||
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/Test Methods/Generic/CheckModelOrientation.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,58 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityObject = UnityEngine.Object;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class CheckModelTypes : ITestScript
|
||||
{
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
|
||||
public CheckModelTypes(GenericTestConfig config, IAssetUtilityService assetUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var allowedExtensions = new string[] { ".fbx", ".dae", ".abc", ".obj" };
|
||||
// Should retrieve All assets and not models here since ADB will not recognize certain
|
||||
// types if appropriate software is not installed (e.g. .blend without Blender)
|
||||
var allAssetPaths = _assetUtility.GetAssetPathsFromAssets(_config.ValidationPaths, AssetType.All);
|
||||
var badModels = new List<UnityObject>();
|
||||
|
||||
foreach (var assetPath in allAssetPaths)
|
||||
{
|
||||
var importer = _assetUtility.GetAssetImporter(assetPath);
|
||||
if (importer == null || !(importer is ModelImporter))
|
||||
continue;
|
||||
|
||||
if (allowedExtensions.Any(x => importer.assetPath.ToLower().EndsWith(x)))
|
||||
continue;
|
||||
|
||||
badModels.Add(_assetUtility.AssetPathToObject(assetPath));
|
||||
}
|
||||
|
||||
if (badModels.Count == 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("All models are of allowed formats!");
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following models are of formats that should not be used for Asset Store packages:", null, badModels.ToArray());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 428b1fb838e6f5a469bbfd26ca3fbfd2
|
||||
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/Test Methods/Generic/CheckModelTypes.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,94 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class CheckNormalMapTextures : ITestScript
|
||||
{
|
||||
public const int TextureCacheLimit = 8;
|
||||
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
|
||||
public CheckNormalMapTextures(GenericTestConfig config, IAssetUtilityService assetUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var materials = _assetUtility.GetObjectsFromAssets<Material>(_config.ValidationPaths, AssetType.Material);
|
||||
var badTextures = new List<Texture>();
|
||||
var badPaths = new List<string>();
|
||||
|
||||
foreach (var mat in materials)
|
||||
{
|
||||
for (int i = 0; i < mat.shader.GetPropertyCount(); i++)
|
||||
{
|
||||
if ((mat.shader.GetPropertyFlags(i) & UnityEngine.Rendering.ShaderPropertyFlags.Normal) != 0)
|
||||
{
|
||||
var propertyName = mat.shader.GetPropertyName(i);
|
||||
var assignedTexture = mat.GetTexture(propertyName);
|
||||
|
||||
if (assignedTexture == null)
|
||||
continue;
|
||||
|
||||
var texturePath = _assetUtility.ObjectToAssetPath(assignedTexture);
|
||||
var textureImporter = _assetUtility.GetAssetImporter(texturePath) as TextureImporter;
|
||||
if (textureImporter == null)
|
||||
continue;
|
||||
|
||||
if (textureImporter.textureType != TextureImporterType.NormalMap && !badTextures.Contains(assignedTexture))
|
||||
{
|
||||
if (badTextures.Count < TextureCacheLimit)
|
||||
{
|
||||
badTextures.Add(assignedTexture);
|
||||
}
|
||||
else
|
||||
{
|
||||
string path = AssetDatabase.GetAssetPath(assignedTexture);
|
||||
badPaths.Add(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EditorUtility.UnloadUnusedAssetsImmediate();
|
||||
}
|
||||
|
||||
if (badTextures.Count == 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("All normal map textures have the correct texture type!");
|
||||
}
|
||||
else if (badPaths.Count != 0)
|
||||
{
|
||||
foreach (Texture texture in badTextures)
|
||||
{
|
||||
string path = AssetDatabase.GetAssetPath(texture);
|
||||
badPaths.Add(path);
|
||||
}
|
||||
|
||||
string paths = string.Join("\n", badPaths);
|
||||
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following textures are not set to type 'Normal Map'", null);
|
||||
result.AddMessage(paths);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following textures are not set to type 'Normal Map'", null, badTextures.ToArray());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d55cea510248f814eb2194c2b53f88d2
|
||||
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/Test Methods/Generic/CheckNormalMapTextures.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,295 @@
|
||||
using AssetStoreTools.Utility;
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class CheckPackageNaming : ITestScript
|
||||
{
|
||||
private const string ForbiddenCharacters = "~`!@#$%^&*()-_=+[{]}\\|;:'\",<>?/";
|
||||
private readonly string[] PathsToCheckForForbiddenCharacters = new string[]
|
||||
{
|
||||
"Assets/",
|
||||
"Assets/Editor/",
|
||||
"Assets/Plugins/",
|
||||
"Assets/Resources/",
|
||||
"Assets/StreamingAssets/",
|
||||
"Assets/WebGLTemplates/"
|
||||
};
|
||||
|
||||
private class PathCheckResult
|
||||
{
|
||||
public Object[] InvalidMainPaths;
|
||||
public Object[] InvalidMainPathContentPaths;
|
||||
public Object[] InvalidMainPathLeadingUpPaths;
|
||||
public Object[] InvalidHybridPackages;
|
||||
public Object[] PotentiallyInvalidContent;
|
||||
|
||||
public bool HasIssues => InvalidMainPaths.Length > 0
|
||||
|| InvalidMainPathContentPaths.Length > 0
|
||||
|| InvalidMainPathLeadingUpPaths.Length > 0
|
||||
|| InvalidHybridPackages.Length > 0
|
||||
|| PotentiallyInvalidContent.Length > 0;
|
||||
}
|
||||
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
|
||||
// Constructor also accepts dependency injection of registered IValidatorService types
|
||||
public CheckPackageNaming(GenericTestConfig config, IAssetUtilityService assetUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var checkResult = GetInvalidPathsInAssets();
|
||||
|
||||
if (checkResult.HasIssues)
|
||||
{
|
||||
result.Status = TestResultStatus.Warning;
|
||||
|
||||
if (checkResult.InvalidMainPaths.Length > 0)
|
||||
{
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following assets appear to be artificially bumped up in the project hierarchy within commonly used folders", null, checkResult.InvalidMainPaths);
|
||||
}
|
||||
|
||||
if (checkResult.InvalidMainPathContentPaths.Length > 0)
|
||||
{
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following assets appear to be artificially bumped up in the project hierarchy within commonly used folders", null, checkResult.InvalidMainPathContentPaths);
|
||||
}
|
||||
|
||||
if (checkResult.InvalidMainPathLeadingUpPaths.Length > 0)
|
||||
{
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("Despite not being directly validated, this path would be automatically created by the Unity Importer when importing your package", null, checkResult.InvalidMainPathLeadingUpPaths);
|
||||
}
|
||||
|
||||
if (checkResult.InvalidHybridPackages.Length > 0)
|
||||
{
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following packages appear to be artificially bumped up in the Package hierarchy with their 'Display Name' configuration", null, checkResult.InvalidHybridPackages);
|
||||
}
|
||||
|
||||
if (checkResult.PotentiallyInvalidContent.Length > 0)
|
||||
{
|
||||
// Do not override previously set severities
|
||||
result.AddMessage("It is recommended that nested package content refrains from starting with a special character", null, checkResult.PotentiallyInvalidContent);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("All package asset names are valid!");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private PathCheckResult GetInvalidPathsInAssets()
|
||||
{
|
||||
var allInvalidMainPaths = new List<string>();
|
||||
var allInvalidMainContentPaths = new List<string>();
|
||||
var allInvalidMainLeadingUpPaths = new List<string>();
|
||||
var allInvalidPackagePaths = new List<string>();
|
||||
var allInvalidOtherContentPaths = new List<string>();
|
||||
|
||||
foreach (var validationPath in _config.ValidationPaths)
|
||||
{
|
||||
// Is path itself not forbidden e.g.: when validating Assets/_Package, the folder _Package would be invalid
|
||||
if (!IsDirectMainPathValid(validationPath))
|
||||
allInvalidMainPaths.Add(validationPath);
|
||||
|
||||
// Are path contents not forbidden e.g.: when validating Assets/, the folder _Package would be invalid
|
||||
if (!IsDirectMainPathContentValid(validationPath, out var invalidContentPaths))
|
||||
allInvalidMainContentPaths.AddRange(invalidContentPaths);
|
||||
|
||||
// Is the path leading up to this path not forbidden e.g: when validating Assets/_WorkDir/Package, the folder _Workdir would be invalid
|
||||
if (!IsPathLeadingUpToMainPathValid(validationPath, out var invalidLeadingUpPath))
|
||||
allInvalidMainLeadingUpPaths.Add(invalidLeadingUpPath);
|
||||
|
||||
// Is the path pointing to a package valid, e.g.: when validating Packages/com.company.product its display name _Product would be invalid
|
||||
if (!IsHybridPackageMainPathValid(validationPath, out string invalidPackagePath))
|
||||
allInvalidPackagePaths.Add(invalidPackagePath);
|
||||
}
|
||||
|
||||
var ignoredPaths = new List<string>();
|
||||
ignoredPaths.AddRange(allInvalidMainPaths);
|
||||
ignoredPaths.AddRange(allInvalidMainContentPaths);
|
||||
ignoredPaths.AddRange(allInvalidMainLeadingUpPaths);
|
||||
ignoredPaths.AddRange(allInvalidPackagePaths);
|
||||
|
||||
// Mark any other paths that start with a forbidden character
|
||||
if (!ArePackageContentsValid(ignoredPaths, out var invalidContents))
|
||||
allInvalidOtherContentPaths.AddRange(invalidContents);
|
||||
|
||||
return new PathCheckResult()
|
||||
{
|
||||
InvalidMainPaths = PathsToObjects(allInvalidMainPaths),
|
||||
InvalidMainPathContentPaths = PathsToObjects(allInvalidMainContentPaths),
|
||||
InvalidMainPathLeadingUpPaths = PathsToObjects(allInvalidMainLeadingUpPaths),
|
||||
InvalidHybridPackages = PathsToObjects(allInvalidPackagePaths),
|
||||
PotentiallyInvalidContent = PathsToObjects(allInvalidOtherContentPaths)
|
||||
};
|
||||
}
|
||||
|
||||
private bool IsDirectMainPathValid(string validationPath)
|
||||
{
|
||||
foreach (var forbiddenPath in PathsToCheckForForbiddenCharacters)
|
||||
{
|
||||
var forbiddenPathWithSeparator = forbiddenPath.EndsWith("/") ? forbiddenPath : forbiddenPath + "/";
|
||||
if (!validationPath.StartsWith(forbiddenPathWithSeparator))
|
||||
continue;
|
||||
|
||||
var truncatedPath = validationPath.Remove(0, forbiddenPathWithSeparator.Length);
|
||||
var truncatedPathSplit = truncatedPath.Split('/');
|
||||
|
||||
// It is not a direct main path if it has deeper paths
|
||||
if (truncatedPathSplit.Length != 1)
|
||||
continue;
|
||||
|
||||
if (ForbiddenCharacters.Any(x => truncatedPath.StartsWith(x.ToString())))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool IsDirectMainPathContentValid(string validationPath, out List<string> invalidContentPaths)
|
||||
{
|
||||
invalidContentPaths = new List<string>();
|
||||
|
||||
var contents = Directory.EnumerateFileSystemEntries(validationPath, "*", SearchOption.AllDirectories)
|
||||
.Where(x => !x.EndsWith(".meta"))
|
||||
.Select(GetAdbPath);
|
||||
|
||||
foreach (var contentPath in contents)
|
||||
{
|
||||
foreach (var forbiddenPath in PathsToCheckForForbiddenCharacters)
|
||||
{
|
||||
var forbiddenPathWithSeparator = forbiddenPath.EndsWith("/") ? forbiddenPath : forbiddenPath + "/";
|
||||
if (!contentPath.StartsWith(forbiddenPathWithSeparator))
|
||||
continue;
|
||||
|
||||
var truncatedPath = contentPath.Remove(0, forbiddenPathWithSeparator.Length);
|
||||
var truncatedPathSplit = truncatedPath.Split('/');
|
||||
|
||||
// Only check the first level of content relative to the forbidden path
|
||||
if (truncatedPathSplit.Length > 1)
|
||||
continue;
|
||||
|
||||
if (ForbiddenCharacters.Any(x => truncatedPathSplit[0].StartsWith(x.ToString())))
|
||||
invalidContentPaths.Add(contentPath);
|
||||
}
|
||||
}
|
||||
|
||||
return invalidContentPaths.Count == 0;
|
||||
}
|
||||
|
||||
private bool IsPathLeadingUpToMainPathValid(string validationPath, out string invalidLeadingUpPath)
|
||||
{
|
||||
invalidLeadingUpPath = string.Empty;
|
||||
|
||||
foreach (var forbiddenPath in PathsToCheckForForbiddenCharacters)
|
||||
{
|
||||
var forbiddenPathWithSeparator = forbiddenPath.EndsWith("/") ? forbiddenPath : forbiddenPath + "/";
|
||||
if (!validationPath.StartsWith(forbiddenPathWithSeparator))
|
||||
continue;
|
||||
|
||||
var truncatedPath = validationPath.Remove(0, forbiddenPathWithSeparator.Length);
|
||||
var truncatedPathSplit = truncatedPath.Split('/');
|
||||
|
||||
// It is not a leading up path if it has no deeper path
|
||||
if (truncatedPathSplit.Length == 1)
|
||||
continue;
|
||||
|
||||
if (ForbiddenCharacters.Any(x => truncatedPathSplit[0].StartsWith(x.ToString())))
|
||||
{
|
||||
invalidLeadingUpPath = forbiddenPathWithSeparator + truncatedPathSplit[0];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool IsHybridPackageMainPathValid(string validationPath, out string invalidPackagePath)
|
||||
{
|
||||
invalidPackagePath = string.Empty;
|
||||
|
||||
if (!PackageUtility.GetPackageByManifestPath($"{validationPath}/package.json", out var package))
|
||||
return true;
|
||||
|
||||
var packageName = package.displayName;
|
||||
if (ForbiddenCharacters.Any(x => packageName.StartsWith(x.ToString())))
|
||||
{
|
||||
invalidPackagePath = validationPath;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ArePackageContentsValid(IEnumerable<string> ignoredPaths, out List<string> invalidContentPaths)
|
||||
{
|
||||
invalidContentPaths = new List<string>();
|
||||
|
||||
foreach (var validationPath in _config.ValidationPaths)
|
||||
{
|
||||
var validationPathFolderName = validationPath.Split('/').Last();
|
||||
if (!ignoredPaths.Contains(validationPath) && ForbiddenCharacters.Any(x => validationPathFolderName.StartsWith(x.ToString())))
|
||||
invalidContentPaths.Add(validationPath);
|
||||
|
||||
var contents = Directory.EnumerateFileSystemEntries(validationPath, "*", SearchOption.AllDirectories)
|
||||
.Where(x => !x.EndsWith(".meta"))
|
||||
.Select(GetAdbPath);
|
||||
|
||||
foreach (var contentEntry in contents)
|
||||
{
|
||||
if (ignoredPaths.Contains(contentEntry))
|
||||
continue;
|
||||
|
||||
var entryName = contentEntry.Split('/').Last();
|
||||
if (ForbiddenCharacters.Any(x => entryName.StartsWith(x.ToString())))
|
||||
invalidContentPaths.Add(contentEntry);
|
||||
}
|
||||
}
|
||||
|
||||
return invalidContentPaths.Count == 0;
|
||||
}
|
||||
|
||||
private string GetAdbPath(string path)
|
||||
{
|
||||
path = path.Replace("\\", "/");
|
||||
if (path.StartsWith(Constants.RootProjectPath))
|
||||
path = path.Remove(Constants.RootProjectPath.Length);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
private Object[] PathsToObjects(IEnumerable<string> paths)
|
||||
{
|
||||
var objects = new List<Object>();
|
||||
|
||||
foreach (var path in paths)
|
||||
{
|
||||
var obj = _assetUtility.AssetPathToObject(path);
|
||||
if (obj != null)
|
||||
objects.Add(obj);
|
||||
}
|
||||
|
||||
return objects.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: afe9e04825c7d904981a54404b222290
|
||||
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/Test Methods/Generic/CheckPackageNaming.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,76 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Data.MessageActions;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class CheckParticleSystems : ITestScript
|
||||
{
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
private ISceneUtilityService _sceneUtility;
|
||||
|
||||
public CheckParticleSystems(GenericTestConfig config, IAssetUtilityService assetUtility, ISceneUtilityService sceneUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
_sceneUtility = sceneUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var originalScenePath = _sceneUtility.CurrentScenePath;
|
||||
|
||||
var scenePaths = _assetUtility.GetAssetPathsFromAssets(_config.ValidationPaths, AssetType.Scene);
|
||||
|
||||
foreach (var path in scenePaths)
|
||||
{
|
||||
var badParticleSystems = new List<ParticleSystem>();
|
||||
|
||||
var scene = _sceneUtility.OpenScene(path);
|
||||
|
||||
if (!scene.IsValid())
|
||||
{
|
||||
Debug.LogWarning("Unable to get Scene in " + path);
|
||||
continue;
|
||||
}
|
||||
|
||||
#if UNITY_2023_1_OR_NEWER
|
||||
var particleSystems = GameObject.FindObjectsByType<ParticleSystem>(FindObjectsInactive.Include, FindObjectsSortMode.None);
|
||||
#else
|
||||
var particleSystems = GameObject.FindObjectsOfType<ParticleSystem>();
|
||||
#endif
|
||||
|
||||
foreach (var ps in particleSystems)
|
||||
{
|
||||
if (PrefabUtility.IsPartOfAnyPrefab(ps.gameObject))
|
||||
continue;
|
||||
badParticleSystems.Add(ps);
|
||||
}
|
||||
|
||||
if (badParticleSystems.Count == 0)
|
||||
continue;
|
||||
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
var message = $"Particle Systems not belonging to any Prefab were found in {path}.\n\nClick this message to open the Scene and see the affected Particle Systems:";
|
||||
result.AddMessage(message, new OpenAssetAction(AssetDatabase.LoadAssetAtPath<SceneAsset>(path)), badParticleSystems.ToArray());
|
||||
}
|
||||
|
||||
_sceneUtility.OpenScene(originalScenePath);
|
||||
|
||||
if (result.Status == TestResultStatus.Undefined)
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("No Particle Systems without Prefabs were found!");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6a623f7988c75884bb17b169ccd3e993
|
||||
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/Test Methods/Generic/CheckParticleSystems.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,98 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using AssetStoreTools.Validator.Utility;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityObject = UnityEngine.Object;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class CheckPathLengths : ITestScript
|
||||
{
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
|
||||
public CheckPathLengths(GenericTestConfig config, IAssetUtilityService assetUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
TestResult result = new TestResult();
|
||||
|
||||
int pathLengthLimit = 140;
|
||||
// Get all project paths and sort by length so that folders always come before files
|
||||
var allPaths = ValidatorUtility.GetProjectPaths(_config.ValidationPaths).OrderBy(x => x.Length);
|
||||
|
||||
var filteredDirs = new Dictionary<string, UnityObject>();
|
||||
var filteredFiles = new Dictionary<string, UnityObject>();
|
||||
|
||||
foreach (var path in allPaths)
|
||||
{
|
||||
// Truncated path examples:
|
||||
// Assets/[Scenes/SampleScene.unity]
|
||||
// Packages/com.example.package/[Editor/EditorScript.cs]
|
||||
var truncatedPath = path;
|
||||
if (path.StartsWith("Assets/"))
|
||||
truncatedPath = path.Remove(0, "Assets/".Length);
|
||||
else if (path.StartsWith("Packages/"))
|
||||
{
|
||||
var splitPath = path.Split('/');
|
||||
truncatedPath = string.Join("/", splitPath.Skip(2));
|
||||
}
|
||||
|
||||
// Skip paths under the character limit
|
||||
if (truncatedPath.Length < pathLengthLimit)
|
||||
continue;
|
||||
|
||||
// Skip children of already added directories
|
||||
if (filteredDirs.Keys.Any(x => truncatedPath.StartsWith(x)))
|
||||
continue;
|
||||
|
||||
if (AssetDatabase.IsValidFolder(path))
|
||||
{
|
||||
filteredDirs.Add(truncatedPath, _assetUtility.AssetPathToObject(path));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!filteredFiles.ContainsKey(truncatedPath))
|
||||
filteredFiles.Add(truncatedPath, _assetUtility.AssetPathToObject(path));
|
||||
}
|
||||
|
||||
if (filteredDirs.Count == 0 && filteredFiles.Count == 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("All package content matches the path limit criteria!");
|
||||
return result;
|
||||
}
|
||||
|
||||
if (filteredDirs.Count > 0)
|
||||
{
|
||||
var maxDirLength = filteredDirs.Keys.Aggregate("", (max, cur) => max.Length > cur.Length ? max : cur);
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage($"The following folders exceed the path length limit:");
|
||||
foreach (var kvp in filteredDirs)
|
||||
{
|
||||
result.AddMessage($"Path length: {kvp.Key.Length} characters", null, kvp.Value);
|
||||
}
|
||||
}
|
||||
|
||||
if (filteredFiles.Count > 0)
|
||||
{
|
||||
var maxFileLength = filteredFiles.Keys.Aggregate("", (max, cur) => max.Length > cur.Length ? max : cur);
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage($"The following files exceed the path length limit:");
|
||||
foreach (var kvp in filteredFiles)
|
||||
{
|
||||
result.AddMessage($"Path length: {kvp.Key.Length} characters", null, kvp.Value);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ae379305e9165e84584373a8272c09e7
|
||||
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/Test Methods/Generic/CheckPathLengths.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,71 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class CheckPrefabTransforms : ITestScript
|
||||
{
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
private IMeshUtilityService _meshUtility;
|
||||
|
||||
public CheckPrefabTransforms(GenericTestConfig config, IAssetUtilityService assetUtility, IMeshUtilityService meshUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
_meshUtility = meshUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var prefabs = _assetUtility.GetObjectsFromAssets<GameObject>(_config.ValidationPaths, AssetType.Prefab);
|
||||
var badPrefabs = new List<GameObject>();
|
||||
var badPrefabsLowOffset = new List<GameObject>();
|
||||
|
||||
foreach (var p in prefabs)
|
||||
{
|
||||
var hasRectTransform = p.TryGetComponent(out RectTransform _);
|
||||
if (hasRectTransform || !_meshUtility.GetCustomMeshesInObject(p).Any())
|
||||
continue;
|
||||
|
||||
var positionString = p.transform.position.ToString("F12");
|
||||
var rotationString = p.transform.rotation.eulerAngles.ToString("F12");
|
||||
var localScaleString = p.transform.localScale.ToString("F12");
|
||||
|
||||
var vectorZeroString = Vector3.zero.ToString("F12");
|
||||
var vectorOneString = Vector3.one.ToString("F12");
|
||||
|
||||
if (positionString != vectorZeroString || rotationString != vectorZeroString || localScaleString != vectorOneString)
|
||||
{
|
||||
if (p.transform.position == Vector3.zero && p.transform.rotation.eulerAngles == Vector3.zero && p.transform.localScale == Vector3.one)
|
||||
badPrefabsLowOffset.Add(p);
|
||||
else
|
||||
badPrefabs.Add(p);
|
||||
}
|
||||
}
|
||||
|
||||
if (badPrefabs.Count == 0 && badPrefabsLowOffset.Count == 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("All found prefabs were reset!");
|
||||
return result;
|
||||
}
|
||||
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
if (badPrefabs.Count > 0)
|
||||
result.AddMessage("The following prefabs' transforms do not fit the requirements", null, badPrefabs.ToArray());
|
||||
if (badPrefabsLowOffset.Count > 0)
|
||||
result.AddMessage("The following prefabs have unusually low transform values, which might not be accurately displayed " +
|
||||
"in the Inspector window. Please use the 'Debug' Inspector mode to review the Transform component of these prefabs " +
|
||||
"or reset the Transform components using the right-click context menu", null, badPrefabsLowOffset.ToArray());
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f712c17a60bf2d049a4e61c8f79e56c2
|
||||
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/Test Methods/Generic/CheckPrefabTransforms.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,30 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using UnityEditor;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class CheckScriptCompilation : ITestScript
|
||||
{
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var hasCompilationErrors = EditorUtility.scriptCompilationFailed;
|
||||
|
||||
if (hasCompilationErrors)
|
||||
{
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("One or more scripts in the project failed to compile.\n" +
|
||||
"Please check the Console window to see the list of errors");
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("All scripts in the project compiled successfully!");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 59db88f43969db8499299bce7f4fb967
|
||||
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/Test Methods/Generic/CheckScriptCompilation.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,63 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
#if !UNITY_2023_1_OR_NEWER
|
||||
using UnityEngine.Experimental.Rendering;
|
||||
#endif
|
||||
#if UNITY_2023_1_OR_NEWER
|
||||
using UnityEngine.Rendering;
|
||||
#endif
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class CheckShaderCompilation : ITestScript
|
||||
{
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
|
||||
public CheckShaderCompilation(GenericTestConfig config, IAssetUtilityService assetUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var shaders = _assetUtility.GetObjectsFromAssets(_config.ValidationPaths, AssetType.Shader);
|
||||
var badShaders = shaders.Where(ShaderHasError).ToArray();
|
||||
|
||||
if (badShaders.Length > 0)
|
||||
{
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following shader files have errors", null, badShaders);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("All found Shaders have no compilation errors!");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool ShaderHasError(Object obj)
|
||||
{
|
||||
switch (obj)
|
||||
{
|
||||
case Shader shader:
|
||||
return ShaderUtil.ShaderHasError(shader);
|
||||
case ComputeShader shader:
|
||||
return ShaderUtil.GetComputeShaderMessageCount(shader) > 0;
|
||||
case RayTracingShader shader:
|
||||
return ShaderUtil.GetRayTracingShaderMessageCount(shader) > 0;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7abb278a6082bde4391e0779394cb85b
|
||||
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/Test Methods/Generic/CheckShaderCompilation.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,57 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class CheckTextureDimensions : ITestScript
|
||||
{
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
|
||||
public CheckTextureDimensions(GenericTestConfig config, IAssetUtilityService assetUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var textures = _assetUtility.GetObjectsFromAssets<Texture>(_config.ValidationPaths, AssetType.Texture);
|
||||
var badTextures = new List<Texture>();
|
||||
|
||||
foreach (var texture in textures)
|
||||
{
|
||||
if (Mathf.IsPowerOfTwo(texture.width) && Mathf.IsPowerOfTwo(texture.height))
|
||||
continue;
|
||||
|
||||
var importer = _assetUtility.GetAssetImporter(_assetUtility.ObjectToAssetPath(texture));
|
||||
|
||||
if (importer == null || !(importer is TextureImporter textureImporter)
|
||||
|| textureImporter.textureType == TextureImporterType.Sprite
|
||||
|| textureImporter.textureType == TextureImporterType.GUI)
|
||||
continue;
|
||||
|
||||
badTextures.Add(texture);
|
||||
}
|
||||
|
||||
if (badTextures.Count == 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("All texture dimensions are a power of 2!");
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following texture dimensions are not a power of 2:", null, badTextures.ToArray());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 073f1dacf3da34d4783140ae9d485d5f
|
||||
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/Test Methods/Generic/CheckTextureDimensions.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,233 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityObject = UnityEngine.Object;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class CheckTypeNamespaces : ITestScript
|
||||
{
|
||||
private readonly string[] ForbiddenNamespaces = new string[] { "Unity" };
|
||||
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
private IScriptUtilityService _scriptUtility;
|
||||
|
||||
private enum NamespaceEligibility
|
||||
{
|
||||
NoNamespace,
|
||||
Ok,
|
||||
Forbidden
|
||||
}
|
||||
|
||||
private class AnalysisResult
|
||||
{
|
||||
public Dictionary<UnityObject, List<string>> TypesWithoutNamespaces;
|
||||
public Dictionary<UnityObject, List<string>> ForbiddenNamespaces;
|
||||
|
||||
public bool HasIssues => TypesWithoutNamespaces.Count > 0
|
||||
|| ForbiddenNamespaces.Count > 0;
|
||||
}
|
||||
|
||||
public CheckTypeNamespaces(GenericTestConfig config, IAssetUtilityService assetUtility, IScriptUtilityService scriptUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
_scriptUtility = scriptUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var scriptResult = CheckScripts();
|
||||
var assemblyResult = CheckAssemblies();
|
||||
|
||||
if (scriptResult.HasIssues || assemblyResult.HasIssues)
|
||||
{
|
||||
result.Status = TestResultStatus.Warning;
|
||||
|
||||
// Error conditions for forbidden namespaces
|
||||
|
||||
if (scriptResult.ForbiddenNamespaces.Count > 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Fail;
|
||||
result.AddMessage("The following scripts contain namespaces starting with a 'Unity' keyword:");
|
||||
AddJoinedMessage(result, scriptResult.ForbiddenNamespaces);
|
||||
}
|
||||
|
||||
if (assemblyResult.ForbiddenNamespaces.Count > 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Fail;
|
||||
result.AddMessage("The following assemblies contain namespaces starting with a 'Unity' keyword:");
|
||||
AddJoinedMessage(result, assemblyResult.ForbiddenNamespaces);
|
||||
}
|
||||
|
||||
// Variable severity conditions for no-namespace types
|
||||
|
||||
if (scriptResult.TypesWithoutNamespaces.Count > 0)
|
||||
{
|
||||
if (result.Status != TestResultStatus.Fail)
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
|
||||
result.AddMessage("The following scripts contain types not nested under a namespace:");
|
||||
AddJoinedMessage(result, scriptResult.TypesWithoutNamespaces);
|
||||
}
|
||||
|
||||
if (assemblyResult.TypesWithoutNamespaces.Count > 0)
|
||||
{
|
||||
if (result.Status != TestResultStatus.Fail)
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
|
||||
result.AddMessage("The following assemblies contain types not nested under a namespace:");
|
||||
AddJoinedMessage(result, assemblyResult.TypesWithoutNamespaces);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("All scripts contain valid namespaces!");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private AnalysisResult CheckScripts()
|
||||
{
|
||||
var scripts = _assetUtility.GetObjectsFromAssets<MonoScript>(_config.ValidationPaths, AssetType.MonoScript).ToArray();
|
||||
var scriptNamespaces = _scriptUtility.GetTypeNamespacesFromScriptAssets(scripts);
|
||||
|
||||
var scriptsWithoutNamespaces = new Dictionary<UnityObject, List<string>>();
|
||||
var scriptsWithForbiddenNamespaces = new Dictionary<UnityObject, List<string>>();
|
||||
|
||||
foreach (var kvp in scriptNamespaces)
|
||||
{
|
||||
var scriptAsset = kvp.Key;
|
||||
var typesInScriptAsset = kvp.Value;
|
||||
|
||||
var typesWithoutNamespace = new List<string>();
|
||||
var discouragedNamespaces = new List<string>();
|
||||
var forbiddenNamespaces = new List<string>();
|
||||
|
||||
foreach (var t in typesInScriptAsset)
|
||||
{
|
||||
var eligibility = CheckNamespaceEligibility(t.Namespace);
|
||||
|
||||
switch (eligibility)
|
||||
{
|
||||
case NamespaceEligibility.NoNamespace:
|
||||
typesWithoutNamespace.Add(t.Name);
|
||||
break;
|
||||
case NamespaceEligibility.Forbidden:
|
||||
if (!forbiddenNamespaces.Contains(t.Namespace))
|
||||
forbiddenNamespaces.Add(t.Namespace);
|
||||
break;
|
||||
case NamespaceEligibility.Ok:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (typesWithoutNamespace.Count > 0)
|
||||
scriptsWithoutNamespaces.Add(scriptAsset, typesWithoutNamespace);
|
||||
|
||||
if (forbiddenNamespaces.Count > 0)
|
||||
scriptsWithForbiddenNamespaces.Add(scriptAsset, forbiddenNamespaces);
|
||||
}
|
||||
|
||||
return new AnalysisResult
|
||||
{
|
||||
TypesWithoutNamespaces = scriptsWithoutNamespaces,
|
||||
ForbiddenNamespaces = scriptsWithForbiddenNamespaces
|
||||
};
|
||||
}
|
||||
|
||||
private AnalysisResult CheckAssemblies()
|
||||
{
|
||||
var assemblies = _assetUtility.GetObjectsFromAssets(_config.ValidationPaths, AssetType.PrecompiledAssembly).ToList();
|
||||
var assemblyTypes = _scriptUtility.GetTypesFromAssemblies(assemblies);
|
||||
|
||||
var assembliesWithoutNamespaces = new Dictionary<UnityObject, List<string>>();
|
||||
var assembliesWithForbiddenNamespaces = new Dictionary<UnityObject, List<string>>();
|
||||
|
||||
foreach (var kvp in assemblyTypes)
|
||||
{
|
||||
var assemblyAsset = kvp.Key;
|
||||
var typesInAssembly = kvp.Value;
|
||||
|
||||
var typesWithoutNamespace = new List<string>();
|
||||
var discouragedNamespaces = new List<string>();
|
||||
var forbiddenNamespaces = new List<string>();
|
||||
|
||||
foreach (var t in typesInAssembly)
|
||||
{
|
||||
var eligibility = CheckNamespaceEligibility(t.Namespace);
|
||||
|
||||
switch (eligibility)
|
||||
{
|
||||
case NamespaceEligibility.NoNamespace:
|
||||
typesWithoutNamespace.Add($"{GetTypeName(t)} {t.Name}");
|
||||
break;
|
||||
case NamespaceEligibility.Forbidden:
|
||||
if (!forbiddenNamespaces.Contains(t.Namespace))
|
||||
forbiddenNamespaces.Add(t.Namespace);
|
||||
break;
|
||||
case NamespaceEligibility.Ok:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (typesWithoutNamespace.Count > 0)
|
||||
assembliesWithoutNamespaces.Add(assemblyAsset, typesWithoutNamespace);
|
||||
|
||||
if (forbiddenNamespaces.Count > 0)
|
||||
assembliesWithForbiddenNamespaces.Add(assemblyAsset, forbiddenNamespaces);
|
||||
}
|
||||
|
||||
return new AnalysisResult
|
||||
{
|
||||
TypesWithoutNamespaces = assembliesWithoutNamespaces,
|
||||
ForbiddenNamespaces = assembliesWithForbiddenNamespaces
|
||||
};
|
||||
}
|
||||
|
||||
private NamespaceEligibility CheckNamespaceEligibility(string fullNamespace)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fullNamespace))
|
||||
return NamespaceEligibility.NoNamespace;
|
||||
|
||||
var split = fullNamespace.Split('.');
|
||||
var topLevelNamespace = split[0];
|
||||
if (ForbiddenNamespaces.Any(x => topLevelNamespace.StartsWith(x, StringComparison.OrdinalIgnoreCase)))
|
||||
return NamespaceEligibility.Forbidden;
|
||||
|
||||
return NamespaceEligibility.Ok;
|
||||
}
|
||||
|
||||
private string GetTypeName(Type type)
|
||||
{
|
||||
if (type.IsClass)
|
||||
return "class";
|
||||
if (type.IsInterface)
|
||||
return "interface";
|
||||
if (type.IsEnum)
|
||||
return "enum";
|
||||
if (type.IsValueType)
|
||||
return "struct";
|
||||
|
||||
throw new ArgumentException($"Received an unrecognizable type {type}. Type must be either a class, interface, struct or enum");
|
||||
}
|
||||
|
||||
private void AddJoinedMessage(TestResult result, Dictionary<UnityObject, List<string>> assetsWithMessages)
|
||||
{
|
||||
foreach (var kvp in assetsWithMessages)
|
||||
{
|
||||
var message = string.Join("\n", kvp.Value);
|
||||
result.AddMessage(message, null, kvp.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 279249fa7ef8c2446b3a9f013eeedbf0
|
||||
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/Test Methods/Generic/CheckTypeNamespaces.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,38 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System.Linq;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class RemoveExecutableFiles : ITestScript
|
||||
{
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
|
||||
public RemoveExecutableFiles(GenericTestConfig config, IAssetUtilityService assetUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var executables = _assetUtility.GetObjectsFromAssets(_config.ValidationPaths, AssetType.Executable).ToArray();
|
||||
|
||||
if (executables.Length == 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("No executable files were found!");
|
||||
return result;
|
||||
}
|
||||
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following executable files were found", null, executables);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8e4450592cc60e54286ad089b66db94d
|
||||
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/Test Methods/Generic/RemoveExecutableFiles.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,38 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System.Linq;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class RemoveJPGFiles : ITestScript
|
||||
{
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
|
||||
public RemoveJPGFiles(GenericTestConfig config, IAssetUtilityService assetUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var jpgs = _assetUtility.GetObjectsFromAssets(_config.ValidationPaths, AssetType.JPG).ToArray();
|
||||
|
||||
if (jpgs.Length == 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("No JPG/JPEG textures were found!");
|
||||
return result;
|
||||
}
|
||||
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following textures are compressed as JPG/JPEG", null, jpgs);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5634a12b3a8544c4585bbc280ae59ce2
|
||||
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/Test Methods/Generic/RemoveJPGFiles.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,38 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System.Linq;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class RemoveJavaScriptFiles : ITestScript
|
||||
{
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
|
||||
public RemoveJavaScriptFiles(GenericTestConfig config, IAssetUtilityService assetUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var javascriptObjects = _assetUtility.GetObjectsFromAssets(_config.ValidationPaths, AssetType.JavaScript).ToArray();
|
||||
|
||||
if (javascriptObjects.Length == 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("No UnityScript / JS files were found!");
|
||||
return result;
|
||||
}
|
||||
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following assets are UnityScript / JS files", null, javascriptObjects);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab1676bde9afba442b35fd3319c18063
|
||||
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/Test Methods/Generic/RemoveJavaScriptFiles.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,83 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using UnityObject = UnityEngine.Object;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class RemoveLossyAudioFiles : ITestScript
|
||||
{
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
|
||||
public RemoveLossyAudioFiles(GenericTestConfig config, IAssetUtilityService assetUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
string SanitizeForComparison(UnityObject o)
|
||||
{
|
||||
Regex alphanumericRegex = new Regex("[^a-zA-Z0-9]");
|
||||
string path = _assetUtility.ObjectToAssetPath(o);
|
||||
path = path.ToLower();
|
||||
|
||||
int extensionIndex = path.LastIndexOf('.');
|
||||
string extension = path.Substring(extensionIndex + 1);
|
||||
string sanitized = path.Substring(0, extensionIndex);
|
||||
|
||||
int separatorIndex = sanitized.LastIndexOf('/');
|
||||
sanitized = sanitized.Substring(separatorIndex);
|
||||
sanitized = alphanumericRegex.Replace(sanitized, String.Empty);
|
||||
sanitized = sanitized.Replace(extension, String.Empty);
|
||||
sanitized = sanitized.Trim();
|
||||
|
||||
return sanitized;
|
||||
}
|
||||
|
||||
var lossyAudioObjects = _assetUtility.GetObjectsFromAssets(_config.ValidationPaths, AssetType.LossyAudio).ToArray();
|
||||
if (lossyAudioObjects.Length == 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("No lossy audio files were found!");
|
||||
return result;
|
||||
}
|
||||
|
||||
// Try to find and match variants
|
||||
var nonLossyAudioObjects = _assetUtility.GetObjectsFromAssets(_config.ValidationPaths, AssetType.NonLossyAudio);
|
||||
HashSet<string> nonLossyPathSet = new HashSet<string>();
|
||||
foreach (var asset in nonLossyAudioObjects)
|
||||
{
|
||||
var path = SanitizeForComparison(asset);
|
||||
nonLossyPathSet.Add(path);
|
||||
}
|
||||
|
||||
var unmatchedAssets = new List<UnityObject>();
|
||||
foreach (var asset in lossyAudioObjects)
|
||||
{
|
||||
var path = SanitizeForComparison(asset);
|
||||
if (!nonLossyPathSet.Contains(path))
|
||||
unmatchedAssets.Add(asset);
|
||||
}
|
||||
|
||||
if (unmatchedAssets.Count == 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("No lossy audio files were found!");
|
||||
return result;
|
||||
}
|
||||
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following lossy audio files were found without identically named non-lossy variants:", null, unmatchedAssets.ToArray());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b7205a85061273a4eb50586f13f35d35
|
||||
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/Test Methods/Generic/RemoveLossyAudioFiles.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,38 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System.Linq;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class RemoveMixamoFiles : ITestScript
|
||||
{
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
|
||||
public RemoveMixamoFiles(GenericTestConfig config, IAssetUtilityService assetUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var mixamoFiles = _assetUtility.GetObjectsFromAssets(_config.ValidationPaths, AssetType.Mixamo).ToArray();
|
||||
|
||||
if (mixamoFiles.Length == 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("No Mixamo files were found!");
|
||||
return result;
|
||||
}
|
||||
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following Mixamo files were found", null, mixamoFiles);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9df432e52aa958b44bb5e20c13d16552
|
||||
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/Test Methods/Generic/RemoveMixamoFiles.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,38 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System.Linq;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class RemoveSpeedTreeFiles : ITestScript
|
||||
{
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
|
||||
public RemoveSpeedTreeFiles(GenericTestConfig config, IAssetUtilityService assetUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var speedtreeObjects = _assetUtility.GetObjectsFromAssets(_config.ValidationPaths, AssetType.SpeedTree).ToArray();
|
||||
|
||||
if (speedtreeObjects.Length == 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("No SpeedTree assets have been found!");
|
||||
return result;
|
||||
}
|
||||
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following SpeedTree assets have been found", null, speedtreeObjects);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e06bb7e0aa4f9944abc18281c002dff4
|
||||
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/Test Methods/Generic/RemoveSpeedTreeFiles.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,38 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System.Linq;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class RemoveVideoFiles : ITestScript
|
||||
{
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
|
||||
public RemoveVideoFiles(GenericTestConfig config, IAssetUtilityService assetUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var videos = _assetUtility.GetObjectsFromAssets(_config.ValidationPaths, AssetType.Video).ToArray();
|
||||
|
||||
if (videos.Length == 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("No video files were found, looking good!");
|
||||
return result;
|
||||
}
|
||||
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("The following video files were found", null, videos);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f99724c71b0de66419b5d6e8e9bfcc2d
|
||||
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/Test Methods/Generic/RemoveVideoFiles.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 016d62b2cd8346a49815615efd1d6e39
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,172 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityObject = UnityEngine.Object;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class CheckDemoScenes : ITestScript
|
||||
{
|
||||
private class DemoSceneScanResult
|
||||
{
|
||||
public List<UnityObject> ValidAdbScenes;
|
||||
public List<string> HybridScenePaths;
|
||||
public List<UnityObject> NestedUnityPackages;
|
||||
}
|
||||
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
private ISceneUtilityService _sceneUtility;
|
||||
|
||||
public CheckDemoScenes(GenericTestConfig config, IAssetUtilityService assetUtility, ISceneUtilityService sceneUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
_sceneUtility = sceneUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult();
|
||||
var demoSceneScanResult = CheckForDemoScenes(_config);
|
||||
|
||||
// Valid demo scenes were found in ADB
|
||||
if (demoSceneScanResult.ValidAdbScenes.Count > 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("Demo scenes found", null, demoSceneScanResult.ValidAdbScenes.ToArray());
|
||||
return result;
|
||||
}
|
||||
|
||||
// Valid demo scenes found in UPM package.json
|
||||
if (demoSceneScanResult.HybridScenePaths.Count > 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
|
||||
var upmSampleSceneList = string.Join("\n-", demoSceneScanResult.HybridScenePaths);
|
||||
upmSampleSceneList = upmSampleSceneList.Insert(0, "-");
|
||||
|
||||
result.AddMessage($"Demo scenes found:\n{upmSampleSceneList}");
|
||||
return result;
|
||||
}
|
||||
|
||||
// No valid scenes found, but package contains nested .unitypackages
|
||||
if (demoSceneScanResult.NestedUnityPackages.Count > 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Warning;
|
||||
result.AddMessage("Could not find any valid Demo scenes in the selected validation paths.");
|
||||
result.AddMessage("The following nested .unitypackage files were found. " +
|
||||
"If they contain any demo scenes, you can ignore this warning.", null, demoSceneScanResult.NestedUnityPackages.ToArray());
|
||||
return result;
|
||||
}
|
||||
|
||||
// No valid scenes were found and there is nothing pointing to their inclusion in the package
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("Could not find any valid Demo Scenes in the selected validation paths.");
|
||||
return result;
|
||||
}
|
||||
|
||||
private DemoSceneScanResult CheckForDemoScenes(GenericTestConfig config)
|
||||
{
|
||||
var scanResult = new DemoSceneScanResult();
|
||||
scanResult.ValidAdbScenes = CheckForDemoScenesInAssetDatabase(config);
|
||||
scanResult.HybridScenePaths = CheckForDemoScenesInUpmSamples(config);
|
||||
scanResult.NestedUnityPackages = CheckForNestedUnityPackages(config);
|
||||
|
||||
return scanResult;
|
||||
}
|
||||
|
||||
private List<UnityObject> CheckForDemoScenesInAssetDatabase(GenericTestConfig config)
|
||||
{
|
||||
var scenePaths = _assetUtility.GetAssetPathsFromAssets(config.ValidationPaths, AssetType.Scene).ToArray();
|
||||
if (scenePaths.Length == 0)
|
||||
return new List<UnityObject>();
|
||||
|
||||
var originalScenePath = _sceneUtility.CurrentScenePath;
|
||||
var validScenePaths = scenePaths.Where(CanBeDemoScene).ToArray();
|
||||
_sceneUtility.OpenScene(originalScenePath);
|
||||
|
||||
if (validScenePaths.Length == 0)
|
||||
return new List<UnityObject>();
|
||||
|
||||
return validScenePaths.Select(x => AssetDatabase.LoadAssetAtPath<UnityObject>(x)).ToList();
|
||||
}
|
||||
|
||||
private bool CanBeDemoScene(string scenePath)
|
||||
{
|
||||
// Check skybox
|
||||
var sceneSkyboxPath = _assetUtility.ObjectToAssetPath(RenderSettings.skybox).Replace("\\", "").Replace("/", "");
|
||||
var defaultSkyboxPath = "Resources/unity_builtin_extra".Replace("\\", "").Replace("/", "");
|
||||
|
||||
if (!sceneSkyboxPath.Equals(defaultSkyboxPath, StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
|
||||
// Check GameObjects
|
||||
_sceneUtility.OpenScene(scenePath);
|
||||
var rootObjects = _sceneUtility.GetRootGameObjects();
|
||||
var count = rootObjects.Length;
|
||||
|
||||
if (count == 0)
|
||||
return false;
|
||||
|
||||
if (count != 2)
|
||||
return true;
|
||||
|
||||
var cameraGOUnchanged = rootObjects.Any(o => o.TryGetComponent<Camera>(out _) && o.GetComponents(typeof(Component)).Length == 3);
|
||||
var lightGOUnchanged = rootObjects.Any(o => o.TryGetComponent<Light>(out _) && o.GetComponents(typeof(Component)).Length == 2);
|
||||
|
||||
return !cameraGOUnchanged || !lightGOUnchanged;
|
||||
}
|
||||
|
||||
private List<string> CheckForDemoScenesInUpmSamples(GenericTestConfig config)
|
||||
{
|
||||
var scenePaths = new List<string>();
|
||||
|
||||
foreach (var path in config.ValidationPaths)
|
||||
{
|
||||
if (!File.Exists($"{path}/package.json"))
|
||||
continue;
|
||||
|
||||
var packageJsonText = File.ReadAllText($"{path}/package.json");
|
||||
var json = JObject.Parse(packageJsonText);
|
||||
|
||||
if (!json.ContainsKey("samples") || json["samples"].Type != JTokenType.Array || json["samples"].ToList().Count == 0)
|
||||
continue;
|
||||
|
||||
foreach (var sample in json["samples"].ToList())
|
||||
{
|
||||
var samplePath = sample["path"].ToString();
|
||||
samplePath = $"{path}/{samplePath}";
|
||||
if (!Directory.Exists(samplePath))
|
||||
continue;
|
||||
|
||||
var sampleScenePaths = Directory.GetFiles(samplePath, "*.unity", SearchOption.AllDirectories);
|
||||
foreach (var scenePath in sampleScenePaths)
|
||||
{
|
||||
// If meta file is not found, the sample will not be included with the exported .unitypackage
|
||||
if (!File.Exists($"{scenePath}.meta"))
|
||||
continue;
|
||||
|
||||
if (!scenePaths.Contains(scenePath.Replace("\\", "/")))
|
||||
scenePaths.Add(scenePath.Replace("\\", "/"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return scenePaths;
|
||||
}
|
||||
|
||||
private List<UnityObject> CheckForNestedUnityPackages(GenericTestConfig config)
|
||||
{
|
||||
var unityPackages = _assetUtility.GetObjectsFromAssets(config.ValidationPaths, AssetType.UnityPackage).ToArray();
|
||||
return unityPackages.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f844c2dfa4669ff4eacf5591b544edaf
|
||||
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/Test Methods/UnityPackage/CheckDemoScenes.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,73 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class CheckDocumentation : ITestScript
|
||||
{
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
|
||||
public CheckDocumentation(GenericTestConfig config, IAssetUtilityService assetUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var textFilePaths = _assetUtility.GetAssetPathsFromAssets(_config.ValidationPaths, AssetType.Documentation).ToArray();
|
||||
var documentationFilePaths = textFilePaths.Where(CouldBeDocumentation).ToArray();
|
||||
|
||||
if (textFilePaths.Length == 0)
|
||||
{
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
result.AddMessage("No potential documentation files ('.txt', '.pdf', " +
|
||||
"'.html', '.rtf', '.md') found within the given path.");
|
||||
}
|
||||
else if (documentationFilePaths.Length == 0)
|
||||
{
|
||||
result.Status = TestResultStatus.Warning;
|
||||
var textFileObjects = textFilePaths.Select(_assetUtility.AssetPathToObject).ToArray();
|
||||
result.AddMessage("The following files have been found to match the documentation file format," +
|
||||
" but may not be documentation in content",
|
||||
null, textFileObjects);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
var documentationFileObjects = documentationFilePaths.Select(_assetUtility.AssetPathToObject).ToArray();
|
||||
result.AddMessage("Found documentation files", null, documentationFileObjects);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool CouldBeDocumentation(string filePath)
|
||||
{
|
||||
if (filePath.EndsWith(".pdf"))
|
||||
return true;
|
||||
|
||||
using (var fs = File.Open(filePath, FileMode.Open))
|
||||
using (var bs = new BufferedStream(fs))
|
||||
using (var sr = new StreamReader(bs))
|
||||
{
|
||||
string line;
|
||||
while ((line = sr.ReadLine()) != null)
|
||||
{
|
||||
var mentionsDocumentation = line.IndexOf("documentation", StringComparison.OrdinalIgnoreCase) >= 0;
|
||||
if (mentionsDocumentation)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3c8425198983eda4c9b35aa0d59ea33c
|
||||
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/Test Methods/UnityPackage/CheckDocumentation.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,69 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System.IO;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class CheckPackageSize : ITestScript
|
||||
{
|
||||
private GenericTestConfig _config;
|
||||
|
||||
public CheckPackageSize(GenericTestConfig config)
|
||||
{
|
||||
_config = config;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var packageSize = CalculatePackageSize(_config.ValidationPaths);
|
||||
float packageSizeInGB = packageSize / (1024f * 1024f * 1024f);
|
||||
float maxPackageSizeInGB = Constants.Uploader.MaxPackageSizeBytes / (1024f * 1024f * 1024f);
|
||||
|
||||
if (packageSizeInGB - maxPackageSizeInGB >= 0.1f)
|
||||
{
|
||||
result.Status = TestResultStatus.Warning;
|
||||
|
||||
result.AddMessage($"The uncompressed size of your package ({packageSizeInGB:0.#} GB) exceeds the maximum allowed package size of {maxPackageSizeInGB:0.#} GB. " +
|
||||
$"Please make sure that the compressed .unitypackage size does not exceed the size limit.");
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("Your package does not exceed the maximum allowed package size!");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private long CalculatePackageSize(string[] assetPaths)
|
||||
{
|
||||
long totalSize = 0;
|
||||
|
||||
foreach (var path in assetPaths)
|
||||
{
|
||||
totalSize += CalculatePathSize(path);
|
||||
}
|
||||
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
private long CalculatePathSize(string path)
|
||||
{
|
||||
long size = 0;
|
||||
|
||||
var dirInfo = new DirectoryInfo(path);
|
||||
if (!dirInfo.Exists)
|
||||
return size;
|
||||
|
||||
foreach (var file in dirInfo.EnumerateFiles())
|
||||
size += file.Length;
|
||||
|
||||
foreach (var nestedDir in dirInfo.EnumerateDirectories())
|
||||
size += CalculatePathSize(nestedDir.FullName);
|
||||
|
||||
return size;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a8601b99f4afa5049954f3a2dd5996d6
|
||||
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/Test Methods/UnityPackage/CheckPackageSize.cs
|
||||
uploadId: 724584
|
||||
@@ -0,0 +1,217 @@
|
||||
using AssetStoreTools.Validator.Data;
|
||||
using AssetStoreTools.Validator.Services.Validation;
|
||||
using AssetStoreTools.Validator.TestDefinitions;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AssetStoreTools.Validator.TestMethods
|
||||
{
|
||||
internal class CheckProjectTemplateAssets : ITestScript
|
||||
{
|
||||
private GenericTestConfig _config;
|
||||
private IAssetUtilityService _assetUtility;
|
||||
|
||||
// Constructor also accepts dependency injection of registered IValidatorService types
|
||||
public CheckProjectTemplateAssets(GenericTestConfig config, IAssetUtilityService assetUtility)
|
||||
{
|
||||
_config = config;
|
||||
_assetUtility = assetUtility;
|
||||
}
|
||||
|
||||
public TestResult Run()
|
||||
{
|
||||
var result = new TestResult() { Status = TestResultStatus.Undefined };
|
||||
|
||||
var assets = _assetUtility.GetObjectsFromAssets<Object>(_config.ValidationPaths, AssetType.All);
|
||||
var invalidAssetsByGuid = CheckGuids(assets);
|
||||
var invalidAssetsByPath = CheckPaths(assets);
|
||||
|
||||
var hasIssues = invalidAssetsByGuid.Length > 0
|
||||
|| invalidAssetsByPath.Length > 0;
|
||||
|
||||
if (hasIssues)
|
||||
{
|
||||
result.Status = TestResultStatus.VariableSeverityIssue;
|
||||
|
||||
if (invalidAssetsByPath.Length > 0)
|
||||
{
|
||||
result.AddMessage("The following assets were found to have an asset path which is common to project template asset paths. They should be renamed or moved:", null, invalidAssetsByPath);
|
||||
}
|
||||
|
||||
if (invalidAssetsByGuid.Length > 0)
|
||||
{
|
||||
result.AddMessage("The following assets were found to be using a GUID which is common to project template asset GUIDs. They should be assigned a new GUID:", null, invalidAssetsByGuid);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Status = TestResultStatus.Pass;
|
||||
result.AddMessage("No common assets that might cause asset clashing were found!");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private Object[] CheckGuids(IEnumerable<Object> assets)
|
||||
{
|
||||
var clashingAssets = new List<Object>();
|
||||
foreach (var asset in assets)
|
||||
{
|
||||
if (!AssetDatabase.TryGetGUIDAndLocalFileIdentifier(asset, out var guid, out long _))
|
||||
continue;
|
||||
|
||||
if (CommonTemplateAssets.Any(x => x.Key.Equals(guid, System.StringComparison.OrdinalIgnoreCase)))
|
||||
clashingAssets.Add(asset);
|
||||
}
|
||||
|
||||
return clashingAssets.ToArray();
|
||||
}
|
||||
|
||||
private Object[] CheckPaths(IEnumerable<Object> assets)
|
||||
{
|
||||
var clashingAssets = new List<Object>();
|
||||
foreach (var asset in assets)
|
||||
{
|
||||
var assetPath = AssetDatabase.GetAssetPath(asset);
|
||||
if (CommonTemplateAssets.Any(x => x.Value.Equals(assetPath, System.StringComparison.OrdinalIgnoreCase)))
|
||||
clashingAssets.Add(asset);
|
||||
}
|
||||
|
||||
return clashingAssets.ToArray();
|
||||
}
|
||||
|
||||
private Dictionary<string, string> CommonTemplateAssets = new Dictionary<string, string>()
|
||||
{
|
||||
{"3f9215ea0144899419cfbc0957140d3f", "Assets/DefaultVolumeProfile.asset"},
|
||||
{"3d4c13846a3e9bd4c8ccfbd0657ed847", "Assets/DefaultVolumeProfile.asset"},
|
||||
{"4cee8bca36f2ab74b8feb832747fa6f4", "Assets/Editor/com.unity.mobile.notifications/NotificationSettings.asset"},
|
||||
{"45a04f37e0f48c744acc0874c4a8918a", "Assets/Editor/com.unity.mobile.notifications/NotificationSettings.asset"},
|
||||
{"54a3a0570aebe8949bec4966f1376581", "Assets/HDRPDefaultResources/DefaultHDRISky.exr"},
|
||||
{"e93c35b24eb03c74284e7dc0b755bfcc", "Assets/HDRPDefaultResources/DefaultHDRPAsset.asset"},
|
||||
{"254320a857a30444da2c99496a186368", "Assets/HDRPDefaultResources/DefaultLookDevProfile.asset"},
|
||||
{"2bfa7b9d63fa79e4abdc033f54a868d2", "Assets/HDRPDefaultResources/DefaultSceneRoot.prefab"},
|
||||
{"f9e3ff5a1b8f49c4fa8686e68d2dadae", "Assets/HDRPDefaultResources/DefaultSceneRoot.prefab"},
|
||||
{"d87f7d7815073e840834a16a518c1237", "Assets/HDRPDefaultResources/DefaultSettingsVolumeProfile.asset"},
|
||||
{"145290c901d58b343bdeb3b4362c9ff2", "Assets/HDRPDefaultResources/DefaultVFXResources.asset"},
|
||||
{"acc11144f57719542b5fa25f02e74afb", "Assets/HDRPDefaultResources/HDRenderPipelineGlobalSettings.asset"},
|
||||
{"582adbd84082fdb4faf7cd4beb1ccd14", "Assets/HDRPDefaultResources/HDRPDefaultSettings.asset"},
|
||||
{"2801c2ff7303a7543a8727f862f6c236", "Assets/HDRPDefaultResources/Sky and Fog Settings Profile.asset"},
|
||||
{"ea5c25297f0c0a04da0eabb1c26a7509", "Assets/HDRPDefaultResources/SkyFogSettingsProfile.asset"},
|
||||
{"3590b91b4603b465dbb4216d601bff33", "Assets/InputSystem_Actions.inputactions"},
|
||||
{"289c1b55c9541489481df5cc06664110", "Assets/InputSystem_Actions.inputactions"},
|
||||
{"dc70d2c4f369241dd99afd7c451b813e", "Assets/InputSystem_Actions.inputactions"},
|
||||
{"2bcd2660ca9b64942af0de543d8d7100", "Assets/InputSystem_Actions.inputactions"},
|
||||
{"052faaac586de48259a63d0c4782560b", "Assets/InputSystem_Actions.inputactions"},
|
||||
{"35845fe01580c41289b024647b1d1c53", "Assets/InputSystem_Actions.inputactions"},
|
||||
{"8124e5870f4fd4c779e7a5f994e84ad1", "Assets/OutdoorsScene.unity"},
|
||||
{"2dd802e4d37c65149922028d3e973832", "Assets/Presets/AudioCompressedInMemory.preset"},
|
||||
{"e18fd6ecd9cdb524ca99844f39b9d9ac", "Assets/Presets/AudioCompressedInMemory.preset"},
|
||||
{"86bcce7f5575b54408aa0f3a7d321039", "Assets/Presets/AudioStreaming.preset"},
|
||||
{"460e573eb8466884baaa0b8475505f83", "Assets/Presets/AudioStreaming.preset"},
|
||||
{"e8537455c6c08bd4e8bf0be3707da685", "Assets/Presets/Defaults/AlbedoTexture_Default.preset"},
|
||||
{"7a99f8aa944efe94cb9bd74562b7d5f9", "Assets/Presets/Defaults/AlbedoTexture_Default.preset"},
|
||||
{"0cd792cc87e492d43b4e95b205fc5cc6", "Assets/Presets/Defaults/AudioDecompressOnLoad_Default.preset"},
|
||||
{"e7689051185d12f4298e1ebb2693a29f", "Assets/Presets/Defaults/AudioDecompressOnLoad.preset"},
|
||||
{"463065d4f17d1d94d848aa127b94dd43", "Assets/Presets/Defaults/DirectionalLight_Default.preset"},
|
||||
{"c1cf8506f04ef2c4a88b64b6c4202eea", "Assets/Presets/Defaults/DirectionalLight_Default.preset"},
|
||||
{"8fa3055e2a1363246838debd20206d37", "Assets/Presets/Defaults/SSSSettings_Default.preset"},
|
||||
{"78830bb1431cab940b74be615e2a739f", "Assets/Presets/HDRTexture.preset"},
|
||||
{"14a57cf3b9fa1c74b884aa7e0dcf1faa", "Assets/Presets/NormalTexture.preset"},
|
||||
{"1d826a4c23450f946b19c20560595a1f", "Assets/Presets/NormalTexture.preset"},
|
||||
{"45f7b2e3c78185248b3adbb14429c2ab", "Assets/Presets/UtilityTexture.preset"},
|
||||
{"78fae3569c6c66c46afc3d9d4fb0b8d4", "Assets/Presets/UtilityTexture.preset"},
|
||||
{"9303d565bd8aa6948ba775e843320e4d", "Assets/Presets/UtilityTexture.preset"},
|
||||
{"34f54ff1ff9415249a847506b6f2fec5", "Assets/Scenes/PrefabEditingScene.unity"},
|
||||
{"cbfe36cfddfde964d9dfce63a355d5dd", "Assets/Scenes/samplescene.unity"},
|
||||
{"2cda990e2423bbf4892e6590ba056729", "Assets/Scenes/SampleScene.unity"},
|
||||
{"9fc0d4010bbf28b4594072e72b8655ab", "Assets/Scenes/SampleScene.unity"},
|
||||
{"3db1837cc97a95e4c98610966fac2b0b", "Assets/Scenes/SampleScene.unity"},
|
||||
{"3fc8acdd13e6c734bafef6554d6fdbcd", "Assets/Scenes/SampleScene.unity"},
|
||||
{"8c9cfa26abfee488c85f1582747f6a02", "Assets/Scenes/SampleScene.unity"},
|
||||
{"c850ee8c3b14cc8459e7e186857cf567", "Assets/Scenes/SampleScene.unity"},
|
||||
{"99c9720ab356a0642a771bea13969a05", "Assets/Scenes/SampleScene.unity"},
|
||||
{"d1c3109bdb54ad54c8a2b2838528e640", "Assets/Scenes/SampleScene.unity"},
|
||||
{"477cc4148fad3449482a3bc3178594e2", "Assets/Scenes/SampleSceneLightingSettings.lighting"},
|
||||
{"4eb578550bc4f824e97f0a72eac1f3a5", "Assets/Scripts/LookWithMouse.cs"},
|
||||
{"87f6dfceb3e39a947a312f7eeaa2a113", "Assets/Scripts/PlayerMovement.cs"},
|
||||
{"be76e5f14cfee674cb30b491fb72b09b", "Assets/Scripts/SimpleCameraController.cs"},
|
||||
{"6547d18b2bc62c94aa5ec1e87434da4e", "Assets/Scripts/SimpleCameraController.cs"},
|
||||
{"e8a636f62116c0a40bbfefdf876d4608", "Assets/Scripts/SimpleCameraController.cs"},
|
||||
{"14e519c409be4a1428028347410f5677", "Assets/Scripts/SimpleCameraController.cs"},
|
||||
{"a04c28107d77d5e42b7155783b8475b6", "Assets/Settings/Cockpit_Renderer.asset"},
|
||||
{"ab09877e2e707104187f6f83e2f62510", "Assets/Settings/DefaultVolumeProfile.asset"},
|
||||
{"238cd62f6b58cb04e9c94749c4a015a7", "Assets/Settings/DefaultVolumeProfile.asset"},
|
||||
{"5a9a2dc462c7bde4f86d0615a19c2c72", "Assets/Settings/DiffusionProfiles/BambooLeaves.asset"},
|
||||
{"78322c7f82657514ebe48203160e3f39", "Assets/Settings/Foliage.asset"},
|
||||
{"3e2e6bfc59709614ab90c0cd7d755e48", "Assets/Settings/HDRP Balanced.asset"},
|
||||
{"36dd385e759c96147b6463dcd1149c11", "Assets/Settings/HDRP High Fidelity.asset"},
|
||||
{"168a2336534e4e043b2a210b6f8d379a", "Assets/Settings/HDRP Performant.asset"},
|
||||
{"4594f4a3fb14247e192bcca6dc23c8ed", "Assets/Settings/HDRPDefaultResources/DefaultLookDevProfile.asset"},
|
||||
{"14b392ee213d25a48b1feddbd9f5a9be", "Assets/Settings/HDRPDefaultResources/DefaultSettingsVolumeProfile.asset"},
|
||||
{"879ffae44eefa4412bb327928f1a96dd", "Assets/Settings/HDRPDefaultResources/FoliageDiffusionProfile.asset"},
|
||||
{"b9f3086da92434da0bc1518f19f0ce86", "Assets/Settings/HDRPDefaultResources/HDRenderPipelineAsset.asset"},
|
||||
{"ac0316ca287ba459492b669ff1317a6f", "Assets/Settings/HDRPDefaultResources/HDRenderPipelineGlobalSettings.asset"},
|
||||
{"48e911a1e337b44e2b85dbc65b47a594", "Assets/Settings/HDRPDefaultResources/SkinDiffusionProfile.asset"},
|
||||
{"d03ed43fc9d8a4f2e9fa70c1c7916eb9", "Assets/Settings/Lit2DSceneTemplate.scenetemplate"},
|
||||
{"65bc7dbf4170f435aa868c779acfb082", "Assets/Settings/Mobile_Renderer.asset"},
|
||||
{"5e6cbd92db86f4b18aec3ed561671858", "Assets/Settings/Mobile_RPAsset.asset"},
|
||||
{"23cccccf13c3d4170a9b21e52a9bc86b", "Assets/Settings/Mobile/Mobile_High_ScreenRenderer.asset"},
|
||||
{"6e8f76111115f44e0a76c2bff3cec258", "Assets/Settings/Mobile/Mobile_Low_Renderer.asset"},
|
||||
{"aed30aee6a3ceae4090dadd1934d2ad0", "Assets/Settings/Mobile/Mobile_Low_ScreenRenderer.asset"},
|
||||
{"d7686b11d09df481bac3c76ecc5ea626", "Assets/Settings/Mobile/Mobile_Low.asset"},
|
||||
{"f288ae1f4751b564a96ac7587541f7a2", "Assets/Settings/PC_Renderer.asset"},
|
||||
{"4b83569d67af61e458304325a23e5dfd", "Assets/Settings/PC_RPAsset.asset"},
|
||||
{"42b230d443c6d6c4b89c47f97db59121", "Assets/Settings/PC/PC_High_ScreenRenderer.asset"},
|
||||
{"13ba41cd2fa191f43890b271bd110ed9", "Assets/Settings/PC/PC_Low_Renderer.asset"},
|
||||
{"a73f6fa069dd14a42b40cbb01bae63b4", "Assets/Settings/PC/PC_Low_ScreenRenderer.asset"},
|
||||
{"4eb9ff6b5314098428cfa0be7e36ccda", "Assets/Settings/PC/PC_Low.asset"},
|
||||
{"573ac53c334415945bf239de2c2f0511", "Assets/Settings/PlayerControllerFPS.prefab"},
|
||||
{"7ba2b06fb32e5274aad88925a5b8d3f5", "Assets/Settings/PostProcessVolumeProfile.asset"},
|
||||
{"424799608f7334c24bf367e4bbfa7f9a", "Assets/Settings/Renderer2D.asset"},
|
||||
{"183cbd347d25080429f42b520742bbd8", "Assets/Settings/SampleScenePostProcessingSettings.asset"},
|
||||
{"10fc4df2da32a41aaa32d77bc913491c", "Assets/Settings/SampleSceneProfile.asset"},
|
||||
{"a6560a915ef98420e9faacc1c7438823", "Assets/Settings/SampleSceneProfile.asset"},
|
||||
{"a123fc0ac58cb774e8592c925f167e7c", "Assets/Settings/SampleSceneSkyandFogSettings.asset"},
|
||||
{"26bdddf49760c61438938733f07fa2a2", "Assets/Settings/Skin.asset"},
|
||||
{"8ba92e2dd7f884a0f88b98fa2d235fe7", "Assets/Settings/SkyandFogSettingsProfile.asset"},
|
||||
{"4a8e21d5c33334b11b34a596161b9360", "Assets/Settings/UniversalRenderer.asset"},
|
||||
{"18dc0cd2c080841dea60987a38ce93fa", "Assets/Settings/UniversalRenderPipelineGlobalSettings.asset"},
|
||||
{"bdede76083021864d8ff8bf23b2f37f1", "Assets/Settings/UniversalRenderPipelineGlobalSettings.asset"},
|
||||
{"19ba41d7c0026c3459d37c2fe90c55a0", "Assets/Settings/UniversalRP-HighQuality.asset"},
|
||||
{"a31e9f9f9c9d4b9429ed0d1234e22103", "Assets/Settings/UniversalRP-LowQuality.asset"},
|
||||
{"d847b876476d3d6468f5dfcd34266f96", "Assets/Settings/UniversalRP-MediumQuality.asset"},
|
||||
{"681886c5eb7344803b6206f758bf0b1c", "Assets/Settings/UniversalRP.asset"},
|
||||
{"e634585d5c4544dd297acaee93dc2beb", "Assets/Settings/URP-Balanced-Renderer.asset"},
|
||||
{"e1260c1148f6143b28bae5ace5e9c5d1", "Assets/Settings/URP-Balanced.asset"},
|
||||
{"c40be3174f62c4acf8c1216858c64956", "Assets/Settings/URP-HighFidelity-Renderer.asset"},
|
||||
{"7b7fd9122c28c4d15b667c7040e3b3fd", "Assets/Settings/URP-HighFidelity.asset"},
|
||||
{"707360a9c581a4bd7aa53bfeb1429f71", "Assets/Settings/URP-Performant-Renderer.asset"},
|
||||
{"d0e2fc18fe036412f8223b3b3d9ad574", "Assets/Settings/URP-Performant.asset"},
|
||||
{"b62413aeefabaaa41a4b5a71dd7ae1ac", "Assets/Settings/VolumeProfiles/CinematicProfile.asset"},
|
||||
{"ac0c2cad5778d4544b6a690963e02fe3", "Assets/Settings/VolumeProfiles/DefaultVolumeProfile.asset"},
|
||||
{"f2d4d916a6612574cad220d125febbf2", "Assets/Settings/VolumeProfiles/LowQualityVolumeProfile.asset"},
|
||||
{"cef078630d63d0442a070f84d4f13735", "Assets/Settings/VolumeProfiles/MarketProfile.asset"},
|
||||
{"7ede9c9f109e5c442b7d29e54b4996fc", "Assets/Settings/VolumeProfiles/MediaOverrides.asset"},
|
||||
{"3532e98caae428047bcefe69a344f72c", "Assets/Settings/VolumeProfiles/OutlineEnabled.asset"},
|
||||
{"bfc08ba7e35de1a44bb84a32f1a693e1", "Assets/Settings/VolumeProfiles/ZenGardenProfile.asset"},
|
||||
{"59a34a3881431c246b3564a0f0ca5bb0", "Assets/Settings/Volumes/CinematicPhysicalCamera.asset"},
|
||||
{"03bc34b71695890468eb021c73b228db", "Assets/Settings/Volumes/ScreenshotsTimelineProfile.asset"},
|
||||
{"7f342610b85f4164f808a1f380dcc668", "Assets/Settings/Volumes/VolumeGlobal.asset"},
|
||||
{"bd6d234073408c44ca3828113aac655e", "Assets/Settings/Volumes/VolumeRoom1.asset"},
|
||||
{"d78a1b031ab26034eb6ec3cbc9fbcec3", "Assets/Settings/Volumes/VolumeRoom2.asset"},
|
||||
{"5727d3e07f75c3744b6cc8a1e55850a9", "Assets/Settings/Volumes/VolumeRoom2Skylight.asset"},
|
||||
{"06114ad16a0bc0a41957375ac3bf472e", "Assets/Settings/Volumes/VolumeRoom3.asset"},
|
||||
{"1584bf21cf81d5147aa00e8a2deaf2fb", "Assets/Settings/Volumes/VolumeRoom3Corridor.asset"},
|
||||
{"7bca3a07cdd522c4c8020832c20b3eae", "Assets/Settings/Volumes/VolumeRoom3Sitting.asset"},
|
||||
{"2872d90954412244a8b4a477b939c3ca", "Assets/Settings/XR/Loaders/Mock_HMD_Loader.asset"},
|
||||
{"f25758a0f79593d4a9b3ee30a17b4c2e", "Assets/Settings/XR/Loaders/Oculus_Loader.asset"},
|
||||
{"9e9f2958d1b4b4642ace1d0c7770650b", "Assets/Settings/XR/Settings/Mock_HMD_Build_Settings.asset"},
|
||||
{"290a6e6411d135049940bec2237b8938", "Assets/Settings/XR/Settings/Oculus_Settings.asset"},
|
||||
{"4c1640683c539c14080cfd43fbeffbda", "Assets/Settings/XR/XRGeneralSettings.asset"},
|
||||
{"93b439a37f63240aca3dd4e01d978a9f", "Assets/UniversalRenderPipelineGlobalSettings.asset"},
|
||||
{"38b35347542e5af4c9b140950c5b18db", "Assets/UniversalRenderPipelineGlobalSettings.asset"}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f02d52a702c712e4e8089f7c2e65bae7
|
||||
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/Test Methods/UnityPackage/CheckProjectTemplateAssets.cs
|
||||
uploadId: 724584
|
||||
Reference in New Issue
Block a user