From eb84bb298d2b95aec7b2ae12cbf25ac64f25379a Mon Sep 17 00:00:00 2001 From: tylermurphy534 Date: Sun, 6 Nov 2022 15:12:42 -0500 Subject: move to self host --- .../VRChat/Scripts/Validation/AvatarValidation.cs | 1 + .../Scripts/Validation/AvatarValidation.cs.meta | 11 + .../VRChat/Scripts/Validation/Performance.meta | 8 + .../Validation/Performance/AvatarPerformance.cs | 165 +++++ .../Performance/AvatarPerformance.cs.meta | 12 + .../Performance/AvatarPerformanceCategory.cs | 37 + .../Performance/AvatarPerformanceCategory.cs.meta | 3 + .../Scripts/Validation/Performance/Filters.meta | 8 + .../Filters/AbstractPerformanceFilter.cs | 109 +++ .../Filters/AbstractPerformanceFilter.cs.meta | 3 + .../Scripts/Validation/Performance/MeshUtils.cs | 33 + .../Validation/Performance/MeshUtils.cs.meta | 3 + .../Validation/Performance/PerformanceFilterSet.cs | 46 ++ .../Performance/PerformanceFilterSet.cs.meta | 3 + .../Performance/PerformanceInfoDisplayLevel.cs | 12 + .../PerformanceInfoDisplayLevel.cs.meta | 3 + .../Validation/Performance/PerformanceRating.cs | 12 + .../Performance/PerformanceRating.cs.meta | 3 + .../Performance/PerformanceScannerSet.cs | 44 ++ .../Performance/PerformanceScannerSet.cs.meta | 3 + .../Scripts/Validation/Performance/Scanners.meta | 8 + .../Scanners/AbstractPerformanceScanner.cs | 97 +++ .../Scanners/AbstractPerformanceScanner.cs.meta | 3 + .../Scanners/AnimatorPerformanceScanner.cs | 44 ++ .../Scanners/AnimatorPerformanceScanner.cs.meta | 3 + .../Scanners/AudioPerformanceScanner.cs | 29 + .../Scanners/AudioPerformanceScanner.cs.meta | 3 + .../Scanners/ClothPerformanceScanner.cs | 48 ++ .../Scanners/ClothPerformanceScanner.cs.meta | 3 + .../Scanners/DynamicBonePerformanceScanner.cs | 191 ++++++ .../Scanners/DynamicBonePerformanceScanner.cs.meta | 3 + .../Scanners/LightPerformanceScanner.cs | 29 + .../Scanners/LightPerformanceScanner.cs.meta | 3 + .../Scanners/LineRendererPerformanceScanner.cs | 31 + .../LineRendererPerformanceScanner.cs.meta | 3 + .../Performance/Scanners/MeshPerformanceScanner.cs | 266 ++++++++ .../Scanners/MeshPerformanceScanner.cs.meta | 3 + .../Scanners/ParticlePerformanceScanner.cs | 114 ++++ .../Scanners/ParticlePerformanceScanner.cs.meta | 3 + .../Scanners/PhysicsPerformanceScanner.cs | 64 ++ .../Scanners/PhysicsPerformanceScanner.cs.meta | 3 + .../Scanners/TrailRendererPerformanceScanner.cs | 31 + .../TrailRendererPerformanceScanner.cs.meta | 3 + .../Scripts/Validation/Performance/Stats.meta | 8 + .../Performance/Stats/AvatarPerformanceStats.cs | 757 +++++++++++++++++++++ .../Stats/AvatarPerformanceStats.cs.meta | 3 + .../Stats/AvatarPerformanceStatsLevel.cs | 32 + .../Stats/AvatarPerformanceStatsLevel.cs.meta | 11 + .../Stats/AvatarPerformanceStatsLevelSet.cs | 15 + .../Stats/AvatarPerformanceStatsLevelSet.cs.meta | 11 + .../VRChat/Scripts/Validation/ShaderValidation.cs | 86 +++ .../Scripts/Validation/ShaderValidation.cs.meta | 3 + .../VRChat/Scripts/Validation/ValidationUtils.cs | 260 +++++++ .../Scripts/Validation/ValidationUtils.cs.meta | 12 + .../VRChat/Scripts/Validation/WorldValidation.cs | 682 +++++++++++++++++++ .../Scripts/Validation/WorldValidation.cs.meta | 12 + 56 files changed, 3396 insertions(+) create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/AvatarValidation.cs create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/AvatarValidation.cs.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/AvatarPerformance.cs create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/AvatarPerformance.cs.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/AvatarPerformanceCategory.cs create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/AvatarPerformanceCategory.cs.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Filters.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Filters/AbstractPerformanceFilter.cs create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Filters/AbstractPerformanceFilter.cs.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/MeshUtils.cs create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/MeshUtils.cs.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceFilterSet.cs create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceFilterSet.cs.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceInfoDisplayLevel.cs create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceInfoDisplayLevel.cs.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceRating.cs create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceRating.cs.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceScannerSet.cs create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceScannerSet.cs.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/AbstractPerformanceScanner.cs create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/AbstractPerformanceScanner.cs.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/AnimatorPerformanceScanner.cs create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/AnimatorPerformanceScanner.cs.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/AudioPerformanceScanner.cs create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/AudioPerformanceScanner.cs.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/ClothPerformanceScanner.cs create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/ClothPerformanceScanner.cs.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/DynamicBonePerformanceScanner.cs create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/DynamicBonePerformanceScanner.cs.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/LightPerformanceScanner.cs create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/LightPerformanceScanner.cs.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/LineRendererPerformanceScanner.cs create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/LineRendererPerformanceScanner.cs.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/MeshPerformanceScanner.cs create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/MeshPerformanceScanner.cs.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/ParticlePerformanceScanner.cs create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/ParticlePerformanceScanner.cs.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/PhysicsPerformanceScanner.cs create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/PhysicsPerformanceScanner.cs.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/TrailRendererPerformanceScanner.cs create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/TrailRendererPerformanceScanner.cs.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats/AvatarPerformanceStats.cs create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats/AvatarPerformanceStats.cs.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats/AvatarPerformanceStatsLevel.cs create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats/AvatarPerformanceStatsLevel.cs.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats/AvatarPerformanceStatsLevelSet.cs create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats/AvatarPerformanceStatsLevelSet.cs.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/ShaderValidation.cs create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/ShaderValidation.cs.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/ValidationUtils.cs create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/ValidationUtils.cs.meta create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/WorldValidation.cs create mode 100644 VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/WorldValidation.cs.meta (limited to 'VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation') diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/AvatarValidation.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/AvatarValidation.cs new file mode 100644 index 00000000..39dd14a7 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/AvatarValidation.cs @@ -0,0 +1 @@ +/* Migration File: Intentionally Left Blank */ \ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/AvatarValidation.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/AvatarValidation.cs.meta new file mode 100644 index 00000000..f6e03bb1 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/AvatarValidation.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d497915ac8463e048aeb2c934a36c299 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance.meta new file mode 100644 index 00000000..07fd6f1c --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 16b48f3cc7015584c9d4157931f1c673 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/AvatarPerformance.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/AvatarPerformance.cs new file mode 100644 index 00000000..3269bc89 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/AvatarPerformance.cs @@ -0,0 +1,165 @@ +using System.Collections; +using UnityEngine; +using VRC.SDKBase.Validation.Performance.Stats; + +namespace VRC.SDKBase.Validation.Performance +{ + public static class AvatarPerformance + { + #region Public Constants + + public const int DEFAULT_DYNAMIC_BONE_MAX_SIMULATED_BONE_LIMIT = 32; + public const int DEFAULT_DYNAMIC_BONE_MAX_COLLIDER_CHECK_LIMIT = 8; + + #if UNITY_ANDROID || UNITY_IOS + internal const PerformanceRating AVATAR_PERFORMANCE_RATING_MINIMUM_TO_DISPLAY_DEFAULT = PerformanceRating.Medium; + internal const PerformanceRating AVATAR_PERFORMANCE_RATING_MINIMUM_TO_DISPLAY_MIN = PerformanceRating.Medium; + internal const PerformanceRating AVATAR_PERFORMANCE_RATING_MINIMUM_TO_DISPLAY_MAX = PerformanceRating.Poor; + #else + internal const PerformanceRating AVATAR_PERFORMANCE_RATING_MINIMUM_TO_DISPLAY_DEFAULT = PerformanceRating.VeryPoor; + internal const PerformanceRating AVATAR_PERFORMANCE_RATING_MINIMUM_TO_DISPLAY_MIN = PerformanceRating.Medium; + internal const PerformanceRating AVATAR_PERFORMANCE_RATING_MINIMUM_TO_DISPLAY_MAX = PerformanceRating.VeryPoor; + #endif + + #endregion + + #region Public Delegates + + public delegate bool IgnoreDelegate(Component component); + + public delegate void FilterBlockCallback(); + + public static IgnoreDelegate ShouldIgnoreComponent { get; set; } + + #endregion + + #region Public Methods + + public static void CalculatePerformanceStats(string avatarName, GameObject avatarObject, AvatarPerformanceStats perfStats) + { + perfStats.Reset(); + perfStats.avatarName = avatarName; + + PerformanceScannerSet performanceScannerSet = GetPerformanceScannerSet(); + if(performanceScannerSet != null) + { + performanceScannerSet.RunPerformanceScan(avatarObject, perfStats, ShouldIgnoreComponentInternal); + } + + // cache performance ratings + perfStats.CalculateAllPerformanceRatings(); + } + + public static IEnumerator CalculatePerformanceStatsEnumerator(string avatarName, GameObject avatarObject, AvatarPerformanceStats perfStats) + { + perfStats.Reset(); + perfStats.avatarName = avatarName; + + PerformanceScannerSet performanceScannerSet = GetPerformanceScannerSet(); + if(performanceScannerSet != null) + { + yield return performanceScannerSet.RunPerformanceScanEnumerator(avatarObject, perfStats, ShouldIgnoreComponentInternal); + } + + // cache performance ratings + perfStats.CalculateAllPerformanceRatings(); + } + + public static IEnumerator ApplyPerformanceFiltersEnumerator(GameObject avatarObject, AvatarPerformanceStats perfStats, PerformanceRating minPerfRating, FilterBlockCallback onBlock) + { + // Performance Filtering is disabled. + if(minPerfRating == PerformanceRating.None) + { + yield break; + } + + PerformanceFilterSet performanceFilterSet = GetPerformanceFilterSet(); + if(performanceFilterSet == null) + { + yield break; + } + + bool avatarBlocked = false; + yield return performanceFilterSet.ApplyPerformanceFilters( + avatarObject, + perfStats, + minPerfRating, + ShouldIgnoreComponentInternal, + () => { avatarBlocked = true; } + ); + + if(!avatarBlocked) + { + yield break; + } + + VRC.Core.Logger.LogFormat( + "Avatar hidden due to low performance rating: [{0}] {1} - minimum setting: {2}", + perfStats.avatarName, + perfStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.Overall), + minPerfRating + ); + + onBlock(); + } + + #endregion + + #region Private Methods + + private static PerformanceScannerSet GetPerformanceScannerSet() + { + PerformanceScannerSet performanceScannerSet; + if(VRC.ValidationHelpers.IsStandalonePlatform()) + { + performanceScannerSet = Resources.Load("Validation/Performance/ScannerSets/PerformanceScannerSet_Windows"); + } + else + { + performanceScannerSet = Resources.Load("Validation/Performance/ScannerSets/PerformanceScannerSet_Quest"); + } + + return performanceScannerSet; + } + + private static PerformanceFilterSet GetPerformanceFilterSet() + { + PerformanceFilterSet performanceFilterSet; + if(VRC.ValidationHelpers.IsStandalonePlatform()) + { + performanceFilterSet = Resources.Load("Validation/Performance/FilterSets/PerformanceFilterSet_Windows"); + } + else + { + performanceFilterSet = Resources.Load("Validation/Performance/FilterSets/PerformanceFilterSet_Quest"); + } + + return performanceFilterSet; + } + + private static bool ShouldIgnoreComponentInternal(Component component) + { + if(Application.isEditor) + { + if(component == null) + { + return false; + } + + if(component.CompareTag("EditorOnly")) + { + return true; + } + } + + if(ShouldIgnoreComponent != null) + { + return ShouldIgnoreComponent(component); + } + + return false; + } + + #endregion + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/AvatarPerformance.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/AvatarPerformance.cs.meta new file mode 100644 index 00000000..8d06a338 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/AvatarPerformance.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 15ecac6f7fdc1bc4fb723fee6f4635dd +timeCreated: 1540944864 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/AvatarPerformanceCategory.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/AvatarPerformanceCategory.cs new file mode 100644 index 00000000..847ac62c --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/AvatarPerformanceCategory.cs @@ -0,0 +1,37 @@ +namespace VRC.SDKBase.Validation.Performance +{ + public enum AvatarPerformanceCategory + { + None, + + Overall, + + DownloadSize, + PolyCount, + AABB, + SkinnedMeshCount, + MeshCount, + MaterialCount, + DynamicBoneComponentCount, + DynamicBoneSimulatedBoneCount, + DynamicBoneColliderCount, + DynamicBoneCollisionCheckCount, + AnimatorCount, + BoneCount, + LightCount, + ParticleSystemCount, + ParticleTotalCount, + ParticleMaxMeshPolyCount, + ParticleTrailsEnabled, + ParticleCollisionEnabled, + TrailRendererCount, + LineRendererCount, + ClothCount, + ClothMaxVertices, + PhysicsColliderCount, + PhysicsRigidbodyCount, + AudioSourceCount, + + AvatarPerformanceCategoryCount + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/AvatarPerformanceCategory.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/AvatarPerformanceCategory.cs.meta new file mode 100644 index 00000000..449a3394 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/AvatarPerformanceCategory.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f1ce994297384ff1bc330196df61b7ca +timeCreated: 1561267912 \ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Filters.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Filters.meta new file mode 100644 index 00000000..b19c2f04 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Filters.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bf5b2b0296bbecc4dba509652ba3eb24 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Filters/AbstractPerformanceFilter.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Filters/AbstractPerformanceFilter.cs new file mode 100644 index 00000000..9896fcc9 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Filters/AbstractPerformanceFilter.cs @@ -0,0 +1,109 @@ +using System.Collections; +using UnityEngine; +using VRC.SDKBase.Validation.Performance.Stats; + +namespace VRC.SDKBase.Validation.Performance.Filters +{ + public abstract class AbstractPerformanceFilter : ScriptableObject + { + public abstract IEnumerator ApplyPerformanceFilter( + GameObject avatarObject, + AvatarPerformanceStats perfStats, + PerformanceRating ratingLimit, + AvatarPerformance.IgnoreDelegate shouldIgnoreComponent, + AvatarPerformance.FilterBlockCallback onBlock + ); + + protected static IEnumerator RemoveComponentsOfTypeEnumerator(GameObject target) where T : Component + { + if(target == null) + { + yield break; + } + + foreach(T targetComponent in target.GetComponentsInChildren(true)) + { + if(targetComponent == null || targetComponent.gameObject == null) + { + continue; + } + + #if VERBOSE_COMPONENT_REMOVAL + Debug.LogWarningFormat("Removing {0} comp from {1}", targetComponent.GetType().Name, targetComponent.gameObject.name); + #endif + + yield return RemoveComponent(targetComponent); + } + } + + protected static IEnumerator RemoveComponent(Component targetComponent) + { + yield return RemoveDependencies(targetComponent); + + Destroy(targetComponent); + yield return null; + } + + protected static IEnumerator RemoveDependencies(Component targetComponent) + { + if(targetComponent == null) + { + yield break; + } + + Component[] siblingComponents = targetComponent.GetComponents(); + if(siblingComponents == null || siblingComponents.Length == 0) + { + yield break; + } + + System.Type componentType = targetComponent.GetType(); + foreach(Component siblingComponent in siblingComponents) + { + if(siblingComponent == null) + { + continue; + } + + bool deleteMe = false; + object[] requireComponentAttributes = siblingComponent.GetType().GetCustomAttributes(typeof(RequireComponent), true); + if(requireComponentAttributes.Length == 0) + { + continue; + } + + foreach(var requireComponentObject in requireComponentAttributes) + { + RequireComponent requireComponentAttribute = requireComponentObject as RequireComponent; + if(requireComponentAttribute == null) + { + continue; + } + + if( + requireComponentAttribute.m_Type0 != componentType && + requireComponentAttribute.m_Type1 != componentType && + requireComponentAttribute.m_Type2 != componentType + ) + { + continue; + } + + deleteMe = true; + break; + } + + if(!deleteMe) + { + continue; + } + + #if VERBOSE_COMPONENT_REMOVAL + Debug.LogWarningFormat("Deleting component dependency {0} found on {1}", siblingComponent.GetType().Name, targetComponent.gameObject.name); + #endif + + yield return RemoveComponent(siblingComponent); + } + } + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Filters/AbstractPerformanceFilter.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Filters/AbstractPerformanceFilter.cs.meta new file mode 100644 index 00000000..6987057b --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Filters/AbstractPerformanceFilter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: abda65e062e44213aa3e1f4c82b400a8 +timeCreated: 1563937347 \ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/MeshUtils.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/MeshUtils.cs new file mode 100644 index 00000000..e5acd99f --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/MeshUtils.cs @@ -0,0 +1,33 @@ +using UnityEngine; + +namespace VRC.SDKBase.Validation.Performance +{ + public static class MeshUtils + { + private const uint INDICES_PER_TRIANGLE = 3U; + + public static uint GetMeshTriangleCount(Mesh sourceMesh) + { + if(sourceMesh == null) + { + return 0; + } + + // We can't use GetIndexCount if the mesh isn't readable so just return a huge number. + // The SDK Control Panel should show a warning in this case. + if(!sourceMesh.isReadable) + { + return uint.MaxValue; + } + + uint count = 0; + for(int i = 0; i < sourceMesh.subMeshCount; i++) + { + uint indexCount = sourceMesh.GetIndexCount(i); + count += indexCount / INDICES_PER_TRIANGLE; + } + + return count; + } + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/MeshUtils.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/MeshUtils.cs.meta new file mode 100644 index 00000000..4658d3db --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/MeshUtils.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f28c978154794266b38d686139c6b872 +timeCreated: 1561249515 \ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceFilterSet.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceFilterSet.cs new file mode 100644 index 00000000..b2637485 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceFilterSet.cs @@ -0,0 +1,46 @@ +using System.Collections; +using UnityEngine; +using VRC.SDKBase.Validation.Performance.Filters; +using VRC.SDKBase.Validation.Performance.Stats; + +namespace VRC.SDKBase.Validation.Performance +{ + #if VRC_CLIENT + [CreateAssetMenu( + fileName = "New PerformanceFilterSet", + menuName = "VRC Scriptable Objects/Performance/PerformanceFilterSet" + )] + #endif + public class PerformanceFilterSet : ScriptableObject + { + public AbstractPerformanceFilter[] performanceFilters; + + public IEnumerator ApplyPerformanceFilters( + GameObject avatarObject, + AvatarPerformanceStats perfStats, + PerformanceRating ratingLimit, + AvatarPerformance.IgnoreDelegate shouldIgnoreComponent, + AvatarPerformance.FilterBlockCallback onBlock + ) + { + foreach(AbstractPerformanceFilter performanceFilter in performanceFilters) + { + if(performanceFilter == null) + { + continue; + } + + bool avatarBlocked = false; + yield return performanceFilter.ApplyPerformanceFilter(avatarObject, perfStats, ratingLimit, shouldIgnoreComponent, () => { avatarBlocked = true; }); + + if(!avatarBlocked) + { + continue; + } + + onBlock(); + break; + } + } + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceFilterSet.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceFilterSet.cs.meta new file mode 100644 index 00000000..dce1427b --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceFilterSet.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8cdca9d06d1b4732b9ccb82a38bb8d9c +timeCreated: 1563939583 \ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceInfoDisplayLevel.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceInfoDisplayLevel.cs new file mode 100644 index 00000000..d132fe4a --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceInfoDisplayLevel.cs @@ -0,0 +1,12 @@ +namespace VRC.SDKBase.Validation.Performance +{ + public enum PerformanceInfoDisplayLevel + { + None, + + Verbose, + Info, + Warning, + Error + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceInfoDisplayLevel.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceInfoDisplayLevel.cs.meta new file mode 100644 index 00000000..c1ea78c5 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceInfoDisplayLevel.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a5ed7498cb1a46c78eab031f5f32448c +timeCreated: 1561267918 \ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceRating.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceRating.cs new file mode 100644 index 00000000..901d8494 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceRating.cs @@ -0,0 +1,12 @@ +namespace VRC.SDKBase.Validation.Performance +{ + public enum PerformanceRating + { + None = 0, + Excellent = 1, + Good = 2, + Medium = 3, + Poor = 4, + VeryPoor = 5 + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceRating.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceRating.cs.meta new file mode 100644 index 00000000..0175bfdb --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceRating.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5019a55ee9e2404c81bc61a39a010d8d +timeCreated: 1561267904 \ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceScannerSet.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceScannerSet.cs new file mode 100644 index 00000000..716c66f7 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceScannerSet.cs @@ -0,0 +1,44 @@ +using System.Collections; +using UnityEngine; +using VRC.SDKBase.Validation.Performance.Scanners; +using VRC.SDKBase.Validation.Performance.Stats; + +namespace VRC.SDKBase.Validation.Performance +{ + #if VRC_CLIENT + [CreateAssetMenu( + fileName = "New PerformanceScannerSet", + menuName = "VRC Scriptable Objects/Performance/PerformanceScannerSet" + )] + #endif + public class PerformanceScannerSet : ScriptableObject + { + public AbstractPerformanceScanner[] performanceScanners; + + public void RunPerformanceScan(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent) + { + foreach(AbstractPerformanceScanner performanceScanner in performanceScanners) + { + if(performanceScanner == null) + { + continue; + } + + performanceScanner.RunPerformanceScan(avatarObject, perfStats, shouldIgnoreComponent); + } + } + + public IEnumerator RunPerformanceScanEnumerator(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent) + { + foreach(AbstractPerformanceScanner performanceScanner in performanceScanners) + { + if(performanceScanner == null) + { + continue; + } + + yield return performanceScanner.RunPerformanceScanEnumerator(avatarObject, perfStats, shouldIgnoreComponent); + } + } + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceScannerSet.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceScannerSet.cs.meta new file mode 100644 index 00000000..7a3b582a --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/PerformanceScannerSet.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 4afb61f36d144fc381114cd7f78d13e7 +timeCreated: 1561259704 \ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners.meta new file mode 100644 index 00000000..3029e53c --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: edddcc1b6de3f554e8a13a0b94d47b96 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/AbstractPerformanceScanner.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/AbstractPerformanceScanner.cs new file mode 100644 index 00000000..9face97c --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/AbstractPerformanceScanner.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Profiling; +using VRC.SDKBase.Validation.Performance.Stats; + +namespace VRC.SDKBase.Validation.Performance.Scanners +{ + public abstract class AbstractPerformanceScanner : ScriptableObject + { + private const int MAXIMUM_COMPONENT_SCANS_PER_FRAME = 10; + private static int _componentScansThisFrame = 0; + private static int _componentScansFrameNumber = 0; + + private readonly Stack _coroutines = new Stack(); + + private bool _limitComponentScansPerFrame = true; + + public abstract IEnumerator RunPerformanceScanEnumerator(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent); + + public void RunPerformanceScan(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent) + { + _limitComponentScansPerFrame = false; + + try + { + _coroutines.Push(RunPerformanceScanEnumerator(avatarObject, perfStats, shouldIgnoreComponent)); + while(_coroutines.Count > 0) + { + IEnumerator currentCoroutine = _coroutines.Peek(); + if(currentCoroutine.MoveNext()) + { + IEnumerator nestedCoroutine = currentCoroutine.Current as IEnumerator; + if(nestedCoroutine != null) + { + _coroutines.Push(nestedCoroutine); + } + } + else + { + _coroutines.Pop(); + } + } + + _coroutines.Clear(); + } + finally + { + _limitComponentScansPerFrame = true; + } + } + + protected IEnumerator ScanAvatarForComponentsOfType(Type componentType, GameObject avatarObject, List destinationBuffer) + { + yield return HandleComponentScansPerFrameLimit(); + + Profiler.BeginSample("Component Scan"); + destinationBuffer.Clear(); + destinationBuffer.AddRange(avatarObject.GetComponentsInChildren(componentType, true)); + Profiler.EndSample(); + } + + protected IEnumerator ScanAvatarForComponentsOfType(GameObject avatarObject, List destinationBuffer) + { + yield return HandleComponentScansPerFrameLimit(); + + Profiler.BeginSample("Component Scan"); + destinationBuffer.Clear(); + avatarObject.GetComponentsInChildren(true, destinationBuffer); + Profiler.EndSample(); + yield return null; + } + + private IEnumerator HandleComponentScansPerFrameLimit() + { + if(!_limitComponentScansPerFrame) + { + yield break; + } + + while(_componentScansThisFrame >= MAXIMUM_COMPONENT_SCANS_PER_FRAME) + { + if(Time.frameCount > _componentScansFrameNumber) + { + _componentScansFrameNumber = Time.frameCount; + _componentScansThisFrame = 0; + break; + } + + yield return null; + } + + _componentScansThisFrame++; + } + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/AbstractPerformanceScanner.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/AbstractPerformanceScanner.cs.meta new file mode 100644 index 00000000..357ef0f0 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/AbstractPerformanceScanner.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0bd0691a021844f49444a04a959d6328 +timeCreated: 1561279121 \ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/AnimatorPerformanceScanner.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/AnimatorPerformanceScanner.cs new file mode 100644 index 00000000..6aa73010 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/AnimatorPerformanceScanner.cs @@ -0,0 +1,44 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using VRC.SDKBase.Validation.Performance.Stats; + +namespace VRC.SDKBase.Validation.Performance.Scanners +{ + #if VRC_CLIENT + [CreateAssetMenu( + fileName = "New AnimatorPerformanceScanner", + menuName = "VRC Scriptable Objects/Performance/Avatar/Scanners/AnimatorPerformanceScanner" + )] + #endif + public sealed class AnimatorPerformanceScanner : AbstractPerformanceScanner + { + public override IEnumerator RunPerformanceScanEnumerator(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent) + { + int animatorCount = 0; + + // Animators + List animatorBuffer = new List(); + yield return ScanAvatarForComponentsOfType(avatarObject, animatorBuffer); + if(shouldIgnoreComponent != null) + { + animatorBuffer.RemoveAll(c => shouldIgnoreComponent(c)); + } + + // ReSharper disable once UselessBinaryOperation + animatorCount += animatorBuffer.Count; + + // Animations + List animationBuffer = new List(); + yield return ScanAvatarForComponentsOfType(avatarObject, animationBuffer); + if(shouldIgnoreComponent != null) + { + animationBuffer.RemoveAll(c => shouldIgnoreComponent(c)); + } + + animatorCount += animationBuffer.Count; + + perfStats.animatorCount = animatorCount; + } + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/AnimatorPerformanceScanner.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/AnimatorPerformanceScanner.cs.meta new file mode 100644 index 00000000..edec0a0f --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/AnimatorPerformanceScanner.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 08c8e931d0544866a0f626855d9c1841 +timeCreated: 1561251363 \ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/AudioPerformanceScanner.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/AudioPerformanceScanner.cs new file mode 100644 index 00000000..a8a5944d --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/AudioPerformanceScanner.cs @@ -0,0 +1,29 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using VRC.SDKBase.Validation.Performance.Stats; + +namespace VRC.SDKBase.Validation.Performance.Scanners +{ + #if VRC_CLIENT + [CreateAssetMenu( + fileName = "New AudioPerformanceScanner", + menuName = "VRC Scriptable Objects/Performance/Avatar/Scanners/AudioPerformanceScanner" + )] + #endif + public sealed class AudioPerformanceScanner : AbstractPerformanceScanner + { + public override IEnumerator RunPerformanceScanEnumerator(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent) + { + // Audio Sources + List audioSourceBuffer = new List(); + yield return ScanAvatarForComponentsOfType(avatarObject, audioSourceBuffer); + if(shouldIgnoreComponent != null) + { + audioSourceBuffer.RemoveAll(c => shouldIgnoreComponent(c)); + } + + perfStats.audioSourceCount = audioSourceBuffer.Count; + } + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/AudioPerformanceScanner.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/AudioPerformanceScanner.cs.meta new file mode 100644 index 00000000..6cbd2a09 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/AudioPerformanceScanner.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b3a8bba736414d1aaa9e766da27b56b5 +timeCreated: 1561255618 \ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/ClothPerformanceScanner.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/ClothPerformanceScanner.cs new file mode 100644 index 00000000..d8332184 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/ClothPerformanceScanner.cs @@ -0,0 +1,48 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Profiling; +using VRC.SDKBase.Validation.Performance.Stats; + +namespace VRC.SDKBase.Validation.Performance.Scanners +{ + #if VRC_CLIENT + [CreateAssetMenu( + fileName = "New ClothPerformanceScanner", + menuName = "VRC Scriptable Objects/Performance/Avatar/Scanners/ClothPerformanceScanner" + )] + #endif + public sealed class ClothPerformanceScanner : AbstractPerformanceScanner + { + public override IEnumerator RunPerformanceScanEnumerator(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent) + { + // Cloth + List clothBuffer = new List(); + yield return ScanAvatarForComponentsOfType(avatarObject, clothBuffer); + if(shouldIgnoreComponent != null) + { + clothBuffer.RemoveAll(c => shouldIgnoreComponent(c)); + } + + int totalClothVertices = 0; + foreach(Cloth cloth in clothBuffer) + { + if(cloth == null) + { + continue; + } + + Vector3[] clothVertices = cloth.vertices; + if(clothVertices == null) + { + continue; + } + + totalClothVertices += clothVertices.Length; + } + + perfStats.clothCount = clothBuffer.Count; + perfStats.clothMaxVertices = totalClothVertices; + } + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/ClothPerformanceScanner.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/ClothPerformanceScanner.cs.meta new file mode 100644 index 00000000..b04d8aef --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/ClothPerformanceScanner.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0cec88b5a46f459195f10a2f11fddb2f +timeCreated: 1561255843 \ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/DynamicBonePerformanceScanner.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/DynamicBonePerformanceScanner.cs new file mode 100644 index 00000000..860df33a --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/DynamicBonePerformanceScanner.cs @@ -0,0 +1,191 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using UnityEngine; +using UnityEngine.Profiling; +using VRC.SDKBase.Validation.Performance.Stats; + +namespace VRC.SDKBase.Validation.Performance.Scanners +{ + #if VRC_CLIENT + [CreateAssetMenu( + fileName = "New DynamicBonePerformanceScanner", + menuName = "VRC Scriptable Objects/Performance/Avatar/Scanners/DynamicBonePerformanceScanner" + )] + #endif + public sealed class DynamicBonePerformanceScanner : AbstractPerformanceScanner + { + private Type _dynamicBoneType; + private FieldInfo _dynamicBoneRootFieldInfo; + private FieldInfo _dynamicBoneExclusionsFieldInfo; + private FieldInfo _dynamicBoneCollidersFieldInfo; + private FieldInfo _dynamicBoneEndLengthFieldInfo; + private FieldInfo _dynamicBoneEndOffsetFieldInfo; + + private void Awake() + { + FindDynamicBoneTypes(); + } + + public override IEnumerator RunPerformanceScanEnumerator(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent) + { + if(_dynamicBoneType == null) + { + yield break; + } + + // Dynamic Bone as Component + List dynamicBoneComponentBuffer = new List(); + List dynamicBoneColliderObjectBuffer = new List(); + yield return ScanAvatarForComponentsOfType(_dynamicBoneType, avatarObject, dynamicBoneComponentBuffer); + if(shouldIgnoreComponent != null) + { + dynamicBoneComponentBuffer.RemoveAll(c => shouldIgnoreComponent(c)); + } + + int totalSimulatedBoneCount = 0; + int totalCollisionChecks = 0; + + Profiler.BeginSample("Analyze Dynamic Bones"); + foreach(Component dynamicBone in dynamicBoneComponentBuffer) + { + Profiler.BeginSample("Single Dynamic Bone Component"); + int simulatedBones = 0; + + // Add extra bones to the end of each chain if end bones are being used. + float endLength = (float)_dynamicBoneEndLengthFieldInfo.GetValue(dynamicBone); + Vector3 endOffset = (Vector3)_dynamicBoneEndOffsetFieldInfo.GetValue(dynamicBone); + bool hasEndBones = endLength > 0 || endOffset != Vector3.zero; + + Transform root = (Transform)_dynamicBoneRootFieldInfo.GetValue(dynamicBone); + if(root != null) + { + List exclusions = (List)_dynamicBoneExclusionsFieldInfo.GetValue(dynamicBone); + + // Calculate number of simulated bones for the hierarchy + simulatedBones = CountTransformsRecursively(root, exclusions, hasEndBones); + totalSimulatedBoneCount += simulatedBones; + } + + int colliderListEntryCount = 0; + IList colliderList = (IList)_dynamicBoneCollidersFieldInfo.GetValue(dynamicBone); + if(colliderList != null) + { + foreach(object collider in colliderList) + { + colliderListEntryCount += 1; + if(collider != null && !dynamicBoneColliderObjectBuffer.Contains(collider)) + { + dynamicBoneColliderObjectBuffer.Add(collider); + } + } + } + + // The root bone is skipped in collision checks. + totalCollisionChecks += (simulatedBones - 1) * colliderListEntryCount; + Profiler.EndSample(); + } + + Profiler.EndSample(); + + yield return null; + + perfStats.dynamicBoneComponentCount = dynamicBoneComponentBuffer.Count; + perfStats.dynamicBoneSimulatedBoneCount = totalSimulatedBoneCount; + perfStats.dynamicBoneColliderCount = dynamicBoneColliderObjectBuffer.Count; + perfStats.dynamicBoneCollisionCheckCount = totalCollisionChecks; + } + + private void FindDynamicBoneTypes() + { + if(_dynamicBoneType != null) + { + return; + } + + Type dyBoneType = ValidationUtils.GetTypeFromName("DynamicBone"); + if(dyBoneType == null) + { + return; + } + + Type dyBoneColliderType = ValidationUtils.GetTypeFromName("DynamicBoneColliderBase") ?? ValidationUtils.GetTypeFromName("DynamicBoneCollider"); + if(dyBoneColliderType == null) + { + return; + } + + FieldInfo rootFieldInfo = dyBoneType.GetField("m_Root", BindingFlags.Public | BindingFlags.Instance); + if(rootFieldInfo == null || rootFieldInfo.FieldType != typeof(Transform)) + { + return; + } + + FieldInfo exclusionsFieldInfo = dyBoneType.GetField("m_Exclusions", BindingFlags.Public | BindingFlags.Instance); + if(exclusionsFieldInfo == null || exclusionsFieldInfo.FieldType != typeof(List)) + { + return; + } + + FieldInfo collidersFieldInfo = dyBoneType.GetField("m_Colliders", BindingFlags.Public | BindingFlags.Instance); + if(collidersFieldInfo == null || collidersFieldInfo.FieldType.GetGenericTypeDefinition() != typeof(List<>) || + collidersFieldInfo.FieldType.GetGenericArguments().Single() != dyBoneColliderType) + { + return; + } + + FieldInfo endLengthFieldInfo = dyBoneType.GetField("m_EndLength", BindingFlags.Public | BindingFlags.Instance); + if(endLengthFieldInfo == null || endLengthFieldInfo.FieldType != typeof(float)) + { + return; + } + + FieldInfo endOffsetFieldInfo = dyBoneType.GetField("m_EndOffset", BindingFlags.Public | BindingFlags.Instance); + if(endOffsetFieldInfo == null || endOffsetFieldInfo.FieldType != typeof(Vector3)) + { + return; + } + + _dynamicBoneType = dyBoneType; + _dynamicBoneRootFieldInfo = rootFieldInfo; + _dynamicBoneExclusionsFieldInfo = exclusionsFieldInfo; + _dynamicBoneCollidersFieldInfo = collidersFieldInfo; + _dynamicBoneEndLengthFieldInfo = endLengthFieldInfo; + _dynamicBoneEndOffsetFieldInfo = endOffsetFieldInfo; + } + + // Like DynamicBone itself exclusions only apply to children of the current bone. + // This means the root bone itself never excluded. + private static int CountTransformsRecursively(Transform transform, List exclusions, bool addEndBones) + { + if(transform == null) + { + return 0; + } + + int count = 1; + int childCount = transform.childCount; + if(childCount > 0) + { + foreach(Transform child in transform) + { + if(exclusions == null || !exclusions.Contains(child)) + { + count += CountTransformsRecursively(child, exclusions, addEndBones); + } + } + } + else + { + if(addEndBones) + { + count++; + } + } + + return count; + } + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/DynamicBonePerformanceScanner.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/DynamicBonePerformanceScanner.cs.meta new file mode 100644 index 00000000..60f0db5a --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/DynamicBonePerformanceScanner.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a226df494ef04404a9a47c714822ab9f +timeCreated: 1561251560 \ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/LightPerformanceScanner.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/LightPerformanceScanner.cs new file mode 100644 index 00000000..8d86c6b5 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/LightPerformanceScanner.cs @@ -0,0 +1,29 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using VRC.SDKBase.Validation.Performance.Stats; + +namespace VRC.SDKBase.Validation.Performance.Scanners +{ + #if VRC_CLIENT + [CreateAssetMenu( + fileName = "New LightPerformanceScanner", + menuName = "VRC Scriptable Objects/Performance/Avatar/Scanners/LightPerformanceScanner" + )] + #endif + public sealed class LightPerformanceScanner : AbstractPerformanceScanner + { + public override IEnumerator RunPerformanceScanEnumerator(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent) + { + // Lights + List lightBuffer = new List(); + yield return ScanAvatarForComponentsOfType(avatarObject, lightBuffer); + if(shouldIgnoreComponent != null) + { + lightBuffer.RemoveAll(c => shouldIgnoreComponent(c)); + } + + perfStats.lightCount = lightBuffer.Count; + } + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/LightPerformanceScanner.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/LightPerformanceScanner.cs.meta new file mode 100644 index 00000000..9c346056 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/LightPerformanceScanner.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 405778fdc32c44c1bb9fdd0476fb0007 +timeCreated: 1561256390 \ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/LineRendererPerformanceScanner.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/LineRendererPerformanceScanner.cs new file mode 100644 index 00000000..1d1faa85 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/LineRendererPerformanceScanner.cs @@ -0,0 +1,31 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using VRC.SDKBase.Validation.Performance.Stats; + +namespace VRC.SDKBase.Validation.Performance.Scanners +{ + #if VRC_CLIENT + [CreateAssetMenu( + fileName = "New LineRendererPerformanceScanner", + menuName = "VRC Scriptable Objects/Performance/Avatar/Scanners/LineRendererPerformanceScanner" + )] + #endif + public sealed class LineRendererPerformanceScanner : AbstractPerformanceScanner + { + public override IEnumerator RunPerformanceScanEnumerator(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent) + { + // Line Renderers + List lineRendererBuffer = new List(); + yield return ScanAvatarForComponentsOfType(avatarObject, lineRendererBuffer); + if(shouldIgnoreComponent != null) + { + lineRendererBuffer.RemoveAll(c => shouldIgnoreComponent(c)); + } + + int numLineRenderers = lineRendererBuffer.Count; + perfStats.lineRendererCount = numLineRenderers; + perfStats.materialCount = perfStats.materialCount.GetValueOrDefault() + numLineRenderers; + } + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/LineRendererPerformanceScanner.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/LineRendererPerformanceScanner.cs.meta new file mode 100644 index 00000000..79875a56 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/LineRendererPerformanceScanner.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ec87392b85844f7bb526a48ec866a8f0 +timeCreated: 1561253047 \ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/MeshPerformanceScanner.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/MeshPerformanceScanner.cs new file mode 100644 index 00000000..9b5b1201 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/MeshPerformanceScanner.cs @@ -0,0 +1,266 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Profiling; +using VRC.SDKBase.Validation.Performance.Stats; + +namespace VRC.SDKBase.Validation.Performance.Scanners +{ + #if VRC_CLIENT + [CreateAssetMenu( + fileName = "New MeshPerformanceScanner", + menuName = "VRC Scriptable Objects/Performance/Avatar/Scanners/MeshPerformanceScanner" + )] + #endif + public sealed class MeshPerformanceScanner : AbstractPerformanceScanner + { + public override IEnumerator RunPerformanceScanEnumerator(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent) + { + // Renderers + List rendererBuffer = new List(16); + yield return ScanAvatarForComponentsOfType(avatarObject, rendererBuffer); + if(shouldIgnoreComponent != null) + { + rendererBuffer.RemoveAll(c => shouldIgnoreComponent(c)); + } + + yield return AnalyzeGeometry(avatarObject, rendererBuffer, perfStats); + AnalyzeMeshRenderers(rendererBuffer, perfStats); + AnalyzeSkinnedMeshRenderers(rendererBuffer, perfStats); + + + yield return null; + } + + private static uint CalculateRendererPolyCount(Renderer renderer) + { + Mesh sharedMesh = null; + SkinnedMeshRenderer skinnedMeshRenderer = renderer as SkinnedMeshRenderer; + if(skinnedMeshRenderer != null) + { + sharedMesh = skinnedMeshRenderer.sharedMesh; + } + + if(sharedMesh == null) + { + MeshRenderer meshRenderer = renderer as MeshRenderer; + if(meshRenderer != null) + { + MeshFilter meshFilter = meshRenderer.GetComponent(); + if(meshFilter != null) + { + sharedMesh = meshFilter.sharedMesh; + } + } + } + + if(sharedMesh == null) + { + return 0; + } + + return MeshUtils.GetMeshTriangleCount(sharedMesh); + } + + private static bool RendererHasMesh(Renderer renderer) + { + MeshRenderer meshRenderer = renderer as MeshRenderer; + if(meshRenderer != null) + { + MeshFilter meshFilter = meshRenderer.GetComponent(); + if(meshFilter == null) + { + return false; + } + + return meshFilter.sharedMesh != null; + } + + SkinnedMeshRenderer skinnedMeshRenderer = renderer as SkinnedMeshRenderer; + if(skinnedMeshRenderer != null) + { + return skinnedMeshRenderer.sharedMesh != null; + } + + return false; + } + + private IEnumerator AnalyzeGeometry(GameObject avatarObject, IEnumerable renderers, AvatarPerformanceStats perfStats) + { + List lodGroupRendererIgnoreBuffer = new List(16); + List lodBuffer = new List(16); + + ulong polyCount = 0; + Bounds bounds = new Bounds(avatarObject.transform.position, Vector3.zero); + + yield return ScanAvatarForComponentsOfType(avatarObject, lodBuffer); + try + { + foreach(LODGroup lodGroup in lodBuffer) + { + LOD[] lodLevels = lodGroup.GetLODs(); + + ulong highestLodPolyCount = 0; + foreach(LOD lod in lodLevels) + { + uint thisLodPolyCount = 0; + foreach(Renderer renderer in lod.renderers) + { + lodGroupRendererIgnoreBuffer.Add(renderer); + checked + { + thisLodPolyCount += CalculateRendererPolyCount(renderer); + } + } + + if(thisLodPolyCount > highestLodPolyCount) + { + highestLodPolyCount = thisLodPolyCount; + } + } + + checked + { + polyCount += highestLodPolyCount; + } + } + } + catch(OverflowException e) + { + VRC.Core.Logger.Log("Overflow exception while analyzing geometry, assuming max value:" + e.ToString(), VRC.Core.DebugLevel.All); + polyCount = uint.MaxValue; + } + + Profiler.BeginSample("Calculate Total Polygon Count and Bounds"); + foreach(Renderer renderer in renderers) + { + Profiler.BeginSample("Single Renderer"); + if(renderer is MeshRenderer || renderer is SkinnedMeshRenderer) + { + if(!RendererHasMesh(renderer)) + { + Profiler.EndSample(); + continue; + } + + bounds.Encapsulate(renderer.bounds); + } + + if(lodGroupRendererIgnoreBuffer.Contains(renderer)) + { + Profiler.EndSample(); + continue; + } + + polyCount += CalculateRendererPolyCount(renderer); + Profiler.EndSample(); + } + + Profiler.EndSample(); + + bounds.center -= avatarObject.transform.position; + + lodGroupRendererIgnoreBuffer.Clear(); + lodBuffer.Clear(); + + perfStats.polyCount = polyCount > int.MaxValue ? int.MaxValue : (int)polyCount; + perfStats.aabb = bounds; + } + + private static void AnalyzeSkinnedMeshRenderers(IEnumerable renderers, AvatarPerformanceStats perfStats) + { + Profiler.BeginSample("AnalyzeSkinnedMeshRenderers"); + int count = 0; + int materialSlots = 0; + int skinnedBoneCount = 0; + HashSet transformIgnoreBuffer = new HashSet(); + + foreach(Renderer renderer in renderers) + { + Profiler.BeginSample("Analyze SkinnedMeshRenderer"); + SkinnedMeshRenderer skinnedMeshRenderer = renderer as SkinnedMeshRenderer; + if(skinnedMeshRenderer == null) + { + Profiler.EndSample(); + continue; + } + + count++; + + Mesh sharedMesh = skinnedMeshRenderer.sharedMesh; + if(sharedMesh != null) + { + materialSlots += sharedMesh.subMeshCount; + } + + // bone count + Profiler.BeginSample("Count Bones"); + Transform[] bones = skinnedMeshRenderer.bones; + foreach(Transform bone in bones) + { + Profiler.BeginSample("Count Bone"); + if(bone == null || transformIgnoreBuffer.Contains(bone)) + { + Profiler.EndSample(); + continue; + } + + transformIgnoreBuffer.Add(bone); + skinnedBoneCount++; + Profiler.EndSample(); + } + + Profiler.EndSample(); + + Profiler.EndSample(); + } + + transformIgnoreBuffer.Clear(); + Profiler.EndSample(); + + perfStats.skinnedMeshCount = count; + perfStats.boneCount = skinnedBoneCount; + perfStats.materialCount = perfStats.materialCount.GetValueOrDefault() + materialSlots; + } + + private static void AnalyzeMeshRenderers(IEnumerable renderers, AvatarPerformanceStats perfStats) + { + Profiler.BeginSample("AnalyzeMeshRenderers"); + int count = 0; + int materialSlots = 0; + foreach(Renderer renderer in renderers) + { + Profiler.BeginSample("Analyze MeshRenderer"); + MeshRenderer meshRenderer = renderer as MeshRenderer; + if(meshRenderer == null) + { + Profiler.EndSample(); + continue; + } + + count++; + + Profiler.BeginSample("Get MeshFilter"); + MeshFilter meshFilter = meshRenderer.GetComponent(); + Profiler.EndSample(); + if(meshFilter == null) + { + Profiler.EndSample(); + continue; + } + + Mesh sharedMesh = meshFilter.sharedMesh; + if(sharedMesh != null) + { + materialSlots += sharedMesh.subMeshCount; + } + } + + Profiler.EndSample(); + + perfStats.meshCount = count; + perfStats.materialCount = perfStats.materialCount.GetValueOrDefault() + materialSlots; + } + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/MeshPerformanceScanner.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/MeshPerformanceScanner.cs.meta new file mode 100644 index 00000000..ba7c1507 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/MeshPerformanceScanner.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 38bca10261df4ddfa10cff3b3bbb9428 +timeCreated: 1561249198 \ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/ParticlePerformanceScanner.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/ParticlePerformanceScanner.cs new file mode 100644 index 00000000..3d7acea8 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/ParticlePerformanceScanner.cs @@ -0,0 +1,114 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Profiling; +using VRC.SDKBase.Validation.Performance.Stats; + +namespace VRC.SDKBase.Validation.Performance.Scanners +{ + #if VRC_CLIENT + [CreateAssetMenu( + fileName = "New ParticlePerformanceScanner", + menuName = "VRC Scriptable Objects/Performance/Avatar/Scanners/ParticlePerformanceScanner" + )] + #endif + public sealed class ParticlePerformanceScanner : AbstractPerformanceScanner + { + public override IEnumerator RunPerformanceScanEnumerator(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent) + { + // Particle Systems + List particleSystemBuffer = new List(); + yield return ScanAvatarForComponentsOfType(avatarObject, particleSystemBuffer); + if(shouldIgnoreComponent != null) + { + particleSystemBuffer.RemoveAll(c => shouldIgnoreComponent(c)); + } + + AnalyzeParticleSystemRenderers(particleSystemBuffer, perfStats); + + yield return null; + } + + private static void AnalyzeParticleSystemRenderers(IEnumerable particleSystems, AvatarPerformanceStats perfStats) + { + int particleSystemCount = 0; + ulong particleTotalCount = 0; + ulong particleTotalMaxMeshPolyCount = 0; + bool particleTrailsEnabled = false; + bool particleCollisionEnabled = false; + int materialSlots = 0; + + Profiler.BeginSample("AnalyzeParticleSystemRenderers"); + foreach(ParticleSystem particleSystem in particleSystems) + { + Profiler.BeginSample("Single Particle System"); + int particleCount = particleSystem.main.maxParticles; + if(particleCount <= 0) + { + Profiler.EndSample(); + continue; + } + + particleSystemCount++; + particleTotalCount += (uint)particleCount; + + ParticleSystemRenderer particleSystemRenderer = particleSystem.GetComponent(); + if(particleSystemRenderer == null) + { + Profiler.EndSample(); + continue; + } + + materialSlots++; + + // mesh particles + if(particleSystemRenderer.renderMode == ParticleSystemRenderMode.Mesh && particleSystemRenderer.meshCount > 0) + { + uint highestPolyCount = 0; + + Mesh[] meshes = new Mesh[particleSystemRenderer.meshCount]; + int particleRendererMeshCount = particleSystemRenderer.GetMeshes(meshes); + for(int meshIndex = 0; meshIndex < particleRendererMeshCount; meshIndex++) + { + Mesh mesh = meshes[meshIndex]; + if(mesh == null) + { + continue; + } + + uint polyCount = MeshUtils.GetMeshTriangleCount(mesh); + if(polyCount > highestPolyCount) + { + highestPolyCount = polyCount; + } + } + + ulong maxMeshParticlePolyCount = (uint)particleCount * highestPolyCount; + particleTotalMaxMeshPolyCount += maxMeshParticlePolyCount; + } + + if(particleSystem.trails.enabled) + { + particleTrailsEnabled = true; + materialSlots++; + } + + if(particleSystem.collision.enabled) + { + particleCollisionEnabled = true; + } + + Profiler.EndSample(); + } + + Profiler.EndSample(); + + perfStats.particleSystemCount = particleSystemCount; + perfStats.particleTotalCount = particleTotalCount > int.MaxValue ? int.MaxValue : (int)particleTotalCount; + perfStats.particleMaxMeshPolyCount = particleTotalMaxMeshPolyCount > int.MaxValue ? int.MaxValue : (int)particleTotalMaxMeshPolyCount; + perfStats.particleTrailsEnabled = particleTrailsEnabled; + perfStats.particleCollisionEnabled = particleCollisionEnabled; + perfStats.materialCount = perfStats.materialCount.GetValueOrDefault() + materialSlots; + } + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/ParticlePerformanceScanner.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/ParticlePerformanceScanner.cs.meta new file mode 100644 index 00000000..54556038 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/ParticlePerformanceScanner.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 10723e354ff14f98a49ab797b3f005e6 +timeCreated: 1561250267 \ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/PhysicsPerformanceScanner.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/PhysicsPerformanceScanner.cs new file mode 100644 index 00000000..c6b643da --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/PhysicsPerformanceScanner.cs @@ -0,0 +1,64 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Profiling; +using VRC.SDKBase.Validation.Performance.Stats; + +namespace VRC.SDKBase.Validation.Performance.Scanners +{ + #if VRC_CLIENT + [CreateAssetMenu( + fileName = "New PhysicsPerformanceScanner", + menuName = "VRC Scriptable Objects/Performance/Avatar/Scanners/PhysicsPerformanceScanner" + )] + #endif + public sealed class PhysicsPerformanceScanner : AbstractPerformanceScanner + { + public override IEnumerator RunPerformanceScanEnumerator(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent) + { + // Colliders + List colliderBuffer = new List(); + yield return ScanAvatarForComponentsOfType(avatarObject, colliderBuffer); + colliderBuffer.RemoveAll( + o => + { + if(shouldIgnoreComponent != null && shouldIgnoreComponent(o)) + { + return true; + } + + if(o.GetComponent() != null) + { + return true; + } + + return false; + } + ); + + perfStats.physicsColliderCount = colliderBuffer.Count; + + // Rigidbodies + List rigidbodyBuffer = new List(); + yield return ScanAvatarForComponentsOfType(avatarObject, rigidbodyBuffer); + rigidbodyBuffer.RemoveAll( + o => + { + if(shouldIgnoreComponent != null && shouldIgnoreComponent(o)) + { + return true; + } + + if(o.GetComponent() != null) + { + return true; + } + + return false; + } + ); + + perfStats.physicsRigidbodyCount = rigidbodyBuffer.Count; + } + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/PhysicsPerformanceScanner.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/PhysicsPerformanceScanner.cs.meta new file mode 100644 index 00000000..ed550cf1 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/PhysicsPerformanceScanner.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6a94ecdeecd04f85824cc3244be5712a +timeCreated: 1561256481 \ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/TrailRendererPerformanceScanner.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/TrailRendererPerformanceScanner.cs new file mode 100644 index 00000000..c75e4cae --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/TrailRendererPerformanceScanner.cs @@ -0,0 +1,31 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using VRC.SDKBase.Validation.Performance.Stats; + +namespace VRC.SDKBase.Validation.Performance.Scanners +{ + #if VRC_CLIENT + [CreateAssetMenu( + fileName = "New TrailRendererPerformanceScanner", + menuName = "VRC Scriptable Objects/Performance/Avatar/Scanners/TrailRendererPerformanceScanner" + )] + #endif + public sealed class TrailRendererPerformanceScanner : AbstractPerformanceScanner + { + public override IEnumerator RunPerformanceScanEnumerator(GameObject avatarObject, AvatarPerformanceStats perfStats, AvatarPerformance.IgnoreDelegate shouldIgnoreComponent) + { + // Trail Renderers + List trailRendererBuffer = new List(); + yield return ScanAvatarForComponentsOfType(avatarObject, trailRendererBuffer); + if(shouldIgnoreComponent != null) + { + trailRendererBuffer.RemoveAll(c => shouldIgnoreComponent(c)); + } + + int numTrailRenderers = trailRendererBuffer.Count; + perfStats.trailRendererCount = numTrailRenderers; + perfStats.materialCount = perfStats.materialCount.GetValueOrDefault() + numTrailRenderers; + } + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/TrailRendererPerformanceScanner.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/TrailRendererPerformanceScanner.cs.meta new file mode 100644 index 00000000..028dd032 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Scanners/TrailRendererPerformanceScanner.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2efd714b564547b4be1ebd1f2700668b +timeCreated: 1561251810 \ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats.meta new file mode 100644 index 00000000..39e091dc --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6970bf241e7266748992480464b59687 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats/AvatarPerformanceStats.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats/AvatarPerformanceStats.cs new file mode 100644 index 00000000..44fd4041 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats/AvatarPerformanceStats.cs @@ -0,0 +1,757 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using UnityEngine; + +namespace VRC.SDKBase.Validation.Performance.Stats +{ + public class AvatarPerformanceStats + { + private delegate int ComparePerformanceStatsDelegate(AvatarPerformanceStats stats, AvatarPerformanceStatsLevel statsLevel); + + #region Public Fields + + public string avatarName; + + public int? polyCount; + public Bounds? aabb; + public int? skinnedMeshCount; + public int? meshCount; + public int? materialCount; + public int? animatorCount; + public int? boneCount; + public int? lightCount; + public int? particleSystemCount; + public int? particleTotalCount; + public int? particleMaxMeshPolyCount; + public bool? particleTrailsEnabled; + public bool? particleCollisionEnabled; + public int? trailRendererCount; + public int? lineRendererCount; + public int? dynamicBoneComponentCount; + public int? dynamicBoneSimulatedBoneCount; + public int? dynamicBoneColliderCount; + public int? dynamicBoneCollisionCheckCount; // number of collider simulated bones excluding the root multiplied by the number of colliders + public int? clothCount; + public int? clothMaxVertices; + public int? physicsColliderCount; + public int? physicsRigidbodyCount; + public int? audioSourceCount; + public float? downloadSize; + + #endregion + + #region Private Fields + + private readonly PerformanceRating[] _performanceRatingCache; + + private static readonly ImmutableArray _performanceCategories = Enum.GetValues(typeof(AvatarPerformanceCategory)) + .Cast() + .ToImmutableArray(); + + private static readonly Dictionary _performanceCategoryDisplayNames = new Dictionary + { + {AvatarPerformanceCategory.PolyCount, "Polygons"}, + {AvatarPerformanceCategory.AABB, "Bounds"}, + {AvatarPerformanceCategory.SkinnedMeshCount, "Skinned Meshes"}, + {AvatarPerformanceCategory.MeshCount, "Meshes"}, + {AvatarPerformanceCategory.MaterialCount, "Material Slots"}, + {AvatarPerformanceCategory.AnimatorCount, "Animators"}, + {AvatarPerformanceCategory.BoneCount, "Bones"}, + {AvatarPerformanceCategory.LightCount, "Lights"}, + {AvatarPerformanceCategory.ParticleSystemCount, "Particle Systems"}, + {AvatarPerformanceCategory.ParticleTotalCount, "Total Max Particles"}, + {AvatarPerformanceCategory.ParticleMaxMeshPolyCount, "Mesh Particle Max Polygons"}, + {AvatarPerformanceCategory.ParticleTrailsEnabled, "Particle Trails Enabled"}, + {AvatarPerformanceCategory.ParticleCollisionEnabled, "Particle Collision Enabled"}, + {AvatarPerformanceCategory.TrailRendererCount, "Trail Renderers"}, + {AvatarPerformanceCategory.LineRendererCount, "Line Renderers"}, + {AvatarPerformanceCategory.DynamicBoneComponentCount, "Dynamic Bone Components"}, + {AvatarPerformanceCategory.DynamicBoneSimulatedBoneCount, "Dynamic Bone Transforms"}, + {AvatarPerformanceCategory.DynamicBoneColliderCount, "Dynamic Bone Colliders"}, + {AvatarPerformanceCategory.DynamicBoneCollisionCheckCount, "Dynamic Bone Collision Check Count"}, + {AvatarPerformanceCategory.ClothCount, "Cloths"}, + {AvatarPerformanceCategory.ClothMaxVertices, "Total Cloth Vertices"}, + {AvatarPerformanceCategory.PhysicsColliderCount, "Physics Colliders"}, + {AvatarPerformanceCategory.PhysicsRigidbodyCount, "Physics Rigidbodies"}, + {AvatarPerformanceCategory.AudioSourceCount, "Audio Sources"}, + {AvatarPerformanceCategory.DownloadSize, "Download Size"}, + }; + + private static readonly Dictionary _performanceRatingDisplayNames = new Dictionary + { + {PerformanceRating.None, "None"}, + {PerformanceRating.Excellent, "Excellent"}, + {PerformanceRating.Good, "Good"}, + {PerformanceRating.Medium, "Medium"}, + {PerformanceRating.Poor, "Poor"}, + {PerformanceRating.VeryPoor, "VeryPoor"} + }; + + #endregion + + #region Initialization + + private static AvatarPerformanceStatsLevelSet _performanceStatsLevelSet = null; + + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)] + public static void Initialize() + { + if(_performanceStatsLevelSet != null) + { + return; + } + + _performanceStatsLevelSet = Resources.Load(GetPlatformPerformanceStatLevels()); + } + + private static string GetPlatformPerformanceStatLevels() + { + #if UNITY_ANDROID + return "Validation/Performance/StatsLevels/Quest/AvatarPerformanceStatLevels_Quest"; + #else + return "Validation/Performance/StatsLevels/Windows/AvatarPerformanceStatLevels_Windows"; + #endif + } + + #endregion + + #region Constructors + + public AvatarPerformanceStats() + { + _performanceRatingCache = new PerformanceRating[(int)AvatarPerformanceCategory.AvatarPerformanceCategoryCount]; + } + + #endregion + + #region Public Methods + + public void Reset() + { + avatarName = null; + polyCount = null; + aabb = null; + skinnedMeshCount = null; + meshCount = null; + materialCount = null; + animatorCount = null; + boneCount = null; + lightCount = null; + particleSystemCount = null; + particleTotalCount = null; + particleMaxMeshPolyCount = null; + particleTrailsEnabled = null; + particleCollisionEnabled = null; + trailRendererCount = null; + lineRendererCount = null; + dynamicBoneComponentCount = null; + dynamicBoneSimulatedBoneCount = null; + dynamicBoneColliderCount = null; + dynamicBoneCollisionCheckCount = null; + clothCount = null; + clothMaxVertices = null; + physicsColliderCount = null; + physicsRigidbodyCount = null; + audioSourceCount = null; + downloadSize = null; + + for(int i = 0; i < (int)AvatarPerformanceCategory.AvatarPerformanceCategoryCount; i++) + { + _performanceRatingCache[i] = PerformanceRating.None; + } + } + + public Snapshot GetSnapshot() + { + return new Snapshot(this); + } + + public PerformanceRating GetPerformanceRatingForCategory(AvatarPerformanceCategory perfCategory) + { + if(_performanceRatingCache[(int)perfCategory] == PerformanceRating.None) + { + _performanceRatingCache[(int)perfCategory] = CalculatePerformanceRatingForCategory(perfCategory); + } + + return _performanceRatingCache[(int)perfCategory]; + } + + public void CalculateAllPerformanceRatings() + { + for(int i = 0; i < _performanceRatingCache.Length; i++) + { + _performanceRatingCache[i] = PerformanceRating.None; + } + + foreach(AvatarPerformanceCategory perfCategory in _performanceCategories) + { + if(perfCategory == AvatarPerformanceCategory.None || + perfCategory == AvatarPerformanceCategory.AvatarPerformanceCategoryCount) + { + continue; + } + + if(_performanceRatingCache[(int)perfCategory] == PerformanceRating.None) + { + _performanceRatingCache[(int)perfCategory] = CalculatePerformanceRatingForCategory(perfCategory); + } + } + } + + public static string GetPerformanceCategoryDisplayName(AvatarPerformanceCategory category) + { + return _performanceCategoryDisplayNames[category]; + } + + public static string GetPerformanceRatingDisplayName(PerformanceRating rating) + { + return _performanceRatingDisplayNames[rating]; + } + + public static AvatarPerformanceStatsLevel GetStatLevelForRating(PerformanceRating rating) + { + switch(rating) + { + case PerformanceRating.None: + return _performanceStatsLevelSet.excellent; + + case PerformanceRating.Excellent: + return _performanceStatsLevelSet.excellent; + + case PerformanceRating.Good: + return _performanceStatsLevelSet.good; + + case PerformanceRating.Medium: + return _performanceStatsLevelSet.medium; + + case PerformanceRating.Poor: + return _performanceStatsLevelSet.poor; + + case PerformanceRating.VeryPoor: + return _performanceStatsLevelSet.poor; + + default: + return _performanceStatsLevelSet.excellent; + } + } + + #endregion + + #region Private Methods + + private PerformanceRating CalculatePerformanceRatingForCategory(AvatarPerformanceCategory perfCategory) + { + switch(perfCategory) + { + case AvatarPerformanceCategory.Overall: + { + PerformanceRating maxRating = PerformanceRating.None; + + foreach(AvatarPerformanceCategory category in _performanceCategories) + { + if(category == AvatarPerformanceCategory.None || + category == AvatarPerformanceCategory.Overall || + category == AvatarPerformanceCategory.AvatarPerformanceCategoryCount) + { + continue; + } + + PerformanceRating rating = GetPerformanceRatingForCategory(category); + if(rating > maxRating) + { + maxRating = rating; + } + } + + return maxRating; + } + case AvatarPerformanceCategory.PolyCount: + { + if(!polyCount.HasValue) + { + return PerformanceRating.None; + } + + return CalculatePerformanceRating((x, y) => x.polyCount.GetValueOrDefault() - y.polyCount); + } + case AvatarPerformanceCategory.AABB: + { + if(!aabb.HasValue) + { + return PerformanceRating.None; + } + + return CalculatePerformanceRating( + (x, y) => + ApproxLessOrEqual(y.aabb.extents.x, 0.0f) || // -1 extents means "no AABB limit" + ( + ApproxLessOrEqual(x.aabb.GetValueOrDefault().extents.x, y.aabb.extents.x) && + ApproxLessOrEqual(x.aabb.GetValueOrDefault().extents.y, y.aabb.extents.y) && + ApproxLessOrEqual(x.aabb.GetValueOrDefault().extents.z, y.aabb.extents.z)) + ? -1 + : 1 + ); + } + case AvatarPerformanceCategory.SkinnedMeshCount: + { + if(!skinnedMeshCount.HasValue) + { + return PerformanceRating.None; + } + + return CalculatePerformanceRating((x, y) => x.skinnedMeshCount.GetValueOrDefault() - y.skinnedMeshCount); + } + case AvatarPerformanceCategory.MeshCount: + { + if(!meshCount.HasValue) + { + return PerformanceRating.None; + } + + return CalculatePerformanceRating((x, y) => x.meshCount.GetValueOrDefault() - y.meshCount); + } + case AvatarPerformanceCategory.MaterialCount: + { + if(!materialCount.HasValue) + { + return PerformanceRating.None; + } + + return CalculatePerformanceRating((x, y) => x.materialCount.GetValueOrDefault() - y.materialCount); + } + case AvatarPerformanceCategory.AnimatorCount: + { + if(!animatorCount.HasValue) + { + return PerformanceRating.None; + } + + return CalculatePerformanceRating((x, y) => x.animatorCount.GetValueOrDefault() - y.animatorCount); + } + case AvatarPerformanceCategory.BoneCount: + { + if(!boneCount.HasValue) + { + return PerformanceRating.None; + } + + return CalculatePerformanceRating((x, y) => x.boneCount.GetValueOrDefault() - y.boneCount); + } + case AvatarPerformanceCategory.LightCount: + { + if(!lightCount.HasValue) + { + return PerformanceRating.None; + } + + return CalculatePerformanceRating((x, y) => x.lightCount.GetValueOrDefault() - y.lightCount); + } + case AvatarPerformanceCategory.ParticleSystemCount: + { + if(!particleSystemCount.HasValue) + { + return PerformanceRating.None; + } + + return CalculatePerformanceRating((x, y) => x.particleSystemCount.GetValueOrDefault() - y.particleSystemCount); + } + case AvatarPerformanceCategory.ParticleTotalCount: + { + if(!particleTotalCount.HasValue) + { + return PerformanceRating.None; + } + + return CalculatePerformanceRating((x, y) => x.particleTotalCount.GetValueOrDefault() - y.particleTotalCount); + } + case AvatarPerformanceCategory.ParticleMaxMeshPolyCount: + { + if(!particleMaxMeshPolyCount.HasValue) + { + return PerformanceRating.None; + } + + return CalculatePerformanceRating((x, y) => x.particleMaxMeshPolyCount.GetValueOrDefault() - y.particleMaxMeshPolyCount); + } + case AvatarPerformanceCategory.ParticleTrailsEnabled: + { + if(!particleTrailsEnabled.HasValue) + { + return PerformanceRating.None; + } + + return CalculatePerformanceRating( + (x, y) => + { + if(x.particleTrailsEnabled == y.particleTrailsEnabled) + { + return 0; + } + + return x.particleTrailsEnabled.GetValueOrDefault() ? 1 : -1; + }); + } + case AvatarPerformanceCategory.ParticleCollisionEnabled: + { + if(!particleCollisionEnabled.HasValue) + { + return PerformanceRating.None; + } + + return CalculatePerformanceRating( + (x, y) => + { + if(x.particleCollisionEnabled == y.particleCollisionEnabled) + { + return 0; + } + + return x.particleCollisionEnabled.GetValueOrDefault() ? 1 : -1; + }); + } + case AvatarPerformanceCategory.TrailRendererCount: + { + if(!trailRendererCount.HasValue) + { + return PerformanceRating.None; + } + + return CalculatePerformanceRating((x, y) => x.trailRendererCount.GetValueOrDefault() - y.trailRendererCount); + } + case AvatarPerformanceCategory.LineRendererCount: + { + if(!lineRendererCount.HasValue) + { + return PerformanceRating.None; + } + + return CalculatePerformanceRating((x, y) => x.lineRendererCount.GetValueOrDefault() - y.lineRendererCount); + } + case AvatarPerformanceCategory.DynamicBoneComponentCount: + { + if(!dynamicBoneComponentCount.HasValue) + { + return PerformanceRating.None; + } + + return CalculatePerformanceRating((x, y) => x.dynamicBoneComponentCount.GetValueOrDefault() - y.dynamicBoneComponentCount); + } + case AvatarPerformanceCategory.DynamicBoneSimulatedBoneCount: + { + if(!dynamicBoneSimulatedBoneCount.HasValue) + { + return PerformanceRating.None; + } + + return CalculatePerformanceRating((x, y) => x.dynamicBoneSimulatedBoneCount.GetValueOrDefault() - y.dynamicBoneSimulatedBoneCount); + } + case AvatarPerformanceCategory.DynamicBoneColliderCount: + { + if(!dynamicBoneColliderCount.HasValue) + { + return PerformanceRating.None; + } + + return CalculatePerformanceRating((x, y) => x.dynamicBoneColliderCount.GetValueOrDefault() - y.dynamicBoneColliderCount); + } + case AvatarPerformanceCategory.DynamicBoneCollisionCheckCount: + { + if(!dynamicBoneCollisionCheckCount.HasValue) + { + return PerformanceRating.None; + } + + return CalculatePerformanceRating((x, y) => x.dynamicBoneCollisionCheckCount.GetValueOrDefault() - y.dynamicBoneCollisionCheckCount); + } + case AvatarPerformanceCategory.ClothCount: + { + if(!clothCount.HasValue) + { + return PerformanceRating.None; + } + + return CalculatePerformanceRating((x, y) => x.clothCount.GetValueOrDefault() - y.clothCount); + } + case AvatarPerformanceCategory.ClothMaxVertices: + { + if(!clothMaxVertices.HasValue) + { + return PerformanceRating.None; + } + + return CalculatePerformanceRating((x, y) => x.clothMaxVertices.GetValueOrDefault() - y.clothMaxVertices); + } + case AvatarPerformanceCategory.PhysicsColliderCount: + { + if(!physicsColliderCount.HasValue) + { + return PerformanceRating.None; + } + + return CalculatePerformanceRating((x, y) => x.physicsColliderCount.GetValueOrDefault() - y.physicsColliderCount); + } + case AvatarPerformanceCategory.PhysicsRigidbodyCount: + { + if(!physicsRigidbodyCount.HasValue) + { + return PerformanceRating.None; + } + + return CalculatePerformanceRating((x, y) => x.physicsRigidbodyCount.GetValueOrDefault() - y.physicsRigidbodyCount); + } + case AvatarPerformanceCategory.AudioSourceCount: + { + if(!audioSourceCount.HasValue) + { + return PerformanceRating.None; + } + + return CalculatePerformanceRating((x, y) => x.audioSourceCount.GetValueOrDefault() - y.audioSourceCount); + } + case AvatarPerformanceCategory.DownloadSize: + { + if(!downloadSize.HasValue) + { + return PerformanceRating.None; + } + + return PerformanceRating.Excellent; + } + default: + { + return PerformanceRating.None; + } + } + } + + private PerformanceRating CalculatePerformanceRating(ComparePerformanceStatsDelegate compareFn) + { + if(compareFn(this, _performanceStatsLevelSet.excellent) <= 0) + { + return PerformanceRating.Excellent; + } + + if(compareFn(this, _performanceStatsLevelSet.good) <= 0) + { + return PerformanceRating.Good; + } + + if(compareFn(this, _performanceStatsLevelSet.medium) <= 0) + { + return PerformanceRating.Medium; + } + + if(compareFn(this, _performanceStatsLevelSet.poor) <= 0) + { + return PerformanceRating.Poor; + } + + return PerformanceRating.VeryPoor; + } + + private static bool ApproxLessOrEqual(float x1, float x2) + { + float r = x1 - x2; + return r < 0.0f || Mathf.Approximately(r, 0.0f); + } + + #endregion + + #region Overrides + + public override string ToString() + { + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + sb.AppendFormat("Avatar Name: {0}\n", avatarName); + sb.AppendFormat("Overall Performance: {0}\n", GetPerformanceRatingForCategory(AvatarPerformanceCategory.Overall)); + sb.AppendFormat("Poly Count: {0}\n", polyCount); + sb.AppendFormat("Bounds: {0}\n", aabb.ToString()); + sb.AppendFormat("Skinned Mesh Count: {0}\n", skinnedMeshCount); + sb.AppendFormat("Mesh Count: {0}\n", meshCount); + sb.AppendFormat("Material Count: {0}\n", materialCount); + sb.AppendFormat("Animator Count: {0}\n", animatorCount); + sb.AppendFormat("Bone Count: {0}\n", boneCount); + sb.AppendFormat("Light Count: {0}\n", lightCount); + sb.AppendFormat("Particle System Count: {0}\n", particleSystemCount); + sb.AppendFormat("Particle Total Count: {0}\n", particleTotalCount); + sb.AppendFormat("Particle Max Mesh Poly Count: {0}\n", particleMaxMeshPolyCount); + sb.AppendFormat("Particle Trails Enabled: {0}\n", particleTrailsEnabled); + sb.AppendFormat("Particle Collision Enabled: {0}\n", particleCollisionEnabled); + sb.AppendFormat("Trail Renderer Count: {0}\n", trailRendererCount); + sb.AppendFormat("Line Renderer Count: {0}\n", lineRendererCount); + sb.AppendFormat("Dynamic Bone Component Count: {0}\n", dynamicBoneComponentCount); + sb.AppendFormat("Dynamic Bone Simulated Bone Count: {0}\n", dynamicBoneSimulatedBoneCount); + sb.AppendFormat("Dynamic Bone Collider Count: {0}\n", dynamicBoneColliderCount); + sb.AppendFormat("Dynamic Bone Collision Check Count: {0}\n", dynamicBoneCollisionCheckCount); + sb.AppendFormat("Cloth Count: {0}\n", clothCount); + sb.AppendFormat("Cloth Max Vertices: {0}\n", clothMaxVertices); + sb.AppendFormat("Physics Collider Count: {0}\n", physicsColliderCount); + sb.AppendFormat("Physics Rigidbody Count: {0}\n", physicsRigidbodyCount); + if(downloadSize > 0) + { + sb.AppendFormat("Download Size: {0} MB\n", downloadSize); + } + + return sb.ToString(); + } + + // Mirror the AvatarPerformanceStats class even if some aren't used right now. + [SuppressMessage("ReSharper", "MemberCanBePrivate.Global")] + [SuppressMessage("ReSharper", "NotAccessedField.Global")] + public readonly struct Snapshot + { + public readonly string avatarName; + + // Stats + public readonly int? polyCount; + public readonly Bounds? aabb; + public readonly int? skinnedMeshCount; + public readonly int? meshCount; + public readonly int? materialCount; + public readonly int? animatorCount; + public readonly int? boneCount; + public readonly int? lightCount; + public readonly int? particleSystemCount; + public readonly int? particleTotalCount; + public readonly int? particleMaxMeshPolyCount; + public readonly bool? particleTrailsEnabled; + public readonly bool? particleCollisionEnabled; + public readonly int? trailRendererCount; + public readonly int? lineRendererCount; + public readonly int? dynamicBoneComponentCount; + public readonly int? dynamicBoneSimulatedBoneCount; + public readonly int? dynamicBoneColliderCount; + public readonly int? dynamicBoneCollisionCheckCount; // number of collider simulated bones excluding the root multiplied by the number of colliders + public readonly int? clothCount; + public readonly int? clothMaxVertices; + public readonly int? physicsColliderCount; + public readonly int? physicsRigidbodyCount; + public readonly int? audioSourceCount; + public readonly float? downloadSize; + + // Ratings + public readonly PerformanceRating overallRating; + public readonly PerformanceRating polyCountRating; + public readonly PerformanceRating aabbRating; + public readonly PerformanceRating skinnedMeshCountRating; + public readonly PerformanceRating meshCountRating; + public readonly PerformanceRating materialCountRating; + public readonly PerformanceRating animatorCountRating; + public readonly PerformanceRating boneCountRating; + public readonly PerformanceRating lightCountRating; + public readonly PerformanceRating particleSystemCountRating; + public readonly PerformanceRating particleTotalCountRating; + public readonly PerformanceRating particleMaxMeshPolyCountRating; + public readonly PerformanceRating particleTrailsEnabledRating; + public readonly PerformanceRating particleCollisionEnabledRating; + public readonly PerformanceRating trailRendererCountRating; + public readonly PerformanceRating lineRendererCountRating; + public readonly PerformanceRating dynamicBoneComponentCountRating; + public readonly PerformanceRating dynamicBoneSimulatedBoneCountRating; + public readonly PerformanceRating dynamicBoneColliderCountRating; + public readonly PerformanceRating dynamicBoneCollisionCheckCountRating; + public readonly PerformanceRating clothCountRating; + public readonly PerformanceRating clothMaxVerticesRating; + public readonly PerformanceRating physicsColliderCountRating; + public readonly PerformanceRating physicsRigidbodyCountRating; + public readonly PerformanceRating audioSourceCountRating; + public readonly PerformanceRating downloadSizeRating; + + public Snapshot(AvatarPerformanceStats avatarPerformanceStats) + { + avatarName = avatarPerformanceStats.avatarName; + polyCount = avatarPerformanceStats.polyCount; + aabb = avatarPerformanceStats.aabb; + skinnedMeshCount = avatarPerformanceStats.skinnedMeshCount; + meshCount = avatarPerformanceStats.meshCount; + materialCount = avatarPerformanceStats.materialCount; + animatorCount = avatarPerformanceStats.animatorCount; + boneCount = avatarPerformanceStats.boneCount; + lightCount = avatarPerformanceStats.lightCount; + particleSystemCount = avatarPerformanceStats.particleSystemCount; + particleTotalCount = avatarPerformanceStats.particleTotalCount; + particleMaxMeshPolyCount = avatarPerformanceStats.particleMaxMeshPolyCount; + particleTrailsEnabled = avatarPerformanceStats.particleTrailsEnabled; + particleCollisionEnabled = avatarPerformanceStats.particleCollisionEnabled; + trailRendererCount = avatarPerformanceStats.trailRendererCount; + lineRendererCount = avatarPerformanceStats.lineRendererCount; + dynamicBoneComponentCount = avatarPerformanceStats.dynamicBoneComponentCount; + dynamicBoneSimulatedBoneCount = avatarPerformanceStats.dynamicBoneSimulatedBoneCount; + dynamicBoneColliderCount = avatarPerformanceStats.dynamicBoneColliderCount; + dynamicBoneCollisionCheckCount = avatarPerformanceStats.dynamicBoneCollisionCheckCount; + clothCount = avatarPerformanceStats.clothCount; + clothMaxVertices = avatarPerformanceStats.clothMaxVertices; + physicsColliderCount = avatarPerformanceStats.physicsColliderCount; + physicsRigidbodyCount = avatarPerformanceStats.physicsRigidbodyCount; + audioSourceCount = avatarPerformanceStats.audioSourceCount; + downloadSize = avatarPerformanceStats.downloadSize; + + overallRating = avatarPerformanceStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.Overall); + polyCountRating = avatarPerformanceStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.PolyCount); + aabbRating = avatarPerformanceStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.AABB); + skinnedMeshCountRating = avatarPerformanceStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.SkinnedMeshCount); + meshCountRating = avatarPerformanceStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.MeshCount); + materialCountRating = avatarPerformanceStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.MaterialCount); + animatorCountRating = avatarPerformanceStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.AnimatorCount); + boneCountRating = avatarPerformanceStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.BoneCount); + lightCountRating = avatarPerformanceStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.LightCount); + particleSystemCountRating = avatarPerformanceStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.ParticleSystemCount); + particleTotalCountRating = avatarPerformanceStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.ParticleTotalCount); + particleMaxMeshPolyCountRating = avatarPerformanceStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.ParticleMaxMeshPolyCount); + particleTrailsEnabledRating = avatarPerformanceStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.ParticleTrailsEnabled); + particleCollisionEnabledRating = avatarPerformanceStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.ParticleCollisionEnabled); + trailRendererCountRating = avatarPerformanceStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.TrailRendererCount); + lineRendererCountRating = avatarPerformanceStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.LineRendererCount); + dynamicBoneComponentCountRating = avatarPerformanceStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.DynamicBoneComponentCount); + dynamicBoneSimulatedBoneCountRating = avatarPerformanceStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.DynamicBoneSimulatedBoneCount); + dynamicBoneColliderCountRating = avatarPerformanceStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.DynamicBoneColliderCount); + dynamicBoneCollisionCheckCountRating = avatarPerformanceStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.DynamicBoneCollisionCheckCount); + clothCountRating = avatarPerformanceStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.ClothCount); + clothMaxVerticesRating = avatarPerformanceStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.ClothMaxVertices); + physicsColliderCountRating = avatarPerformanceStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.PhysicsColliderCount); + physicsRigidbodyCountRating = avatarPerformanceStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.PhysicsRigidbodyCount); + audioSourceCountRating = avatarPerformanceStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.AudioSourceCount); + downloadSizeRating = avatarPerformanceStats.GetPerformanceRatingForCategory(AvatarPerformanceCategory.DownloadSize); + } + + public override string ToString() + { + System.Text.StringBuilder sb = new System.Text.StringBuilder(1024); + sb.AppendFormat("Avatar Name: {0}\n", avatarName); + sb.AppendFormat("Overall Performance: {0}\n", overallRating); + sb.AppendFormat("Poly Count: {0}\n", polyCount); + sb.AppendFormat("Bounds: {0}\n", aabb.ToString()); + sb.AppendFormat("Skinned Mesh Count: {0}\n", skinnedMeshCount); + sb.AppendFormat("Mesh Count: {0}\n", meshCount); + sb.AppendFormat("Material Count: {0}\n", materialCount); + sb.AppendFormat("Animator Count: {0}\n", animatorCount); + sb.AppendFormat("Bone Count: {0}\n", boneCount); + sb.AppendFormat("Light Count: {0}\n", lightCount); + sb.AppendFormat("Particle System Count: {0}\n", particleSystemCount); + sb.AppendFormat("Particle Total Count: {0}\n", particleTotalCount); + sb.AppendFormat("Particle Max Mesh Poly Count: {0}\n", particleMaxMeshPolyCount); + sb.AppendFormat("Particle Trails Enabled: {0}\n", particleTrailsEnabled); + sb.AppendFormat("Particle Collision Enabled: {0}\n", particleCollisionEnabled); + sb.AppendFormat("Trail Renderer Count: {0}\n", trailRendererCount); + sb.AppendFormat("Line Renderer Count: {0}\n", lineRendererCount); + sb.AppendFormat("Dynamic Bone Component Count: {0}\n", dynamicBoneComponentCount); + sb.AppendFormat("Dynamic Bone Simulated Bone Count: {0}\n", dynamicBoneSimulatedBoneCount); + sb.AppendFormat("Dynamic Bone Collider Count: {0}\n", dynamicBoneColliderCount); + sb.AppendFormat("Dynamic Bone Collision Check Count: {0}\n", dynamicBoneCollisionCheckCount); + sb.AppendFormat("Cloth Count: {0}\n", clothCount); + sb.AppendFormat("Cloth Max Vertices: {0}\n", clothMaxVertices); + sb.AppendFormat("Physics Collider Count: {0}\n", physicsColliderCount); + sb.AppendFormat("Physics Rigidbody Count: {0}\n", physicsRigidbodyCount); + sb.AppendFormat("Download Size: {0} MB\n", downloadSize); + + return sb.ToString(); + } + } + + #endregion + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats/AvatarPerformanceStats.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats/AvatarPerformanceStats.cs.meta new file mode 100644 index 00000000..894716a6 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats/AvatarPerformanceStats.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1bf4fb79a49d4b109c4dce6b38e5548e +timeCreated: 1561267926 \ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats/AvatarPerformanceStatsLevel.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats/AvatarPerformanceStatsLevel.cs new file mode 100644 index 00000000..c31b43a2 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats/AvatarPerformanceStatsLevel.cs @@ -0,0 +1,32 @@ +using UnityEngine; + +namespace VRC.SDKBase.Validation.Performance.Stats +{ + public class AvatarPerformanceStatsLevel : ScriptableObject + { + public int polyCount; + public Bounds aabb; + public int skinnedMeshCount; + public int meshCount; + public int materialCount; + public int animatorCount; + public int boneCount; + public int lightCount; + public int particleSystemCount; + public int particleTotalCount; + public int particleMaxMeshPolyCount; + public bool particleTrailsEnabled; + public bool particleCollisionEnabled; + public int trailRendererCount; + public int lineRendererCount; + public int dynamicBoneComponentCount; + public int dynamicBoneSimulatedBoneCount; + public int dynamicBoneColliderCount; + public int dynamicBoneCollisionCheckCount; + public int clothCount; + public int clothMaxVertices; + public int physicsColliderCount; + public int physicsRigidbodyCount; + public int audioSourceCount; + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats/AvatarPerformanceStatsLevel.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats/AvatarPerformanceStatsLevel.cs.meta new file mode 100644 index 00000000..966fbdc0 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats/AvatarPerformanceStatsLevel.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f742c36dce5730f4d96e37d82c330584 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats/AvatarPerformanceStatsLevelSet.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats/AvatarPerformanceStatsLevelSet.cs new file mode 100644 index 00000000..6490496b --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats/AvatarPerformanceStatsLevelSet.cs @@ -0,0 +1,15 @@ +using UnityEngine; +using UnityEngine.Serialization; + +namespace VRC.SDKBase.Validation.Performance.Stats +{ + public class AvatarPerformanceStatsLevelSet : ScriptableObject + { + [FormerlySerializedAs("veryGood")] + public AvatarPerformanceStatsLevel excellent; + public AvatarPerformanceStatsLevel good; + public AvatarPerformanceStatsLevel medium; + [FormerlySerializedAs("bad")] + public AvatarPerformanceStatsLevel poor; + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats/AvatarPerformanceStatsLevelSet.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats/AvatarPerformanceStatsLevelSet.cs.meta new file mode 100644 index 00000000..603c0a80 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/Performance/Stats/AvatarPerformanceStatsLevelSet.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 468554b1bfc447f41a20a2f5bae65d16 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/ShaderValidation.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/ShaderValidation.cs new file mode 100644 index 00000000..0a69a1af --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/ShaderValidation.cs @@ -0,0 +1,86 @@ +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace VRC.SDKBase.Validation +{ + public static class ShaderValidation + { + public static IEnumerable FindIllegalShaders(GameObject target, string[] whitelist) + { + List illegalShaders = new List(); + IEnumerator seeker = FindIllegalShadersEnumerator(target, whitelist, (c) => illegalShaders.Add(c)); + while(seeker.MoveNext()) + { + } + + return illegalShaders; + } + + private static IEnumerator FindIllegalShadersEnumerator(GameObject target, string[] whitelist, System.Action onFound, bool useWatch = false) + { + System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch(); + if(useWatch) + { + watch.Start(); + } + + List materialCache = new List(); + Queue children = new Queue(); + children.Enqueue(target.gameObject); + while(children.Count > 0) + { + GameObject child = children.Dequeue(); + if(child == null) + { + continue; + } + + for(int idx = 0; idx < child.transform.childCount; ++idx) + { + children.Enqueue(child.transform.GetChild(idx).gameObject); + } + + foreach(Renderer childRenderers in child.transform.GetComponents()) + { + if(childRenderers == null) + { + continue; + } + + foreach(Material sharedMaterial in childRenderers.sharedMaterials) + { + if(materialCache.Any(cacheMtl => sharedMaterial == cacheMtl)) // did we already look at this one? + { + continue; + } + + // Skip empty material slots, or materials without shaders. + // Both will end up using the magenta error shader. + if(sharedMaterial == null || sharedMaterial.shader == null) + { + continue; + } + + if(whitelist.All(okayShaderName => sharedMaterial.shader.name != okayShaderName)) + { + onFound(sharedMaterial.shader); + yield return null; + } + + materialCache.Add(sharedMaterial); + } + + if(!useWatch || watch.ElapsedMilliseconds <= 1) + { + continue; + } + + yield return null; + watch.Reset(); + } + } + } + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/ShaderValidation.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/ShaderValidation.cs.meta new file mode 100644 index 00000000..1b9e8680 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/ShaderValidation.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bef0a8d1d2c547119a62b7d7a5c512ea +timeCreated: 1563940360 \ No newline at end of file diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/ValidationUtils.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/ValidationUtils.cs new file mode 100644 index 00000000..e6dfef95 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/ValidationUtils.cs @@ -0,0 +1,260 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using UnityEngine; +using System.Reflection; + +namespace VRC.SDKBase.Validation +{ + public static class ValidationUtils + { + public static void RemoveIllegalComponents(GameObject target, HashSet whitelist, bool retry = true, bool onlySceneObjects = false, bool logStripping = true) + { + List foundComponents = FindIllegalComponents(target, whitelist); + foreach(Component component in foundComponents) + { + if(component == null) + { + continue; + } + + if(onlySceneObjects && component.GetInstanceID() < 0) + { + continue; + } + + if(logStripping) + { + Core.Logger.LogWarning($"Removing {component.GetType().Name} comp from {component.gameObject.name}"); + } + + RemoveComponent(component); + } + } + + public static List FindIllegalComponents(GameObject target, HashSet whitelist) + { + List foundComponents = new List(); + Component[] allComponents = target.GetComponentsInChildren(true); + foreach(Component component in allComponents) + { + if(component == null) + { + continue; + } + + Type componentType = component.GetType(); + if(whitelist.Contains(componentType)) + { + continue; + } + + foundComponents.Add(component); + } + + return foundComponents; + } + + private static readonly Dictionary _typeCache = new Dictionary(); + private static readonly Dictionary> _whitelistCache = new Dictionary>(); + public static HashSet WhitelistedTypes(string whitelistName, IEnumerable componentTypeWhitelist) + { + if (_whitelistCache.ContainsKey(whitelistName)) + { + return _whitelistCache[whitelistName]; + } + + Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); + HashSet whitelist = new HashSet(); + foreach(string whitelistedTypeName in componentTypeWhitelist) + { + Type whitelistedType = GetTypeFromName(whitelistedTypeName, assemblies); + if(whitelistedType == null) + { + continue; + } + + if(whitelist.Contains(whitelistedType)) + { + continue; + } + + whitelist.Add(whitelistedType); + } + + AddDerivedClasses(whitelist); + + _whitelistCache[whitelistName] = whitelist; + + return _whitelistCache[whitelistName]; + } + + public static HashSet WhitelistedTypes(string whitelistName, IEnumerable componentTypeWhitelist) + { + if (_whitelistCache.ContainsKey(whitelistName)) + { + return _whitelistCache[whitelistName]; + } + + HashSet whitelist = new HashSet(); + whitelist.UnionWith(componentTypeWhitelist); + + AddDerivedClasses(whitelist); + + _whitelistCache[whitelistName] = whitelist; + + return _whitelistCache[whitelistName]; + } + + private static void AddDerivedClasses(HashSet whitelist) + { + Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); + foreach(Assembly assembly in assemblies) + { + foreach(Type type in assembly.GetTypes()) + { + if(whitelist.Contains(type)) + { + continue; + } + + if(!typeof(Component).IsAssignableFrom(type)) + { + continue; + } + + Type currentType = type; + while(currentType != typeof(object) && currentType != null) + { + if(whitelist.Contains(currentType)) + { + whitelist.Add(type); + break; + } + + currentType = currentType.BaseType; + } + } + } + } + + public static Type GetTypeFromName(string name, Assembly[] assemblies = null) + { + if (_typeCache.ContainsKey(name)) + { + + return _typeCache[name]; + } + + if (assemblies == null) + { + assemblies = AppDomain.CurrentDomain.GetAssemblies(); + } + + foreach (Assembly assembly in assemblies) + { + Type found = assembly.GetType(name); + if(found == null) + { + continue; + } + + _typeCache[name] = found; + return found; + } + + //This is really verbose for some SDK scenes, eg. + //If they don't have FinalIK installed +#if VRC_CLIENT && UNITY_EDITOR + Debug.LogWarningFormat("Could not find type {0}", name); +#endif + + _typeCache[name] = null; + return null; + } + + private static readonly Dictionary> _requireComponentsCache = new Dictionary>(); + private static void RemoveDependencies(Component rootComponent) + { + if (rootComponent == null) + { + return; + } + + Component[] components = rootComponent.GetComponents(); + if (components == null || components.Length == 0) + { + return; + } + + Type compType = rootComponent.GetType(); + foreach (var siblingComponent in components) + { + if (siblingComponent == null) + { + continue; + } + + Type siblingComponentType = siblingComponent.GetType(); + if(!_requireComponentsCache.TryGetValue(siblingComponentType, out ImmutableArray requiredComponentAttributes)) + { + requiredComponentAttributes = siblingComponentType.GetCustomAttributes(typeof(RequireComponent), true).Cast().ToImmutableArray(); + _requireComponentsCache.Add(siblingComponentType, requiredComponentAttributes); + } + + bool deleteMe = false; + foreach (RequireComponent requireComponent in requiredComponentAttributes) + { + if (requireComponent == null) + { + continue; + } + + if(requireComponent.m_Type0 != compType && requireComponent.m_Type1 != compType && requireComponent.m_Type2 != compType) + { + continue; + } + + deleteMe = true; + break; + } + + if (deleteMe && siblingComponent != rootComponent) + { + RemoveComponent(siblingComponent); + } + } + } + + public static void RemoveComponent(Component comp) + { + if (comp == null) + { + return; + } + + RemoveDependencies(comp); + +#if VRC_CLIENT + UnityEngine.Object.DestroyImmediate(comp, true); +#else + UnityEngine.Object.DestroyImmediate(comp, false); +#endif + } + + public static void RemoveComponentsOfType(GameObject target) where T : Component + { + if (target == null) + return; + + foreach (T comp in target.GetComponentsInChildren(true)) + { + if (comp == null || comp.gameObject == null) + continue; + + RemoveComponent(comp); + } + } + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/ValidationUtils.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/ValidationUtils.cs.meta new file mode 100644 index 00000000..adc2f728 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/ValidationUtils.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8a90ec11b51863c4cb2d8a8cee31c2fb +timeCreated: 1504829091 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/WorldValidation.cs b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/WorldValidation.cs new file mode 100644 index 00000000..3dab42c2 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/WorldValidation.cs @@ -0,0 +1,682 @@ +using System; +using System.Collections.Generic; +using JetBrains.Annotations; +#if TextMeshPro +using TMPro; +#endif +using UnityEngine; +using UnityEngine.Playables; +using UnityEngine.Timeline; +using UnityEngine.UI; + +namespace VRC.SDKBase.Validation +{ + public static class WorldValidation + { + private static readonly Lazy _debugLevel = new Lazy(InitializeLogging); + private static int DebugLevel => _debugLevel.Value; + + private static int InitializeLogging() + { + int hashCode = typeof(WorldValidation).GetHashCode(); + VRC.Core.Logger.DescribeDebugLevel(hashCode, "WorldValidation", VRC.Core.Logger.Color.red); + VRC.Core.Logger.AddDebugLevel(hashCode); + return hashCode; + } + + static string[] ComponentTypeWhiteList = null; + + public enum WhiteListConfiguration + { + None, + VRCSDK2, + VRCSDK3, + Unchanged + } + + static WhiteListConfiguration ComponentTypeWhiteListConfiguration = WhiteListConfiguration.None; + + static readonly string[] ComponentTypeWhiteListCommon = new string[] + { + #if UNITY_STANDALONE + "UnityEngine.Rendering.PostProcessing.PostProcessDebug", + "UnityEngine.Rendering.PostProcessing.PostProcessLayer", + "UnityEngine.Rendering.PostProcessing.PostProcessVolume", + #endif + "VRC.Core.PipelineManager", + "UiInputField", + "VRCProjectSettings", + "DynamicBone", + "DynamicBoneCollider", + "TMPro.TMP_Dropdown", + "TMPro.TMP_InputField", + "TMPro.TMP_ScrollbarEventHandler", + "TMPro.TMP_SelectionCaret", + "TMPro.TMP_SpriteAnimator", + "TMPro.TMP_SubMesh", + "TMPro.TMP_SubMeshUI", + "TMPro.TMP_Text", + "TMPro.TextMeshPro", + "TMPro.TextMeshProUGUI", + "TMPro.TextContainer", + "TMPro.TMP_Dropdown+DropdownItem", + "UnityEngine.EventSystems.EventSystem", + "UnityEngine.EventSystems.EventTrigger", + "UnityEngine.EventSystems.UIBehaviour", + "UnityEngine.EventSystems.BaseInput", + "UnityEngine.EventSystems.BaseInputModule", + "UnityEngine.EventSystems.PointerInputModule", + "UnityEngine.EventSystems.StandaloneInputModule", + "UnityEngine.EventSystems.TouchInputModule", + "UnityEngine.EventSystems.BaseRaycaster", + "UnityEngine.EventSystems.PhysicsRaycaster", + "UnityEngine.UI.Button", + "UnityEngine.UI.Dropdown", + "UnityEngine.UI.Dropdown+DropdownItem", + "UnityEngine.UI.Graphic", + "UnityEngine.UI.GraphicRaycaster", + "UnityEngine.UI.Image", + "UnityEngine.UI.InputField", + "UnityEngine.UI.Mask", + "UnityEngine.UI.MaskableGraphic", + "UnityEngine.UI.RawImage", + "UnityEngine.UI.RectMask2D", + "UnityEngine.UI.Scrollbar", + "UnityEngine.UI.ScrollRect", + "UnityEngine.UI.Selectable", + "UnityEngine.UI.Slider", + "UnityEngine.UI.Text", + "UnityEngine.UI.Toggle", + "UnityEngine.UI.ToggleGroup", + "UnityEngine.UI.AspectRatioFitter", + "UnityEngine.UI.CanvasScaler", + "UnityEngine.UI.ContentSizeFitter", + "UnityEngine.UI.GridLayoutGroup", + "UnityEngine.UI.HorizontalLayoutGroup", + "UnityEngine.UI.HorizontalOrVerticalLayoutGroup", + "UnityEngine.UI.LayoutElement", + "UnityEngine.UI.LayoutGroup", + "UnityEngine.UI.VerticalLayoutGroup", + "UnityEngine.UI.BaseMeshEffect", + "UnityEngine.UI.Outline", + "UnityEngine.UI.PositionAsUV1", + "UnityEngine.UI.Shadow", + "OVRLipSync", + "OVRLipSyncContext", + "OVRLipSyncContextBase", + "OVRLipSyncContextCanned", + "OVRLipSyncContextMorphTarget", + "OVRLipSyncContextTextureFlip", + "ONSPReflectionZone", + "OculusSpatializerUnity", + "ONSPAmbisonicsNative", + "ONSPAudioSource", + "RootMotion.FinalIK.BipedIK", + "RootMotion.FinalIK.FingerRig", + "RootMotion.FinalIK.Grounder", + "RootMotion.FinalIK.GrounderBipedIK", + "RootMotion.FinalIK.GrounderFBBIK", + "RootMotion.FinalIK.GrounderIK", + "RootMotion.FinalIK.GrounderQuadruped", + "RootMotion.FinalIK.GrounderVRIK", + "RootMotion.FinalIK.AimIK", + "RootMotion.FinalIK.CCDIK", + "RootMotion.FinalIK.FABRIK", + "RootMotion.FinalIK.FABRIKRoot", + "RootMotion.FinalIK.FullBodyBipedIK", + "RootMotion.FinalIK.IK", + "RootMotion.FinalIK.IKExecutionOrder", + "RootMotion.FinalIK.LegIK", + "RootMotion.FinalIK.LimbIK", + "RootMotion.FinalIK.LookAtIK", + "RootMotion.FinalIK.TrigonometricIK", + "RootMotion.FinalIK.VRIK", + "RootMotion.FinalIK.FBBIKArmBending", + "RootMotion.FinalIK.FBBIKHeadEffector", + "RootMotion.FinalIK.TwistRelaxer", + "RootMotion.FinalIK.InteractionObject", + "RootMotion.FinalIK.InteractionSystem", + "RootMotion.FinalIK.InteractionTarget", + "RootMotion.FinalIK.InteractionTrigger", + "RootMotion.FinalIK.GenericPoser", + "RootMotion.FinalIK.HandPoser", + "RootMotion.FinalIK.Poser", + "RootMotion.FinalIK.RagdollUtility", + "RootMotion.FinalIK.RotationLimit", + "RootMotion.FinalIK.RotationLimitAngle", + "RootMotion.FinalIK.RotationLimitHinge", + "RootMotion.FinalIK.RotationLimitPolygonal", + "RootMotion.FinalIK.RotationLimitSpline", + "RootMotion.FinalIK.AimPoser", + "RootMotion.FinalIK.Amplifier", + "RootMotion.FinalIK.BodyTilt", + "RootMotion.FinalIK.HitReaction", + "RootMotion.FinalIK.HitReactionVRIK", + "RootMotion.FinalIK.Inertia", + "RootMotion.FinalIK.OffsetModifier", + "RootMotion.FinalIK.OffsetModifierVRIK", + "RootMotion.FinalIK.OffsetPose", + "RootMotion.FinalIK.Recoil", + "RootMotion.FinalIK.ShoulderRotator", + "RootMotion.Dynamics.AnimationBlocker", + "RootMotion.Dynamics.BehaviourBase", + "RootMotion.Dynamics.BehaviourFall", + "RootMotion.Dynamics.BehaviourPuppet", + "RootMotion.Dynamics.JointBreakBroadcaster", + "RootMotion.Dynamics.MuscleCollisionBroadcaster", + "RootMotion.Dynamics.PressureSensor", + "RootMotion.Dynamics.Prop", + "RootMotion.Dynamics.PropRoot", + "RootMotion.Dynamics.PuppetMaster", + "RootMotion.Dynamics.PuppetMasterSettings", + // TODO: remove these if they are only needed in editor + "RootMotion.Dynamics.BipedRagdollCreator", + "RootMotion.Dynamics.RagdollCreator", + "RootMotion.Dynamics.RagdollEditor", + // + "RootMotion.SolverManager", + "RootMotion.TriggerEventBroadcaster", + "UnityEngine.WindZone", + "UnityEngine.Tilemaps.Tilemap", + "UnityEngine.Tilemaps.TilemapRenderer", + "UnityEngine.Terrain", + "UnityEngine.Tree", + "UnityEngine.SpriteMask", + "UnityEngine.Grid", + "UnityEngine.GridLayout", + "UnityEngine.AudioSource", + "UnityEngine.AudioReverbZone", + "UnityEngine.AudioLowPassFilter", + "UnityEngine.AudioHighPassFilter", + "UnityEngine.AudioDistortionFilter", + "UnityEngine.AudioEchoFilter", + "UnityEngine.AudioChorusFilter", + "UnityEngine.AudioReverbFilter", + "UnityEngine.Playables.PlayableDirector", + "UnityEngine.TerrainCollider", + "UnityEngine.Canvas", + "UnityEngine.CanvasGroup", + "UnityEngine.CanvasRenderer", + "UnityEngine.TextMesh", + "UnityEngine.Animator", + "UnityEngine.AI.NavMeshAgent", + "UnityEngine.AI.NavMeshObstacle", + "UnityEngine.AI.OffMeshLink", + "UnityEngine.Cloth", + "UnityEngine.WheelCollider", + "UnityEngine.Rigidbody", + "UnityEngine.Joint", + "UnityEngine.HingeJoint", + "UnityEngine.SpringJoint", + "UnityEngine.FixedJoint", + "UnityEngine.CharacterJoint", + "UnityEngine.ConfigurableJoint", + "UnityEngine.ConstantForce", + "UnityEngine.Collider", + "UnityEngine.BoxCollider", + "UnityEngine.SphereCollider", + "UnityEngine.MeshCollider", + "UnityEngine.CapsuleCollider", + "UnityEngine.CharacterController", + "UnityEngine.ParticleSystem", + "UnityEngine.ParticleSystemRenderer", + "UnityEngine.BillboardRenderer", + "UnityEngine.Camera", + "UnityEngine.FlareLayer", + "UnityEngine.SkinnedMeshRenderer", + "UnityEngine.Renderer", + "UnityEngine.TrailRenderer", + "UnityEngine.LineRenderer", + "UnityEngine.GUIElement", + "UnityEngine.GUILayer", + "UnityEngine.Light", + "UnityEngine.LightProbeGroup", + "UnityEngine.LightProbeProxyVolume", + "UnityEngine.LODGroup", + "UnityEngine.ReflectionProbe", + "UnityEngine.SpriteRenderer", + "UnityEngine.Transform", + "UnityEngine.RectTransform", + "UnityEngine.Rendering.SortingGroup", + "UnityEngine.Projector", + "UnityEngine.OcclusionPortal", + "UnityEngine.OcclusionArea", + "UnityEngine.LensFlare", + "UnityEngine.Skybox", + "UnityEngine.MeshFilter", + "UnityEngine.Halo", + "UnityEngine.MeshRenderer", + "UnityEngine.Collider2D", + "UnityEngine.Rigidbody2D", + "UnityEngine.CompositeCollider2D", + "UnityEngine.ConstantForce2D", + "UnityEngine.AreaEffector2D", + "UnityEngine.CapsuleCollider2D", + "UnityEngine.DistanceJoint2D", + "UnityEngine.EdgeCollider2D", + "UnityEngine.Effector2D", + "UnityEngine.BoxCollider2D", + "UnityEngine.CircleCollider2D", + "UnityEngine.FixedJoint2D", + "UnityEngine.HingeJoint2D", + "UnityEngine.FrictionJoint2D", + "UnityEngine.PlatformEffector2D", + "UnityEngine.PointEffector2D", + "UnityEngine.PolygonCollider2D", + "UnityEngine.SliderJoint2D", + "UnityEngine.SurfaceEffector2D", + "UnityEngine.RelativeJoint2D", + "UnityEngine.TargetJoint2D", + "UnityEngine.WheelJoint2D", + "UnityEngine.Joint2D", + "UnityEngine.ParticleSystemForceField" + }; + + static readonly string[] ComponentTypeWhiteListSdk2 = new string[] + { + #if UNITY_STANDALONE + "VRCSDK2.VRC_CustomRendererBehaviour", + "VRCSDK2.VRC_MidiNoteIn", + "VRCSDK2.scripts.Scenes.VRC_Panorama", + "VRCSDK2.VRC_Water", + "UnityStandardAssets.Water.WaterBasic", + "UnityStandardAssets.Water.Displace", + "UnityStandardAssets.Water.GerstnerDisplace", + "UnityStandardAssets.Water.PlanarReflection", + "UnityStandardAssets.Water.SpecularLighting", + "UnityStandardAssets.Water.Water", + "UnityStandardAssets.Water.WaterBase", + "UnityStandardAssets.Water.WaterTile", + #endif + "VRCSDK2.VRCTriggerRelay", + "VRCSDK2.VRC_AudioBank", + "VRCSDK2.VRC_DataStorage", + "VRCSDK2.VRC_EventHandler", + "VRCSDK2.VRC_IKFollower", + "VRCSDK2.VRC_Label", + "VRCSDK2.VRC_KeyEvents", + "VRCSDK2.VRC_PhysicsRoot", + "VRCSDK2.VRC_CombatSystem", + "VRCSDK2.VRC_DestructibleStandard", + "VRC_VisualDamage", + "VRCSDK2.VRC_OscButtonIn", + "VRCSDK2.VRC_GunStats", + "VRCSDK2.VRC_JukeBox", + "VRCSDK2.VRC_AddDamage", + "VRCSDK2.VRC_AddHealth", + "VRCSDK2.VRC_AvatarCalibrator", + "VRCSDK2.VRC_AvatarPedestal", + "VRCSDK2.VRC_NPCSpawn", + "VRCSDK2.VRC_ObjectSpawn", + "VRCSDK2.VRC_ObjectSync", + "VRCSDK2.VRC_Pickup", + "VRCSDK2.VRC_PortalMarker", + "VRCSDK2.VRC_SlideShow", + "VRCSDK2.VRC_SpatialAudioSource", + "VRCSDK2.VRC_StationInput", + "VRCSDK2.VRC_SyncAnimation", + "VRCSDK2.VRC_SyncVideoPlayer", + "VRCSDK2.VRC_SyncVideoStream", + "VRCSDK2.VRC_VideoScreen", + "VRCSDK2.VRC_VideoSpeaker", + "VRCSDK2.VRC_PlayerAudioOverride", + "VRCSDK2.VRC_MirrorReflection", + "VRCSDK2.VRC_PlayerMods", + "VRCSDK2.VRC_SceneDescriptor", + "VRCSDK2.VRC_SceneResetPosition", + "VRCSDK2.VRC_SceneSmoothShift", + "VRCSDK2.VRC_SpecialLayer", + "VRCSDK2.VRC_Station", + "VRCSDK2.VRC_StereoObject", + "VRCSDK2.VRC_TimedEvents", + "VRCSDK2.VRC_Trigger", + "VRCSDK2.VRC_TriggerColliderEventTrigger", + "VRCSDK2.VRC_UseEvents", + "VRCSDK2.VRC_UiShape", + "UnityEngine.Animation", + #if !UNITY_2019_4_OR_NEWER + "UnityEngine.GUIText", + "UnityEngine.GUITexture", + #endif + "UnityEngine.Video.VideoPlayer", + "PhysSound.PhysSoundBase", + "PhysSound.PhysSoundObject", + "PhysSound.PhysSoundTempAudio", + "PhysSound.PhysSoundTempAudioPool", + "PhysSound.PhysSoundTerrain", + "RealisticEyeMovements.EyeAndHeadAnimator", + "RealisticEyeMovements.LookTargetController", + "UnityStandardAssets.Cameras.AbstractTargetFollower", + "UnityStandardAssets.Cameras.AutoCam", + "UnityStandardAssets.Cameras.FreeLookCam", + "UnityStandardAssets.Cameras.HandHeldCam", + "UnityStandardAssets.Cameras.LookatTarget", + "UnityStandardAssets.Cameras.PivotBasedCameraRig", + "UnityStandardAssets.Cameras.ProtectCameraFromWallClip", + "UnityStandardAssets.Cameras.TargetFieldOfView", + "UnityStandardAssets.Characters.FirstPerson.FirstPersonController", + "UnityStandardAssets.Characters.FirstPerson.HeadBob", + "UnityStandardAssets.Characters.FirstPerson.RigidbodyFirstPersonController", + "UnityStandardAssets.Vehicles.Ball.Ball", + "UnityStandardAssets.Vehicles.Ball.BallUserControl", + "UnityStandardAssets.Characters.ThirdPerson.AICharacterControl", + "UnityStandardAssets.Characters.ThirdPerson.ThirdPersonCharacter", + "UnityStandardAssets.Characters.ThirdPerson.ThirdPersonUserControl", + "UnityStandardAssets.CrossPlatformInput.AxisTouchButton", + "UnityStandardAssets.CrossPlatformInput.ButtonHandler", + "UnityStandardAssets.CrossPlatformInput.InputAxisScrollbar", + "UnityStandardAssets.CrossPlatformInput.Joystick", + "UnityStandardAssets.CrossPlatformInput.MobileControlRig", + "UnityStandardAssets.CrossPlatformInput.TiltInput", + "UnityStandardAssets.CrossPlatformInput.TouchPad", + "UnityStandardAssets.Effects.AfterburnerPhysicsForce", + "UnityStandardAssets.Effects.ExplosionFireAndDebris", + "UnityStandardAssets.Effects.ExplosionPhysicsForce", + "UnityStandardAssets.Effects.Explosive", + "UnityStandardAssets.Effects.ExtinguishableParticleSystem", + "UnityStandardAssets.Effects.FireLight", + "UnityStandardAssets.Effects.Hose", + "UnityStandardAssets.Effects.ParticleSystemMultiplier", + "UnityStandardAssets.Effects.SmokeParticles", + "UnityStandardAssets.Effects.WaterHoseParticles", + "UnityStandardAssets.Utility.ActivateTrigger", + "UnityStandardAssets.Utility.AutoMoveAndRotate", + "UnityStandardAssets.Utility.DragRigidbody", + "UnityStandardAssets.Utility.DynamicShadowSettings", + "UnityStandardAssets.Utility.FollowTarget", + "UnityStandardAssets.Utility.FPSCounter", + "UnityStandardAssets.Utility.ObjectResetter", + "UnityStandardAssets.Utility.ParticleSystemDestroyer", + #if !UNITY_2019_4_OR_NEWER + "UnityStandardAssets.Utility.SimpleActivatorMenu", + #endif + "UnityStandardAssets.Utility.SimpleMouseRotator", + "UnityStandardAssets.Utility.SmoothFollow", + "UnityStandardAssets.Utility.TimedObjectActivator", + "UnityStandardAssets.Utility.TimedObjectDestructor", + "UnityStandardAssets.Utility.WaypointCircuit", + "UnityStandardAssets.Utility.WaypointProgressTracker", + "UnityStandardAssets.Vehicles.Aeroplane.AeroplaneAiControl", + "UnityStandardAssets.Vehicles.Aeroplane.AeroplaneAudio", + "UnityStandardAssets.Vehicles.Aeroplane.AeroplaneController", + "UnityStandardAssets.Vehicles.Aeroplane.AeroplaneControlSurfaceAnimator", + "UnityStandardAssets.Vehicles.Aeroplane.AeroplanePropellerAnimator", + "UnityStandardAssets.Vehicles.Aeroplane.AeroplaneUserControl2Axis", + "UnityStandardAssets.Vehicles.Aeroplane.AeroplaneUserControl4Axis", + "UnityStandardAssets.Vehicles.Aeroplane.JetParticleEffect", + "UnityStandardAssets.Vehicles.Aeroplane.LandingGear", + "UnityStandardAssets.Vehicles.Car.BrakeLight", + "UnityStandardAssets.Vehicles.Car.CarAIControl", + "UnityStandardAssets.Vehicles.Car.CarAudio", + "UnityStandardAssets.Vehicles.Car.CarController", + "UnityStandardAssets.Vehicles.Car.CarSelfRighting", + "UnityStandardAssets.Vehicles.Car.CarUserControl", + "UnityStandardAssets.Vehicles.Car.Mudguard", + "UnityStandardAssets.Vehicles.Car.SkidTrail", + "UnityStandardAssets.Vehicles.Car.Suspension", + "UnityStandardAssets.Vehicles.Car.WheelEffects", + "RenderHeads.Media.AVProVideo.ApplyToMaterial", + "RenderHeads.Media.AVProVideo.ApplyToMesh", + "RenderHeads.Media.AVProVideo.AudioOutput", + "RenderHeads.Media.AVProVideo.CubemapCube", + "RenderHeads.Media.AVProVideo.DebugOverlay", + "RenderHeads.Media.AVProVideo.DisplayBackground", + "RenderHeads.Media.AVProVideo.DisplayIMGUI", + "RenderHeads.Media.AVProVideo.DisplayUGUI", + "RenderHeads.Media.AVProVideo.MediaPlayer", + "RenderHeads.Media.AVProVideo.StreamParser", + "RenderHeads.Media.AVProVideo.SubtitlesUGUI", + "RenderHeads.Media.AVProVideo.UpdateStereoMaterial", + "AlphaButtonClickMask", + "EventSystemChecker", + "VirtualMarketplaceItem", + "SDK2UrlLauncher" + }; + + static readonly string[] ComponentTypeWhiteListSdk3 = new string[] + { + "VRC.SDK3.VRCDestructibleStandard", + "VRC.SDK3.Components.VRCVisualDamage", + "VRC.SDK3.Components.VRCAvatarPedestal", + "VRC.SDK3.Components.VRCPickup", + "VRC.SDK3.Components.VRCPortalMarker", + "VRC.SDK3.Components.VRCSpatialAudioSource", + "VRC.SDK3.Components.VRCMirrorReflection", + "VRC.SDK3.Components.VRCSceneDescriptor", + "VRC.SDK3.Components.VRCStation", + "VRC.SDK3.Components.VRCUiShape", + "VRC.SDK3.Components.VRCObjectSync", + "VRC.SDK3.Components.VRCObjectPool", + "VRC.SDK3.Video.Components.VRCUnityVideoPlayer", + "VRC.SDK3.Video.Components.AVPro.VRCAVProVideoPlayer", + "VRC.SDK3.Video.Components.AVPro.VRCAVProVideoScreen", + "VRC.SDK3.Video.Components.AVPro.VRCAVProVideoSpeaker", + "VRC.SDK3.Midi.VRCMidiListener", + "VRC.Udon.UdonBehaviour", + "VRC.Udon.AbstractUdonBehaviourEventProxy", + "UnityEngine.Animations.AimConstraint", + "UnityEngine.Animations.LookAtConstraint", + "UnityEngine.Animations.ParentConstraint", + "UnityEngine.Animations.PositionConstraint", + "UnityEngine.Animations.RotationConstraint", + "UnityEngine.Animations.ScaleConstraint", + "UnityEngine.ParticleSystemForceField", + "Cinemachine.Cinemachine3rdPersonAim", + "Cinemachine.CinemachineBlendListCamera", + "Cinemachine.CinemachineBrain", + "Cinemachine.CinemachineCameraOffset", + "Cinemachine.CinemachineClearShot", + "Cinemachine.CinemachineCollider", + "Cinemachine.CinemachineConfiner", + "Cinemachine.CinemachineDollyCart", + "Cinemachine.CinemachineExternalCamera", + "Cinemachine.CinemachineFollowZoom", + "Cinemachine.CinemachineFreeLook", + "Cinemachine.CinemachineMixingCamera", + "Cinemachine.CinemachinePath", + "Cinemachine.CinemachinePipeline", + "Cinemachine.CinemachinePixelPerfect", + "Cinemachine.CinemachineRecomposer", + "Cinemachine.CinemachineSmoothPath", + "Cinemachine.CinemachineStateDrivenCamera", + "Cinemachine.CinemachineStoryboard", + "Cinemachine.CinemachineTargetGroup", + "Cinemachine.CinemachineVirtualCamera", + "Cinemachine.Cinemachine3rdPersonFollow", + "Cinemachine.CinemachineBasicMultiChannelPerlin", + "Cinemachine.CinemachineComposer", + "Cinemachine.CinemachineFramingTransposer", + "Cinemachine.CinemachineGroupComposer", + "Cinemachine.CinemachineHardLockToTarget", + "Cinemachine.CinemachineHardLookAt", + "Cinemachine.CinemachineOrbitalTransposer", + "Cinemachine.CinemachinePOV", + "Cinemachine.CinemachineSameAsFollowTarget", + "Cinemachine.CinemachineTrackedDolly", + "Cinemachine.CinemachineTransposer", + "Cinemachine.CinemachineCore" + }; + + public static readonly string[] ShaderWhiteList = new string[] + { + "VRChat/Mobile/Standard Lite", + "VRChat/Mobile/Diffuse", + "VRChat/Mobile/Bumped Diffuse", + "VRChat/Mobile/Bumped Mapped Specular", + "VRChat/Mobile/Toon Lit", + "VRChat/Mobile/MatCap Lit", + "VRChat/Mobile/Lightmapped", + "VRChat/Mobile/Skybox", + "VRChat/Mobile/Particles/Additive", + "VRChat/Mobile/Particles/Multiply", + "FX/MirrorReflection", + "UI/Default", + }; + + private static readonly HashSet scannedObjects = new HashSet(); + + private static void ConfigureWhiteList(WhiteListConfiguration config) + { + if(ComponentTypeWhiteListConfiguration == config || + config == WhiteListConfiguration.Unchanged) + { + return; + } + + List concatenation = new List(); + concatenation.AddRange(ComponentTypeWhiteListCommon); + + switch(config) + { + case WhiteListConfiguration.VRCSDK2: + concatenation.AddRange(ComponentTypeWhiteListSdk2); + break; + case WhiteListConfiguration.VRCSDK3: + concatenation.AddRange(ComponentTypeWhiteListSdk3); + break; + } + + ComponentTypeWhiteListConfiguration = config; + ComponentTypeWhiteList = concatenation.ToArray(); + } + + [PublicAPI] + public static void RemoveIllegalComponents(List targets, WhiteListConfiguration config, bool retry = true, HashSet tagWhitelistedTypes = null) + { + ConfigureWhiteList(config); + + HashSet whitelist = ValidationUtils.WhitelistedTypes($"world{config}", ComponentTypeWhiteList); + + // combine whitelist types from world tags with cached whitelist + if (tagWhitelistedTypes != null) + { + tagWhitelistedTypes.UnionWith(whitelist); + } + + foreach(GameObject target in targets) + { + ValidationUtils.RemoveIllegalComponents(target, (tagWhitelistedTypes == null) ? whitelist : tagWhitelistedTypes, retry, true, true); + SecurityScan(target); + AddScanned(target); + } + } + + private static void AddScanned(GameObject obj) + { + if(obj == null) + return; + + if(!scannedObjects.Contains(obj.GetInstanceID())) + scannedObjects.Add(obj.GetInstanceID()); + + for(int idx = 0; idx < obj.transform.childCount; ++idx) + AddScanned(obj.transform.GetChild(idx)?.gameObject); + } + + private static bool WasScanned(GameObject obj) + { + return scannedObjects.Contains(obj.GetInstanceID()); + } + + [PublicAPI] + public static void ScanGameObject(GameObject target, WhiteListConfiguration config) + { + if(WasScanned(target)) + { + return; + } + + ConfigureWhiteList(config); + HashSet whitelist = ValidationUtils.WhitelistedTypes("world" + config, ComponentTypeWhiteList); + ValidationUtils.RemoveIllegalComponents(target, whitelist); + SecurityScan(target); + AddScanned(target); + + // Must be called after AddScanned to avoid infinite recursion. + ScanDropdownTemplates(target, config); + } + + [PublicAPI] + public static void ClearScannedGameObjectCache() + { + scannedObjects.Clear(); + } + + [PublicAPI] + public static IEnumerable FindIllegalShaders(GameObject target) + { + return ShaderValidation.FindIllegalShaders(target, ShaderWhiteList); + } + + private static void SecurityScan(GameObject target) + { + PlayableDirector[] playableDirectors = target.GetComponentsInChildren(true); + foreach(PlayableDirector playableDirector in playableDirectors) + { + StripPlayableDirectorWithPrefabs(playableDirector); + } + } + + private static void ScanDropdownTemplates(GameObject target, WhiteListConfiguration config) + { + Dropdown[] dropdowns = target.GetComponentsInChildren(true); + foreach(Dropdown dropdown in dropdowns) + { + if(dropdown == null) + { + continue; + } + + RectTransform dropdownTemplate = dropdown.template; + if(dropdownTemplate == null) + { + continue; + } + + ScanGameObject(dropdownTemplate.transform.root.gameObject, config); + } + + #if TextMeshPro + TMP_Dropdown[] tmpDropdowns = target.GetComponentsInChildren(true); + foreach(TMP_Dropdown textMeshProDropdown in tmpDropdowns) + { + if(textMeshProDropdown == null) + { + continue; + } + + RectTransform dropdownTemplate = textMeshProDropdown.template; + if(dropdownTemplate == null) + { + continue; + } + + ScanGameObject(dropdownTemplate.transform.root.gameObject, config); + } + #endif + } + + private static void StripPlayableDirectorWithPrefabs(PlayableDirector playableDirector) + { + if(!(playableDirector.playableAsset is UnityEngine.Timeline.TimelineAsset timelineAsset)) + return; + + IEnumerable tracks = timelineAsset.GetOutputTracks(); + foreach(TrackAsset track in tracks) + { + if(!(track is ControlTrack)) + continue; + + IEnumerable clips = track.GetClips(); + foreach(TimelineClip clip in clips) + { + if(clip.asset is ControlPlayableAsset controlPlayableAsset && controlPlayableAsset.prefabGameObject != null) + { + UnityEngine.Object.Destroy(playableDirector); + VRC.Core.Logger.LogWarning("PlayableDirector containing prefab removed", DebugLevel, playableDirector.gameObject); + } + } + } + } + } +} diff --git a/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/WorldValidation.cs.meta b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/WorldValidation.cs.meta new file mode 100644 index 00000000..f84c2b09 --- /dev/null +++ b/VRCSDK3AvatarsLegacy/Assets/VRCSDK/Dependencies/VRChat/Scripts/Validation/WorldValidation.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 9b03724cd556cb047b2da80492ea28a5 +timeCreated: 1504829091 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: -- cgit v1.2.3-freya