com.wallstop-studios.unity-helpers 2.1.0 → 2.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/AGENTS.md +1 -0
  2. package/Docs/ILIST_SORTING_PERFORMANCE.md +92 -0
  3. package/{package-lock.json.meta → Docs/ILIST_SORTING_PERFORMANCE.md.meta} +1 -1
  4. package/Docs/INDEX.md +11 -1
  5. package/Docs/Images/random_generators.svg +7 -7
  6. package/Docs/RANDOM_PERFORMANCE.md +17 -14
  7. package/Docs/REFLECTION_HELPERS.md +84 -1
  8. package/Docs/REFLECTION_PERFORMANCE.md +169 -0
  9. package/Docs/REFLECTION_PERFORMANCE.md.meta +7 -0
  10. package/Docs/RELATIONAL_COMPONENTS.md +6 -0
  11. package/Docs/RELATIONAL_COMPONENT_PERFORMANCE.md +63 -0
  12. package/Docs/RELATIONAL_COMPONENT_PERFORMANCE.md.meta +7 -0
  13. package/Docs/SPATIAL_TREE_2D_PERFORMANCE.md +64 -64
  14. package/Docs/SPATIAL_TREE_3D_PERFORMANCE.md +64 -64
  15. package/Editor/Core/Helper/AnimationEventHelpers.cs +1 -1
  16. package/Editor/Sprites/AnimationCopier.cs +1 -1
  17. package/Editor/Sprites/AnimationViewerWindow.cs +4 -4
  18. package/Editor/Sprites/SpriteSettingsApplierAPI.cs +2 -1
  19. package/Editor/Sprites/TextureResizerWizard.cs +4 -3
  20. package/Editor/Utils/ScriptableObjectSingletonCreator.cs +3 -3
  21. package/README.md +33 -18
  22. package/Runtime/Core/Attributes/BaseRelationalComponentAttribute.cs +147 -20
  23. package/Runtime/Core/Attributes/ChildComponentAttribute.cs +630 -117
  24. package/Runtime/Core/Attributes/NotNullAttribute.cs +5 -2
  25. package/Runtime/Core/Attributes/ParentComponentAttribute.cs +477 -103
  26. package/Runtime/Core/Attributes/RelationalComponentAssigner.cs +26 -3
  27. package/Runtime/Core/Attributes/RelationalComponentExtensions.cs +19 -3
  28. package/Runtime/Core/Attributes/SiblingComponentAttribute.cs +265 -92
  29. package/Runtime/Core/CodeGen.meta +8 -0
  30. package/Runtime/Core/DataStructure/ImmutableBitSet.cs +5 -20
  31. package/Runtime/Core/Extension/IListExtensions.cs +720 -12
  32. package/Runtime/Core/Helper/Logging/UnityLogTagFormatter.cs +11 -7
  33. package/Runtime/Core/Helper/Objects.cs +1 -1
  34. package/Runtime/Core/Helper/ReflectionHelpers.Factory.cs +5142 -0
  35. package/Runtime/Core/Helper/ReflectionHelpers.Factory.cs.meta +11 -0
  36. package/Runtime/Core/Helper/ReflectionHelpers.cs +1812 -1518
  37. package/Runtime/Core/Helper/UnityMainThreadDispatcher.cs +2 -3
  38. package/Runtime/Core/Math/Line2D.cs +2 -4
  39. package/Runtime/Core/Math/Line3D.cs +2 -4
  40. package/Runtime/Core/Random/AbstractRandom.cs +52 -5
  41. package/Runtime/Core/Random/DotNetRandom.cs +3 -3
  42. package/Runtime/Core/Random/FlurryBurstRandom.cs +279 -0
  43. package/Runtime/Core/Random/FlurryBurstRandom.cs.meta +3 -0
  44. package/Runtime/Core/Random/IllusionFlow.cs +3 -3
  45. package/Runtime/Core/Random/LinearCongruentialGenerator.cs +3 -3
  46. package/Runtime/Core/Random/PcgRandom.cs +6 -6
  47. package/Runtime/Core/Random/PhotonSpinRandom.cs +387 -0
  48. package/Runtime/Core/Random/PhotonSpinRandom.cs.meta +3 -0
  49. package/Runtime/Core/Random/RomuDuo.cs +3 -3
  50. package/Runtime/Core/Random/SplitMix64.cs +3 -3
  51. package/Runtime/Core/Random/SquirrelRandom.cs +6 -4
  52. package/Runtime/Core/Random/StormDropRandom.cs +271 -0
  53. package/Runtime/Core/Random/StormDropRandom.cs.meta +3 -0
  54. package/Runtime/Core/Random/UnityRandom.cs +3 -3
  55. package/Runtime/Core/Random/WyRandom.cs +6 -4
  56. package/Runtime/Core/Random/XorShiftRandom.cs +3 -3
  57. package/Runtime/Core/Random/XoroShiroRandom.cs +3 -3
  58. package/Runtime/Tags/AttributeMetadataCache.cs +316 -9
  59. package/Runtime/Tags/CosmeticEffectData.cs +1 -1
  60. package/Runtime/Visuals/UIToolkit/MultiFileSelectorElement.cs +3 -3
  61. package/Tests/Editor/Helper/HelpersTests.cs +2 -2
  62. package/Tests/Editor/Helper/ReflectionHelpersTypedEditorTests.cs +87 -0
  63. package/Tests/Editor/Helper/ReflectionHelpersTypedEditorTests.cs.meta +11 -0
  64. package/Tests/Editor/Helper/SpriteHelpersTests.cs +1 -1
  65. package/Tests/Editor/PrefabCheckerReportTests.cs +3 -3
  66. package/Tests/Editor/Sprites/AnimationCopierFilterTests.cs +18 -12
  67. package/Tests/Editor/Sprites/AnimationCopierWindowTests.cs +8 -7
  68. package/Tests/Editor/Sprites/AnimationViewerWindowTests.cs +2 -1
  69. package/Tests/Editor/Sprites/ScriptableSpriteAtlasEditorTests.cs +6 -5
  70. package/Tests/Editor/Sprites/SpriteCropperAdditionalTests.cs +2 -1
  71. package/Tests/Editor/Sprites/SpriteCropperTests.cs +7 -6
  72. package/Tests/Editor/Sprites/SpritePivotAdjusterAdditionalTests.cs +2 -1
  73. package/Tests/Editor/Sprites/SpritePivotAdjusterTests.cs +4 -3
  74. package/Tests/Editor/Sprites/TextureResizerWizardTests.cs +10 -9
  75. package/Tests/Editor/Sprites/TextureSettingsApplierAPITests.cs +2 -1
  76. package/Tests/Editor/Tags/AttributeMetadataCacheTests.cs +192 -0
  77. package/Tests/Editor/Tags/AttributeMetadataCacheTests.cs.meta +11 -0
  78. package/Tests/Editor/Tags.meta +8 -0
  79. package/Tests/Runtime/Extensions/IListExtensionTests.cs +187 -1
  80. package/Tests/Runtime/Helper/ObjectsTests.cs +4 -4
  81. package/Tests/Runtime/Helper/ReflectionHelperCapabilityMatrixTests.cs +2923 -0
  82. package/Tests/Runtime/Helper/ReflectionHelperCapabilityMatrixTests.cs.meta +11 -0
  83. package/Tests/Runtime/Helper/ReflectionHelperTests.cs +660 -0
  84. package/Tests/Runtime/Integrations/Reflex/RelationalComponentsReflexTests.cs +2 -2
  85. package/Tests/Runtime/Performance/IListSortingPerformanceTests.cs +346 -0
  86. package/Tests/Runtime/Performance/IListSortingPerformanceTests.cs.meta +11 -0
  87. package/Tests/Runtime/Performance/RandomPerformanceTests.cs +3 -0
  88. package/Tests/Runtime/Performance/ReflectionPerformanceTests.cs +1238 -0
  89. package/Tests/Runtime/Performance/ReflectionPerformanceTests.cs.meta +11 -0
  90. package/Tests/Runtime/Performance/RelationalComponentBenchmarkTests.cs +832 -0
  91. package/Tests/Runtime/Performance/RelationalComponentBenchmarkTests.cs.meta +11 -0
  92. package/Tests/Runtime/Random/FlurryBurstRandomTests.cs +12 -0
  93. package/Tests/Runtime/Random/FlurryBurstRandomTests.cs.meta +3 -0
  94. package/Tests/Runtime/Random/PhotonSpinRandomTests.cs +12 -0
  95. package/Tests/Runtime/Random/PhotonSpinRandomTests.cs.meta +3 -0
  96. package/Tests/Runtime/Random/RandomProtoSerializationTests.cs +14 -0
  97. package/Tests/Runtime/Random/RandomTestBase.cs +39 -4
  98. package/Tests/Runtime/Random/StormDropRandomTests.cs +12 -0
  99. package/Tests/Runtime/Random/StormDropRandomTests.cs.meta +3 -0
  100. package/Tests/Runtime/Serialization/ProtoInterfaceResolutionEdgeTests.cs +2 -2
  101. package/Tests/Runtime/Serialization/ProtoRootRegistrationTests.cs +1 -1
  102. package/Tests/Runtime/Serialization/ProtoSerializeBehaviorTests.cs +1 -1
  103. package/Tests/Runtime/Tags/PeriodicEffectDefinitionSerializationTests.cs +2 -2
  104. package/package.json +1 -1
  105. package/Tests/Runtime/Performance/RelationComponentPerformanceTests.cs +0 -60
  106. package/Tests/Runtime/Performance/RelationComponentPerformanceTests.cs.meta +0 -3
@@ -5,6 +5,7 @@ namespace WallstopStudios.UnityHelpers.Tags
5
5
  using Core.Attributes;
6
6
  using UnityEngine;
7
7
  using Utils;
8
+ using WallstopStudios.UnityHelpers.Core.Helper;
8
9
 
9
10
  /// <summary>
10
11
  /// Serialized cache of attribute metadata to avoid runtime reflection.
@@ -150,7 +151,8 @@ namespace WallstopStudios.UnityHelpers.Tags
150
151
 
151
152
  public bool Equals(ElementTypeKey other)
152
153
  {
153
- return componentType == other.componentType && fieldName == other.fieldName;
154
+ return componentType == other.componentType
155
+ && string.Equals(fieldName, other.fieldName, StringComparison.Ordinal);
154
156
  }
155
157
 
156
158
  public override bool Equals(object obj)
@@ -160,11 +162,7 @@ namespace WallstopStudios.UnityHelpers.Tags
160
162
 
161
163
  public override int GetHashCode()
162
164
  {
163
- unchecked
164
- {
165
- return ((componentType?.GetHashCode() ?? 0) * 397)
166
- ^ (fieldName?.GetHashCode() ?? 0);
167
- }
165
+ return Objects.HashCode(componentType, fieldName);
168
166
  }
169
167
  }
170
168
 
@@ -484,9 +482,15 @@ namespace WallstopStudios.UnityHelpers.Tags
484
482
  RelationalTypeMetadata[] relationalTypeMetadata
485
483
  )
486
484
  {
487
- _allAttributeNames = allAttributeNames;
488
- _typeMetadata = typeMetadata;
489
- _relationalTypeMetadata = relationalTypeMetadata;
485
+ string[] normalizedAttributeNames = SortAttributeNames(allAttributeNames);
486
+ TypeFieldMetadata[] normalizedTypeMetadata = SortTypeMetadata(typeMetadata);
487
+ RelationalTypeMetadata[] normalizedRelationalMetadata = SortRelationalTypeMetadata(
488
+ relationalTypeMetadata
489
+ );
490
+
491
+ _allAttributeNames = normalizedAttributeNames;
492
+ _typeMetadata = normalizedTypeMetadata;
493
+ _relationalTypeMetadata = normalizedRelationalMetadata;
490
494
  _computedAllAttributeNames = null;
491
495
  _computedAllAttributeNamesIncludesTests = false;
492
496
  _typeFieldsLookup = null;
@@ -495,6 +499,309 @@ namespace WallstopStudios.UnityHelpers.Tags
495
499
  _elementTypeLookup = null;
496
500
  UnityEditor.EditorUtility.SetDirty(this);
497
501
  }
502
+
503
+ private static string[] SortAttributeNames(string[] attributeNames)
504
+ {
505
+ if (attributeNames == null || attributeNames.Length == 0)
506
+ {
507
+ return Array.Empty<string>();
508
+ }
509
+
510
+ string[] result = new string[attributeNames.Length];
511
+ Array.Copy(attributeNames, result, attributeNames.Length);
512
+ Array.Sort(result, StringComparer.Ordinal);
513
+ return result;
514
+ }
515
+
516
+ private static TypeFieldMetadata[] SortTypeMetadata(TypeFieldMetadata[] typeMetadata)
517
+ {
518
+ if (typeMetadata == null || typeMetadata.Length == 0)
519
+ {
520
+ return Array.Empty<TypeFieldMetadata>();
521
+ }
522
+
523
+ int nonNullCount = 0;
524
+ for (int i = 0; i < typeMetadata.Length; i++)
525
+ {
526
+ if (typeMetadata[i] != null)
527
+ {
528
+ nonNullCount++;
529
+ }
530
+ }
531
+
532
+ if (nonNullCount == 0)
533
+ {
534
+ return Array.Empty<TypeFieldMetadata>();
535
+ }
536
+
537
+ TypeFieldMetadata[] result = new TypeFieldMetadata[nonNullCount];
538
+ int resultIndex = 0;
539
+ for (int i = 0; i < typeMetadata.Length; i++)
540
+ {
541
+ TypeFieldMetadata metadata = typeMetadata[i];
542
+ if (metadata == null)
543
+ {
544
+ continue;
545
+ }
546
+
547
+ string typeName = metadata.typeName ?? string.Empty;
548
+ string[] fieldNames = metadata.fieldNames ?? Array.Empty<string>();
549
+ string[] sortedFieldNames =
550
+ fieldNames.Length == 0 ? Array.Empty<string>() : CopyAndSort(fieldNames);
551
+
552
+ result[resultIndex] = new TypeFieldMetadata(typeName, sortedFieldNames);
553
+ resultIndex++;
554
+ }
555
+
556
+ Array.Sort(result, CompareTypeFieldMetadata);
557
+ return result;
558
+ }
559
+
560
+ private static RelationalTypeMetadata[] SortRelationalTypeMetadata(
561
+ RelationalTypeMetadata[] relationalTypeMetadata
562
+ )
563
+ {
564
+ if (relationalTypeMetadata == null || relationalTypeMetadata.Length == 0)
565
+ {
566
+ return Array.Empty<RelationalTypeMetadata>();
567
+ }
568
+
569
+ int nonNullCount = 0;
570
+ for (int i = 0; i < relationalTypeMetadata.Length; i++)
571
+ {
572
+ if (relationalTypeMetadata[i] != null)
573
+ {
574
+ nonNullCount++;
575
+ }
576
+ }
577
+
578
+ if (nonNullCount == 0)
579
+ {
580
+ return Array.Empty<RelationalTypeMetadata>();
581
+ }
582
+
583
+ RelationalTypeMetadata[] result = new RelationalTypeMetadata[nonNullCount];
584
+ int resultIndex = 0;
585
+ for (int i = 0; i < relationalTypeMetadata.Length; i++)
586
+ {
587
+ RelationalTypeMetadata metadata = relationalTypeMetadata[i];
588
+ if (metadata == null)
589
+ {
590
+ continue;
591
+ }
592
+
593
+ string typeName = metadata.typeName ?? string.Empty;
594
+ RelationalFieldMetadata[] sortedFields = SortRelationalFields(metadata.fields);
595
+ result[resultIndex] = new RelationalTypeMetadata(typeName, sortedFields);
596
+ resultIndex++;
597
+ }
598
+
599
+ Array.Sort(result, CompareRelationalTypeMetadata);
600
+ return result;
601
+ }
602
+
603
+ private static RelationalFieldMetadata[] SortRelationalFields(
604
+ RelationalFieldMetadata[] relationalFields
605
+ )
606
+ {
607
+ if (relationalFields == null || relationalFields.Length == 0)
608
+ {
609
+ return Array.Empty<RelationalFieldMetadata>();
610
+ }
611
+
612
+ int nonNullCount = 0;
613
+ for (int i = 0; i < relationalFields.Length; i++)
614
+ {
615
+ if (relationalFields[i] != null)
616
+ {
617
+ nonNullCount++;
618
+ }
619
+ }
620
+
621
+ if (nonNullCount == 0)
622
+ {
623
+ return Array.Empty<RelationalFieldMetadata>();
624
+ }
625
+
626
+ RelationalFieldMetadata[] result = new RelationalFieldMetadata[nonNullCount];
627
+ int resultIndex = 0;
628
+ for (int i = 0; i < relationalFields.Length; i++)
629
+ {
630
+ RelationalFieldMetadata field = relationalFields[i];
631
+ if (field == null)
632
+ {
633
+ continue;
634
+ }
635
+
636
+ result[resultIndex] = new RelationalFieldMetadata(
637
+ field.fieldName,
638
+ field.attributeKind,
639
+ field.fieldKind,
640
+ field.elementTypeName,
641
+ field.isInterface
642
+ );
643
+ resultIndex++;
644
+ }
645
+
646
+ Array.Sort(result, CompareRelationalFieldMetadata);
647
+ return result;
648
+ }
649
+
650
+ private static string[] CopyAndSort(string[] values)
651
+ {
652
+ string[] result = new string[values.Length];
653
+ Array.Copy(values, result, values.Length);
654
+ Array.Sort(result, StringComparer.Ordinal);
655
+ return result;
656
+ }
657
+
658
+ private static int CompareTypeFieldMetadata(TypeFieldMetadata left, TypeFieldMetadata right)
659
+ {
660
+ if (ReferenceEquals(left, right))
661
+ {
662
+ return 0;
663
+ }
664
+
665
+ if (left == null)
666
+ {
667
+ return -1;
668
+ }
669
+
670
+ if (right == null)
671
+ {
672
+ return 1;
673
+ }
674
+
675
+ int typeNameComparison = string.CompareOrdinal(left.typeName, right.typeName);
676
+ if (typeNameComparison != 0)
677
+ {
678
+ return typeNameComparison;
679
+ }
680
+
681
+ string[] leftFields = left.fieldNames ?? Array.Empty<string>();
682
+ string[] rightFields = right.fieldNames ?? Array.Empty<string>();
683
+
684
+ int lengthComparison = leftFields.Length.CompareTo(rightFields.Length);
685
+ if (lengthComparison != 0)
686
+ {
687
+ return lengthComparison;
688
+ }
689
+
690
+ for (int i = 0; i < leftFields.Length; i++)
691
+ {
692
+ int fieldComparison = string.CompareOrdinal(leftFields[i], rightFields[i]);
693
+ if (fieldComparison != 0)
694
+ {
695
+ return fieldComparison;
696
+ }
697
+ }
698
+
699
+ return 0;
700
+ }
701
+
702
+ private static int CompareRelationalTypeMetadata(
703
+ RelationalTypeMetadata left,
704
+ RelationalTypeMetadata right
705
+ )
706
+ {
707
+ if (ReferenceEquals(left, right))
708
+ {
709
+ return 0;
710
+ }
711
+
712
+ if (left == null)
713
+ {
714
+ return -1;
715
+ }
716
+
717
+ if (right == null)
718
+ {
719
+ return 1;
720
+ }
721
+
722
+ int typeNameComparison = string.CompareOrdinal(left.typeName, right.typeName);
723
+ if (typeNameComparison != 0)
724
+ {
725
+ return typeNameComparison;
726
+ }
727
+
728
+ RelationalFieldMetadata[] leftFields =
729
+ left.fields ?? Array.Empty<RelationalFieldMetadata>();
730
+ RelationalFieldMetadata[] rightFields =
731
+ right.fields ?? Array.Empty<RelationalFieldMetadata>();
732
+
733
+ int lengthComparison = leftFields.Length.CompareTo(rightFields.Length);
734
+ if (lengthComparison != 0)
735
+ {
736
+ return lengthComparison;
737
+ }
738
+
739
+ for (int i = 0; i < leftFields.Length; i++)
740
+ {
741
+ int fieldComparison = CompareRelationalFieldMetadata(leftFields[i], rightFields[i]);
742
+ if (fieldComparison != 0)
743
+ {
744
+ return fieldComparison;
745
+ }
746
+ }
747
+
748
+ return 0;
749
+ }
750
+
751
+ private static int CompareRelationalFieldMetadata(
752
+ RelationalFieldMetadata left,
753
+ RelationalFieldMetadata right
754
+ )
755
+ {
756
+ if (ReferenceEquals(left, right))
757
+ {
758
+ return 0;
759
+ }
760
+
761
+ if (left == null)
762
+ {
763
+ return -1;
764
+ }
765
+
766
+ if (right == null)
767
+ {
768
+ return 1;
769
+ }
770
+
771
+ int fieldNameComparison = string.CompareOrdinal(left.fieldName, right.fieldName);
772
+ if (fieldNameComparison != 0)
773
+ {
774
+ return fieldNameComparison;
775
+ }
776
+
777
+ int attributeComparison = left.attributeKind.CompareTo(right.attributeKind);
778
+ if (attributeComparison != 0)
779
+ {
780
+ return attributeComparison;
781
+ }
782
+
783
+ int fieldKindComparison = left.fieldKind.CompareTo(right.fieldKind);
784
+ if (fieldKindComparison != 0)
785
+ {
786
+ return fieldKindComparison;
787
+ }
788
+
789
+ int elementTypeComparison = string.CompareOrdinal(
790
+ left.elementTypeName,
791
+ right.elementTypeName
792
+ );
793
+ if (elementTypeComparison != 0)
794
+ {
795
+ return elementTypeComparison;
796
+ }
797
+
798
+ if (left.isInterface == right.isInterface)
799
+ {
800
+ return 0;
801
+ }
802
+
803
+ return left.isInterface ? -1 : 1;
804
+ }
498
805
  #endif
499
806
  }
500
807
  }
@@ -103,7 +103,7 @@ namespace WallstopStudios.UnityHelpers.Tags
103
103
 
104
104
  public override int GetHashCode()
105
105
  {
106
- return _cosmeticTypes.Value.Count.GetHashCode();
106
+ return Objects.HashCode(_cosmeticTypes.Value.Count);
107
107
  }
108
108
  }
109
109
  }
@@ -663,7 +663,7 @@ namespace WallstopStudios.UnityHelpers.Visuals.UIToolkit
663
663
  if (!string.IsNullOrEmpty(rel))
664
664
  {
665
665
  // If rel starts with Assets, strip it for subsequent segments
666
- display = rel.Replace('\\', '/');
666
+ display = rel.SanitizePath();
667
667
  if (display.StartsWith("Assets/", StringComparison.OrdinalIgnoreCase))
668
668
  {
669
669
  display = display.Substring("Assets/".Length);
@@ -712,8 +712,8 @@ namespace WallstopStudios.UnityHelpers.Visuals.UIToolkit
712
712
  {
713
713
  return;
714
714
  }
715
- Toggle toggle = (evt.currentTarget as VisualElement)?.userData as Toggle;
716
- if (toggle != null)
715
+
716
+ if ((evt.currentTarget as VisualElement)?.userData is Toggle toggle)
717
717
  {
718
718
  toggle.value = !toggle.value;
719
719
  }
@@ -28,7 +28,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Helper
28
28
  AssetDatabase.CreateFolder("Assets", "TempHelpersPrefabs");
29
29
  }
30
30
 
31
- string assetPath = Path.Combine(folder, "TestPrefab.prefab").Replace('\\', '/');
31
+ string assetPath = Path.Combine(folder, "TestPrefab.prefab").SanitizePath();
32
32
  GameObject prefabSource = Track(new GameObject("Helpers_PrefabSource"));
33
33
  try
34
34
  {
@@ -63,7 +63,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Helper
63
63
  AssetDatabase.CreateFolder("Assets", "TempHelpersScriptables");
64
64
  }
65
65
 
66
- string assetPath = Path.Combine(folder, "Dummy.asset").Replace('\\', '/');
66
+ string assetPath = Path.Combine(folder, "Dummy.asset").SanitizePath();
67
67
  DummyScriptableObject asset = Track(
68
68
  ScriptableObject.CreateInstance<DummyScriptableObject>()
69
69
  );
@@ -0,0 +1,87 @@
1
+ #if UNITY_EDITOR
2
+ namespace WallstopStudios.UnityHelpers.Tests.Editor.Helper
3
+ {
4
+ using System;
5
+ using System.Reflection;
6
+ using NUnit.Framework;
7
+ using WallstopStudios.UnityHelpers.Core.Helper;
8
+
9
+ public sealed class TypedHelperEditorTarget
10
+ {
11
+ public int Field;
12
+ public int Property { get; set; }
13
+ }
14
+
15
+ [TestFixture]
16
+ public sealed class ReflectionHelpersTypedEditorTests
17
+ {
18
+ [Test]
19
+ public void EditorTypedFieldSetterFallbacksWhenCapabilitiesDisabled()
20
+ {
21
+ FieldInfo field = typeof(TypedHelperEditorTarget).GetField(
22
+ nameof(TypedHelperEditorTarget.Field)
23
+ );
24
+ using (
25
+ ReflectionHelpers.OverrideReflectionCapabilities(
26
+ expressions: false,
27
+ dynamicIl: false
28
+ )
29
+ )
30
+ {
31
+ FieldSetter<TypedHelperEditorTarget, int> setter = ReflectionHelpers.GetFieldSetter<
32
+ TypedHelperEditorTarget,
33
+ int
34
+ >(field);
35
+ TypedHelperEditorTarget instance = new();
36
+ setter(ref instance, 12);
37
+ Assert.AreEqual(12, instance.Field);
38
+ }
39
+ }
40
+
41
+ [Test]
42
+ public void EditorTypedPropertySetterFallbacksWhenCapabilitiesDisabled()
43
+ {
44
+ PropertyInfo property = typeof(TypedHelperEditorTarget).GetProperty(
45
+ nameof(TypedHelperEditorTarget.Property)
46
+ );
47
+ using (
48
+ ReflectionHelpers.OverrideReflectionCapabilities(
49
+ expressions: false,
50
+ dynamicIl: false
51
+ )
52
+ )
53
+ {
54
+ Action<TypedHelperEditorTarget, int> setter = ReflectionHelpers.GetPropertySetter<
55
+ TypedHelperEditorTarget,
56
+ int
57
+ >(property);
58
+ TypedHelperEditorTarget instance = new();
59
+ setter(instance, 34);
60
+ Assert.AreEqual(34, instance.Property);
61
+ }
62
+ }
63
+
64
+ [Test]
65
+ public void EditorTypedPropertyGetterFallbacksWhenCapabilitiesDisabled()
66
+ {
67
+ PropertyInfo property = typeof(TypedHelperEditorTarget).GetProperty(
68
+ nameof(TypedHelperEditorTarget.Property)
69
+ );
70
+ TypedHelperEditorTarget instance = new() { Property = 56 };
71
+ using (
72
+ ReflectionHelpers.OverrideReflectionCapabilities(
73
+ expressions: false,
74
+ dynamicIl: false
75
+ )
76
+ )
77
+ {
78
+ Func<TypedHelperEditorTarget, int> getter = ReflectionHelpers.GetPropertyGetter<
79
+ TypedHelperEditorTarget,
80
+ int
81
+ >(property);
82
+ Assert.AreEqual(56, getter(instance));
83
+ }
84
+ }
85
+ }
86
+ }
87
+ #endif
@@ -0,0 +1,11 @@
1
+ fileFormatVersion: 2
2
+ guid: 93f41b1f874e3e349b8eecd9d3d2038e
3
+ MonoImporter:
4
+ externalObjects: {}
5
+ serializedVersion: 2
6
+ defaultReferences: []
7
+ executionOrder: 0
8
+ icon: {instanceID: 0}
9
+ userData:
10
+ assetBundleName:
11
+ assetBundleVariant:
@@ -296,7 +296,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Helper
296
296
  private void CreateTestTexture(bool readable, int width = 4, int height = 4)
297
297
  {
298
298
  _testTexturePath = Path.Combine(TestFolder, $"TestTexture_{System.Guid.NewGuid()}.png")
299
- .Replace('\\', '/');
299
+ .SanitizePath();
300
300
 
301
301
  Texture2D tempTexture = Track(
302
302
  new Texture2D(width, height, TextureFormat.RGBA32, false)
@@ -11,7 +11,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor
11
11
  [Test]
12
12
  public void ScanReportConstructorCopiesFolders()
13
13
  {
14
- var report = new PrefabChecker.ScanReport(new[] { "A", "B" });
14
+ PrefabChecker.ScanReport report = new PrefabChecker.ScanReport(new[] { "A", "B" });
15
15
  string[] folders = report.folders;
16
16
  CollectionAssert.AreEqual(new[] { "A", "B" }, folders);
17
17
  }
@@ -19,10 +19,10 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor
19
19
  [Test]
20
20
  public void ScanReportAddCopiesMessages()
21
21
  {
22
- var report = new PrefabChecker.ScanReport(Array.Empty<string>());
22
+ PrefabChecker.ScanReport report = new PrefabChecker.ScanReport(Array.Empty<string>());
23
23
  report.Add("path.prefab", new List<string> { "m1", "m2" });
24
24
  Assert.AreEqual(1, report.items.Count);
25
- var first = report.items[0];
25
+ PrefabChecker.ScanReport.Item first = report.items[0];
26
26
  Assert.AreEqual("path.prefab", first.path);
27
27
  string[] messages = first.messages;
28
28
  CollectionAssert.AreEqual(new[] { "m1", "m2" }, messages);
@@ -18,20 +18,23 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
18
18
  public void SortsAscendingAndDescending()
19
19
  {
20
20
  AnimationCopierWindow wnd = ScriptableObject.CreateInstance<AnimationCopierWindow>();
21
- var a = NewFileInfo("zeta.anim");
22
- var b = NewFileInfo("alpha.anim");
23
- var c = NewFileInfo("beta.anim");
24
- var items = new List<AnimationCopierWindow.AnimationFileInfo> { a, b, c };
21
+ AnimationCopierWindow.AnimationFileInfo a = NewFileInfo("zeta.anim");
22
+ AnimationCopierWindow.AnimationFileInfo b = NewFileInfo("alpha.anim");
23
+ AnimationCopierWindow.AnimationFileInfo c = NewFileInfo("beta.anim");
24
+ List<AnimationCopierWindow.AnimationFileInfo> items =
25
+ new List<AnimationCopierWindow.AnimationFileInfo> { a, b, c };
25
26
 
26
27
  wnd._filterText = string.Empty;
27
28
  wnd._filterUseRegex = false;
28
29
  wnd._sortAscending = true;
29
- var asc = wnd.ApplyFilterAndSort(items).ToList();
30
+ List<AnimationCopierWindow.AnimationFileInfo> asc = wnd.ApplyFilterAndSort(items)
31
+ .ToList();
30
32
  string[] ascNames = asc.Select(o => o.FileName).ToArray();
31
33
  CollectionAssert.AreEqual(new[] { "alpha.anim", "beta.anim", "zeta.anim" }, ascNames);
32
34
 
33
35
  wnd._sortAscending = false;
34
- var desc = wnd.ApplyFilterAndSort(items).ToList();
36
+ List<AnimationCopierWindow.AnimationFileInfo> desc = wnd.ApplyFilterAndSort(items)
37
+ .ToList();
35
38
  string[] descNames = desc.Select(o => o.FileName).ToArray();
36
39
  CollectionAssert.AreEqual(new[] { "zeta.anim", "beta.anim", "alpha.anim" }, descNames);
37
40
  }
@@ -40,21 +43,24 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
40
43
  public void FiltersBySubstringAndRegex()
41
44
  {
42
45
  AnimationCopierWindow wnd = ScriptableObject.CreateInstance<AnimationCopierWindow>();
43
- var a = NewFileInfo("walk.anim");
44
- var b = NewFileInfo("attack.anim");
45
- var c = NewFileInfo("idle.anim");
46
- var items = new List<AnimationCopierWindow.AnimationFileInfo> { a, b, c };
46
+ AnimationCopierWindow.AnimationFileInfo a = NewFileInfo("walk.anim");
47
+ AnimationCopierWindow.AnimationFileInfo b = NewFileInfo("attack.anim");
48
+ AnimationCopierWindow.AnimationFileInfo c = NewFileInfo("idle.anim");
49
+ List<AnimationCopierWindow.AnimationFileInfo> items =
50
+ new List<AnimationCopierWindow.AnimationFileInfo> { a, b, c };
47
51
 
48
52
  wnd._filterText = "ta";
49
53
  wnd._filterUseRegex = false;
50
54
  wnd._sortAscending = true;
51
- var sub = wnd.ApplyFilterAndSort(items).ToList();
55
+ List<AnimationCopierWindow.AnimationFileInfo> sub = wnd.ApplyFilterAndSort(items)
56
+ .ToList();
52
57
  string[] subNames = sub.Select(o => o.FileName).ToArray();
53
58
  CollectionAssert.AreEquivalent(new[] { "attack.anim" }, subNames);
54
59
 
55
60
  wnd._filterText = "^i";
56
61
  wnd._filterUseRegex = true;
57
- var rx = wnd.ApplyFilterAndSort(items).ToList();
62
+ List<AnimationCopierWindow.AnimationFileInfo> rx = wnd.ApplyFilterAndSort(items)
63
+ .ToList();
58
64
  string[] rxNames = rx.Select(o => o.FileName).ToArray();
59
65
  CollectionAssert.AreEquivalent(new[] { "idle.anim" }, rxNames);
60
66
  }
@@ -5,6 +5,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
5
5
  using NUnit.Framework;
6
6
  using UnityEditor;
7
7
  using UnityEngine;
8
+ using WallstopStudios.UnityHelpers.Core.Helper;
8
9
  using WallstopStudios.UnityHelpers.Editor.Sprites;
9
10
  using WallstopStudios.UnityHelpers.Tests.Editor.Utils;
10
11
 
@@ -35,7 +36,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
35
36
  [Test]
36
37
  public void AnalyzeDetectsNewChangedUnchangedAndOrphans()
37
38
  {
38
- string srcA = Path.Combine(SrcRoot, "A.anim").Replace('\\', '/');
39
+ string srcA = Path.Combine(SrcRoot, "A.anim").SanitizePath();
39
40
  CreateEmptyClip(srcA);
40
41
  AssetDatabase.SaveAssets();
41
42
  AssetDatabase.Refresh();
@@ -55,7 +56,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
55
56
  Assert.AreEqual(0, orphansCount);
56
57
 
57
58
  // Create destination copy to become unchanged
58
- string dstA = Path.Combine(DstRoot, "A.anim").Replace('\\', '/');
59
+ string dstA = Path.Combine(DstRoot, "A.anim").SanitizePath();
59
60
  Assert.IsTrue(AssetDatabase.CopyAsset(srcA, dstA));
60
61
  AssetDatabase.SaveAssets();
61
62
  AssetDatabase.Refresh();
@@ -66,7 +67,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
66
67
  AssetDatabase.Refresh();
67
68
 
68
69
  // Add orphan in destination
69
- string dstB = Path.Combine(DstRoot, "B.anim").Replace('\\', '/');
70
+ string dstB = Path.Combine(DstRoot, "B.anim").SanitizePath();
70
71
  CreateEmptyClip(dstB);
71
72
  AssetDatabase.SaveAssets();
72
73
  AssetDatabase.Refresh();
@@ -87,8 +88,8 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
87
88
  [Test]
88
89
  public void CopyChangedPreservesGuidAndOverwrites()
89
90
  {
90
- string srcA = Path.Combine(SrcRoot, "A.anim").Replace('\\', '/');
91
- string dstA = Path.Combine(DstRoot, "A.anim").Replace('\\', '/');
91
+ string srcA = Path.Combine(SrcRoot, "A.anim").SanitizePath();
92
+ string dstA = Path.Combine(DstRoot, "A.anim").SanitizePath();
92
93
  CreateEmptyClip(srcA);
93
94
  AssetDatabase.SaveAssets();
94
95
  AssetDatabase.Refresh();
@@ -121,8 +122,8 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
121
122
  [Test]
122
123
  public void MirrorDeleteRemovesOrphansWhenNotDryRun()
123
124
  {
124
- string srcA = Path.Combine(SrcRoot, "A.anim").Replace('\\', '/');
125
- string dstB = Path.Combine(DstRoot, "B.anim").Replace('\\', '/');
125
+ string srcA = Path.Combine(SrcRoot, "A.anim").SanitizePath();
126
+ string dstB = Path.Combine(DstRoot, "B.anim").SanitizePath();
126
127
  CreateEmptyClip(srcA);
127
128
  CreateEmptyClip(dstB);
128
129
  AssetDatabase.SaveAssets();
@@ -29,7 +29,8 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
29
29
  keys[2] = new ObjectReferenceKeyframe { time = 0.2f, value = s3 };
30
30
  AnimationUtility.SetObjectReferenceCurve(clip, binding, keys);
31
31
 
32
- var instance = new AnimationViewerWindow.EditorLayerData(clip);
32
+ AnimationViewerWindow.EditorLayerData instance =
33
+ new AnimationViewerWindow.EditorLayerData(clip);
33
34
  Assert.NotNull(instance);
34
35
  Assert.AreEqual(3, instance.Sprites.Count);
35
36
  }