com.wallstop-studios.unity-helpers 2.0.0 → 2.0.1

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 (133) hide show
  1. package/.github/workflows/format-on-demand.yml +2 -2
  2. package/.github/workflows/markdown-json.yml +1 -1
  3. package/.github/workflows/npm-publish.yml +1 -1
  4. package/.github/workflows/prettier-autofix.yml +4 -4
  5. package/.github/workflows/yaml-format-lint.yml +1 -1
  6. package/Docs/EFFECTS_SYSTEM.md +1316 -0
  7. package/{EFFECTS_SYSTEM_TUTORIAL.md → Docs/EFFECTS_SYSTEM_TUTORIAL.md} +1 -1
  8. package/{GETTING_STARTED.md → Docs/GETTING_STARTED.md} +10 -8
  9. package/{GLOSSARY.md → Docs/GLOSSARY.md} +4 -4
  10. package/Docs/HELPER_UTILITIES.md +885 -0
  11. package/Docs/HELPER_UTILITIES.md.meta +7 -0
  12. package/{INDEX.md → Docs/INDEX.md} +107 -62
  13. package/Docs/MATH_AND_EXTENSIONS.md +1039 -0
  14. package/{RANDOM_PERFORMANCE.md → Docs/RANDOM_PERFORMANCE.md} +15 -15
  15. package/{RELATIONAL_COMPONENTS.md → Docs/RELATIONAL_COMPONENTS.md} +21 -3
  16. package/{SPATIAL_TREES_2D_GUIDE.md → Docs/SPATIAL_TREES_2D_GUIDE.md} +2 -2
  17. package/{SPATIAL_TREES_3D_GUIDE.md → Docs/SPATIAL_TREES_3D_GUIDE.md} +1 -1
  18. package/{SPATIAL_TREE_2D_PERFORMANCE.md → Docs/SPATIAL_TREE_2D_PERFORMANCE.md} +64 -64
  19. package/{SPATIAL_TREE_3D_PERFORMANCE.md → Docs/SPATIAL_TREE_3D_PERFORMANCE.md} +64 -64
  20. package/Docs/UTILITY_COMPONENTS.md +906 -0
  21. package/Docs/UTILITY_COMPONENTS.md.meta +7 -0
  22. package/Docs/VISUAL_COMPONENTS.md +337 -0
  23. package/Docs/VISUAL_COMPONENTS.md.meta +7 -0
  24. package/Editor/Sprites/AnimationCopier.cs +3 -3
  25. package/README.md +69 -62
  26. package/Runtime/AssemblyInfo.cs +2 -0
  27. package/Runtime/Core/DataStructure/KDTree3D.cs +1 -1
  28. package/Runtime/Core/DataStructure/OctTree3D.cs +1 -1
  29. package/Runtime/Core/Extension/AsyncOperationExtensions.cs +122 -0
  30. package/Runtime/Core/Serialization/ProtobufUnitySurrogates.cs +24 -29
  31. package/Runtime/Integrations/Reflex/AssemblyInfo.cs +7 -0
  32. package/Runtime/Integrations/Reflex/AssemblyInfo.cs.meta +11 -0
  33. package/Runtime/Integrations/Reflex/ContainerRelationalExtensions.cs +198 -0
  34. package/Runtime/Integrations/Reflex/ContainerRelationalExtensions.cs.meta +11 -0
  35. package/Runtime/Integrations/Reflex/RelationalComponentsInstaller.cs +86 -0
  36. package/Runtime/Integrations/Reflex/RelationalComponentsInstaller.cs.meta +11 -0
  37. package/Runtime/Integrations/Reflex/RelationalReflexSceneBootstrapper.cs +316 -0
  38. package/Runtime/Integrations/Reflex/RelationalReflexSceneBootstrapper.cs.meta +11 -0
  39. package/Runtime/Integrations/Reflex/RelationalSceneAssignmentOptions.cs +86 -0
  40. package/Runtime/Integrations/Reflex/RelationalSceneAssignmentOptions.cs.meta +11 -0
  41. package/Runtime/Integrations/Reflex/WallstopStudios.UnityHelpers.Integration.Reflex.asmdef +20 -0
  42. package/Runtime/Integrations/Reflex/WallstopStudios.UnityHelpers.Integration.Reflex.asmdef.meta +7 -0
  43. package/Runtime/Integrations/Reflex.meta +8 -0
  44. package/Runtime/Utils/ScriptableObjectSingleton.cs +1 -1
  45. package/Samples~/DI - Reflex/README.md +527 -0
  46. package/Samples~/DI - Reflex/README.md.meta +7 -0
  47. package/Samples~/DI - Reflex/Scripts/ReflexPaletteService.cs +36 -0
  48. package/Samples~/DI - Reflex/Scripts/ReflexPaletteService.cs.meta +11 -0
  49. package/Samples~/DI - Reflex/Scripts/ReflexRelationalConsumer.cs +79 -0
  50. package/Samples~/DI - Reflex/Scripts/ReflexRelationalConsumer.cs.meta +11 -0
  51. package/Samples~/DI - Reflex/Scripts/ReflexSampleInstaller.cs +30 -0
  52. package/Samples~/DI - Reflex/Scripts/ReflexSampleInstaller.cs.meta +11 -0
  53. package/Samples~/DI - Reflex/Scripts/ReflexSpawner.cs +79 -0
  54. package/Samples~/DI - Reflex/Scripts/ReflexSpawner.cs.meta +11 -0
  55. package/Samples~/DI - Reflex/Scripts/Samples.UnityHelpers.DI.Reflex.asmdef +26 -0
  56. package/Samples~/DI - Reflex/Scripts/Samples.UnityHelpers.DI.Reflex.asmdef.meta +9 -0
  57. package/Samples~/DI - Reflex/Scripts.meta +8 -0
  58. package/Samples~/DI - Reflex.meta +8 -0
  59. package/Samples~/DI - VContainer/README.md +6 -5
  60. package/Samples~/DI - Zenject/README.md +6 -5
  61. package/Tests/Editor/Core/Attributes/RelationalComponentAssignerTests.cs +29 -31
  62. package/Tests/Editor/Integrations/Reflex/ReflexIntegrationCompilationTests.cs +41 -0
  63. package/Tests/Editor/Integrations/Reflex/ReflexIntegrationCompilationTests.cs.meta +11 -0
  64. package/Tests/Editor/Integrations/Reflex/WallstopStudios.UnityHelpers.Tests.Editor.Reflex.asmdef +27 -0
  65. package/Tests/Editor/Integrations/Reflex/WallstopStudios.UnityHelpers.Tests.Editor.Reflex.asmdef.meta +7 -0
  66. package/Tests/Editor/Integrations/Reflex.meta +8 -0
  67. package/Tests/Editor/Integrations/VContainer/VContainerRelationalEntryPointTests.cs +15 -16
  68. package/Tests/Editor/Integrations/VContainer/VContainerRelationalHelpersTests.cs +7 -13
  69. package/Tests/Editor/Integrations/Zenject/ZenjectRelationalHelpersTests.cs +7 -11
  70. package/Tests/Editor/Integrations/Zenject/ZenjectRelationalInitializerTests.cs +19 -21
  71. package/Tests/Editor/PersistentDirectorySettingsTests.cs +0 -1
  72. package/Tests/Editor/Sprites/AnimationCopierFilterTests.cs +0 -1
  73. package/Tests/Editor/Sprites/AnimationViewerWindowTests.cs +2 -2
  74. package/Tests/Editor/Tools/ImageBlurToolTests.cs +1 -1
  75. package/Tests/Editor/Utils/CommonTestBase.cs +17 -0
  76. package/Tests/Editor/Utils/ScriptableObjectSingletonCreatorTests.cs +1 -1
  77. package/Tests/Runtime/Extensions/AsyncOperationExtensionsTests.cs +179 -0
  78. package/Tests/Runtime/Extensions/RandomExtensionTests.cs +55 -0
  79. package/Tests/Runtime/Integrations/Reflex/RelationalComponentsReflexTests.cs +445 -0
  80. package/Tests/Runtime/Integrations/Reflex/RelationalComponentsReflexTests.cs.meta +11 -0
  81. package/Tests/Runtime/Integrations/Reflex/WallstopStudios.UnityHelpers.Tests.Runtime.Reflex.asmdef +28 -0
  82. package/Tests/Runtime/Integrations/Reflex/WallstopStudios.UnityHelpers.Tests.Runtime.Reflex.asmdef.meta +7 -0
  83. package/Tests/Runtime/Integrations/Reflex.meta +8 -0
  84. package/Tests/Runtime/Integrations/VContainer/RelationalComponentsVContainerTests.cs +24 -29
  85. package/Tests/Runtime/Integrations/VContainer/RelationalObjectPoolsVContainerTests.cs +8 -3
  86. package/Tests/Runtime/Integrations/Zenject/RelationalComponentsZenjectTests.cs +10 -20
  87. package/Tests/Runtime/Performance/RandomPerformanceTests.cs +1 -1
  88. package/Tests/Runtime/Performance/SpatialTree2DPerformanceTests.cs +1 -1
  89. package/Tests/Runtime/Performance/SpatialTree3DPerformanceTests.cs +1 -1
  90. package/Tests/Runtime/Serialization/JsonRoundtripComprehensiveTests.cs +4 -9
  91. package/Tests/Runtime/Serialization/ProtoRoundtripComprehensiveTests.cs +13 -13
  92. package/Tests/Runtime/TestUtils/CommonTestBase.cs +11 -0
  93. package/Tests/Runtime/TestUtils/ReflexTestSupport.cs +111 -0
  94. package/Tests/Runtime/TestUtils/ReflexTestSupport.cs.meta +12 -0
  95. package/Tests/Runtime/Utils/MatchColliderToSpriteTests.cs +4 -4
  96. package/Tests/TestUtils.meta +8 -0
  97. package/package.json +6 -1
  98. package/EFFECTS_SYSTEM.md +0 -242
  99. package/MATH_AND_EXTENSIONS.md +0 -316
  100. /package/{CHANGELOG.md → Docs/CHANGELOG.md} +0 -0
  101. /package/{CHANGELOG.md.meta → Docs/CHANGELOG.md.meta} +0 -0
  102. /package/{CONTRIBUTING.md → Docs/CONTRIBUTING.md} +0 -0
  103. /package/{CONTRIBUTING.md.meta → Docs/CONTRIBUTING.md.meta} +0 -0
  104. /package/{DATA_STRUCTURES.md → Docs/DATA_STRUCTURES.md} +0 -0
  105. /package/{DATA_STRUCTURES.md.meta → Docs/DATA_STRUCTURES.md.meta} +0 -0
  106. /package/{EDITOR_TOOLS_GUIDE.md → Docs/EDITOR_TOOLS_GUIDE.md} +0 -0
  107. /package/{EDITOR_TOOLS_GUIDE.md.meta → Docs/EDITOR_TOOLS_GUIDE.md.meta} +0 -0
  108. /package/{EFFECTS_SYSTEM.md.meta → Docs/EFFECTS_SYSTEM.md.meta} +0 -0
  109. /package/{EFFECTS_SYSTEM_TUTORIAL.md.meta → Docs/EFFECTS_SYSTEM_TUTORIAL.md.meta} +0 -0
  110. /package/{GETTING_STARTED.md.meta → Docs/GETTING_STARTED.md.meta} +0 -0
  111. /package/{GLOSSARY.md.meta → Docs/GLOSSARY.md.meta} +0 -0
  112. /package/{HULLS.md → Docs/HULLS.md} +0 -0
  113. /package/{HULLS.md.meta → Docs/HULLS.md.meta} +0 -0
  114. /package/{INDEX.md.meta → Docs/INDEX.md.meta} +0 -0
  115. /package/{LICENSE.md → Docs/LICENSE.md} +0 -0
  116. /package/{LICENSE.md.meta → Docs/LICENSE.md.meta} +0 -0
  117. /package/{MATH_AND_EXTENSIONS.md.meta → Docs/MATH_AND_EXTENSIONS.md.meta} +0 -0
  118. /package/{RANDOM_PERFORMANCE.md.meta → Docs/RANDOM_PERFORMANCE.md.meta} +0 -0
  119. /package/{REFLECTION_HELPERS.md → Docs/REFLECTION_HELPERS.md} +0 -0
  120. /package/{REFLECTION_HELPERS.md.meta → Docs/REFLECTION_HELPERS.md.meta} +0 -0
  121. /package/{RELATIONAL_COMPONENTS.md.meta → Docs/RELATIONAL_COMPONENTS.md.meta} +0 -0
  122. /package/{SERIALIZATION.md → Docs/SERIALIZATION.md} +0 -0
  123. /package/{SERIALIZATION.md.meta → Docs/SERIALIZATION.md.meta} +0 -0
  124. /package/{SINGLETONS.md → Docs/SINGLETONS.md} +0 -0
  125. /package/{SINGLETONS.md.meta → Docs/SINGLETONS.md.meta} +0 -0
  126. /package/{SPATIAL_TREES_2D_GUIDE.md.meta → Docs/SPATIAL_TREES_2D_GUIDE.md.meta} +0 -0
  127. /package/{SPATIAL_TREES_3D_GUIDE.md.meta → Docs/SPATIAL_TREES_3D_GUIDE.md.meta} +0 -0
  128. /package/{SPATIAL_TREE_2D_PERFORMANCE.md.meta → Docs/SPATIAL_TREE_2D_PERFORMANCE.md.meta} +0 -0
  129. /package/{SPATIAL_TREE_3D_PERFORMANCE.md.meta → Docs/SPATIAL_TREE_3D_PERFORMANCE.md.meta} +0 -0
  130. /package/{SPATIAL_TREE_SEMANTICS.md → Docs/SPATIAL_TREE_SEMANTICS.md} +0 -0
  131. /package/{SPATIAL_TREE_SEMANTICS.md.meta → Docs/SPATIAL_TREE_SEMANTICS.md.meta} +0 -0
  132. /package/{THIRD_PARTY_NOTICES.md → Docs/THIRD_PARTY_NOTICES.md} +0 -0
  133. /package/{THIRD_PARTY_NOTICES.md.meta → Docs/THIRD_PARTY_NOTICES.md.meta} +0 -0
@@ -33,20 +33,19 @@ namespace WallstopStudios.UnityHelpers.Tests.Integrations.Zenject
33
33
 
34
34
  AttributeMetadataCache cache = CreateScriptableObject<AttributeMetadataCache>();
35
35
  #if UNITY_EDITOR
36
- AttributeMetadataCache.RelationalTypeMetadata relationalMetadata =
37
- new AttributeMetadataCache.RelationalTypeMetadata(
38
- typeof(Consumer).AssemblyQualifiedName,
39
- new[]
40
- {
41
- new AttributeMetadataCache.RelationalFieldMetadata(
42
- "_spriteRenderer",
43
- AttributeMetadataCache.RelationalAttributeKind.Sibling,
44
- AttributeMetadataCache.FieldKind.Single,
45
- typeof(SpriteRenderer).AssemblyQualifiedName,
46
- false
47
- ),
48
- }
49
- );
36
+ AttributeMetadataCache.RelationalTypeMetadata relationalMetadata = new(
37
+ typeof(Consumer).AssemblyQualifiedName,
38
+ new[]
39
+ {
40
+ new AttributeMetadataCache.RelationalFieldMetadata(
41
+ "_spriteRenderer",
42
+ AttributeMetadataCache.RelationalAttributeKind.Sibling,
43
+ AttributeMetadataCache.FieldKind.Single,
44
+ typeof(SpriteRenderer).AssemblyQualifiedName,
45
+ false
46
+ ),
47
+ }
48
+ );
50
49
 
51
50
  cache.SetMetadata(
52
51
  System.Array.Empty<string>(),
@@ -57,13 +56,12 @@ namespace WallstopStudios.UnityHelpers.Tests.Integrations.Zenject
57
56
  yield return null;
58
57
  #endif
59
58
 
60
- RelationalComponentAssigner assigner = new RelationalComponentAssigner(cache);
61
- RelationalComponentSceneInitializer initializer =
62
- new RelationalComponentSceneInitializer(
63
- assigner,
64
- cache,
65
- RelationalSceneAssignmentOptions.Default
66
- );
59
+ RelationalComponentAssigner assigner = new(cache);
60
+ RelationalComponentSceneInitializer initializer = new(
61
+ assigner,
62
+ cache,
63
+ RelationalSceneAssignmentOptions.Default
64
+ );
67
65
 
68
66
  initializer.Initialize();
69
67
 
@@ -2,7 +2,6 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor
2
2
  {
3
3
  #if UNITY_EDITOR
4
4
  using NUnit.Framework;
5
- using UnityEditor;
6
5
  using UnityEngine;
7
6
  using WallstopStudios.UnityHelpers.Editor;
8
7
 
@@ -1,7 +1,6 @@
1
1
  namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
2
2
  {
3
3
  #if UNITY_EDITOR
4
- using System;
5
4
  using System.Collections.Generic;
6
5
  using System.Linq;
7
6
  using NUnit.Framework;
@@ -12,8 +12,8 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Sprites
12
12
  public void EditorLayerDataBuildsSpriteListFromClip()
13
13
  {
14
14
  // Build a test clip with 3 sprite keyframes
15
- AnimationClip clip = new AnimationClip();
16
- Texture2D tex = new Texture2D(2, 2);
15
+ AnimationClip clip = new();
16
+ Texture2D tex = new(2, 2);
17
17
  Sprite s1 = Sprite.Create(tex, new Rect(0, 0, 1, 1), Vector2.zero);
18
18
  Sprite s2 = Sprite.Create(tex, new Rect(0, 0, 1, 1), Vector2.zero);
19
19
  Sprite s3 = Sprite.Create(tex, new Rect(0, 0, 1, 1), Vector2.zero);
@@ -27,7 +27,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Tools
27
27
  [Test]
28
28
  public void BlurredTextureMatchesInputDimensions()
29
29
  {
30
- Texture2D tex = new Texture2D(8, 8, TextureFormat.RGBA32, false);
30
+ Texture2D tex = new(8, 8, TextureFormat.RGBA32, false);
31
31
  for (int y = 0; y < tex.height; y++)
32
32
  {
33
33
  for (int x = 0; x < tex.width; x++)
@@ -3,6 +3,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Utils
3
3
  using System;
4
4
  using System.Collections;
5
5
  using System.Collections.Generic;
6
+ using System.Reflection;
6
7
  using NUnit.Framework;
7
8
  using UnityEngine;
8
9
  using UnityEngine.SceneManagement;
@@ -19,6 +20,22 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Utils
19
20
  /// </summary>
20
21
  public abstract class CommonTestBase
21
22
  {
23
+ [SetUp]
24
+ public virtual void BaseSetUp()
25
+ {
26
+ #if REFLEX_PRESENT
27
+ Type supportType = Type.GetType(
28
+ "WallstopStudios.UnityHelpers.Tests.TestUtils.ReflexTestSupport, WallstopStudios.UnityHelpers.Tests.Runtime",
29
+ throwOnError: false
30
+ );
31
+ MethodInfo ensureMethod = supportType?.GetMethod(
32
+ "EnsureReflexSettings",
33
+ BindingFlags.Public | BindingFlags.Static
34
+ );
35
+ ensureMethod?.Invoke(null, null);
36
+ #endif
37
+ }
38
+
22
39
  protected readonly List<Object> _trackedObjects = new();
23
40
  protected readonly List<IDisposable> _trackedDisposables = new();
24
41
  protected readonly List<Scene> _trackedScenes = new();
@@ -79,7 +79,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Editor.Utils
79
79
  string occupiedPath = targetFolder + "/Duplicate.asset";
80
80
  if (AssetDatabase.LoadAssetAtPath<Object>(occupiedPath) == null)
81
81
  {
82
- TextAsset ta = new TextAsset("occupied");
82
+ TextAsset ta = new("occupied");
83
83
  AssetDatabase.CreateAsset(ta, occupiedPath);
84
84
  }
85
85
 
@@ -281,6 +281,91 @@ namespace WallstopStudios.UnityHelpers.Tests.Extensions
281
281
  Assert.IsTrue(exceptionThrown);
282
282
  }
283
283
 
284
+ [UnityTest]
285
+ public IEnumerator TaskTupleAsCoroutineCompletesSuccessfully()
286
+ {
287
+ Task<(int, string)> task = CreateDelayedTask(() => (7, "lucky"));
288
+
289
+ int first = 0;
290
+ string second = null;
291
+ yield return task.AsCoroutine(
292
+ (value, label) =>
293
+ {
294
+ first = value;
295
+ second = label;
296
+ }
297
+ );
298
+
299
+ Assert.AreEqual(7, first);
300
+ Assert.AreEqual("lucky", second);
301
+ }
302
+
303
+ [UnityTest]
304
+ public IEnumerator TaskTupleAsCoroutineWorksWithoutCallback()
305
+ {
306
+ Task<(int, string)> task = CreateDelayedTask(() => (5, "five"));
307
+
308
+ yield return task.AsCoroutine();
309
+
310
+ Assert.AreEqual((5, "five"), task.Result);
311
+ }
312
+
313
+ [UnityTest]
314
+ public IEnumerator TaskTupleAsCoroutineThrowsOnFaultedTask()
315
+ {
316
+ Task<(int, string)> task = CreateFaultedTask<(int, string)>();
317
+
318
+ bool exceptionThrown = false;
319
+ IEnumerator coroutine = task.AsCoroutine((_, _) => { });
320
+
321
+ while (true)
322
+ {
323
+ try
324
+ {
325
+ if (!coroutine.MoveNext())
326
+ {
327
+ break;
328
+ }
329
+ }
330
+ catch (InvalidOperationException)
331
+ {
332
+ exceptionThrown = true;
333
+ break;
334
+ }
335
+ catch (AggregateException e)
336
+ {
337
+ exceptionThrown = e.Flatten()
338
+ .InnerExceptions.Any(inner => inner is InvalidOperationException);
339
+ break;
340
+ }
341
+ yield return null;
342
+ }
343
+
344
+ Assert.IsTrue(exceptionThrown);
345
+ }
346
+
347
+ [UnityTest]
348
+ public IEnumerator TaskTripleAsCoroutineCompletesSuccessfully()
349
+ {
350
+ Task<(int, string, bool)> task = CreateDelayedTask(() => (1, "one", true));
351
+
352
+ int first = 0;
353
+ string second = null;
354
+ bool third = false;
355
+ yield return task.AsCoroutine(
356
+ (value, label, flag) =>
357
+ {
358
+ first = value;
359
+ second = label;
360
+ third = flag;
361
+ }
362
+ );
363
+
364
+ Assert.AreEqual(1, first);
365
+ Assert.AreEqual("one", second);
366
+ Assert.IsTrue(third);
367
+ }
368
+
284
369
  // Tests for ValueTask.AsCoroutine()
285
370
  [UnityTest]
286
371
  public IEnumerator ValueTaskAsCoroutineCompletesSuccessfully()
@@ -400,6 +485,100 @@ namespace WallstopStudios.UnityHelpers.Tests.Extensions
400
485
  Assert.IsTrue(exceptionThrown);
401
486
  }
402
487
 
488
+ [UnityTest]
489
+ public IEnumerator ValueTaskTupleAsCoroutineCompletesSuccessfully()
490
+ {
491
+ ValueTask<(int, string)> task = new(CreateDelayedTask(() => (2, "two")));
492
+
493
+ int first = 0;
494
+ string second = null;
495
+ yield return task.AsCoroutine(
496
+ (value, label) =>
497
+ {
498
+ first = value;
499
+ second = label;
500
+ }
501
+ );
502
+
503
+ Assert.AreEqual(2, first);
504
+ Assert.AreEqual("two", second);
505
+ }
506
+
507
+ [UnityTest]
508
+ public IEnumerator ValueTaskTupleAsCoroutineCompletesImmediatelyWhenAlreadyDone()
509
+ {
510
+ ValueTask<(int, string)> task = new((3, "three"));
511
+
512
+ int first = 0;
513
+ string second = null;
514
+ yield return task.AsCoroutine(
515
+ (value, label) =>
516
+ {
517
+ first = value;
518
+ second = label;
519
+ }
520
+ );
521
+
522
+ Assert.AreEqual(3, first);
523
+ Assert.AreEqual("three", second);
524
+ }
525
+
526
+ [UnityTest]
527
+ public IEnumerator ValueTaskTupleAsCoroutineThrowsOnFaultedTask()
528
+ {
529
+ ValueTask<(int, string)> task = new(CreateFaultedTask<(int, string)>());
530
+
531
+ bool exceptionThrown = false;
532
+ IEnumerator coroutine = task.AsCoroutine((_, _) => { });
533
+
534
+ while (true)
535
+ {
536
+ try
537
+ {
538
+ if (!coroutine.MoveNext())
539
+ {
540
+ break;
541
+ }
542
+ }
543
+ catch (InvalidOperationException)
544
+ {
545
+ exceptionThrown = true;
546
+ break;
547
+ }
548
+ catch (AggregateException e)
549
+ {
550
+ exceptionThrown = e.Flatten()
551
+ .InnerExceptions.Any(inner => inner is InvalidOperationException);
552
+ break;
553
+ }
554
+ yield return null;
555
+ }
556
+
557
+ Assert.IsTrue(exceptionThrown);
558
+ }
559
+
560
+ [UnityTest]
561
+ public IEnumerator ValueTaskTripleAsCoroutineCompletesSuccessfully()
562
+ {
563
+ ValueTask<(int, string, bool)> task = new(CreateDelayedTask(() => (4, "four", true)));
564
+
565
+ int first = 0;
566
+ string second = null;
567
+ bool third = false;
568
+ yield return task.AsCoroutine(
569
+ (value, label, flag) =>
570
+ {
571
+ first = value;
572
+ second = label;
573
+ third = flag;
574
+ }
575
+ );
576
+
577
+ Assert.AreEqual(4, first);
578
+ Assert.AreEqual("four", second);
579
+ Assert.IsTrue(third);
580
+ }
581
+
403
582
  // Tests for IEnumerator.AsTask()
404
583
  [UnityTest]
405
584
  public IEnumerator IEnumeratorAsTaskCompletesSuccessfully()
@@ -445,6 +445,61 @@ namespace WallstopStudios.UnityHelpers.Tests.Extensions
445
445
  }
446
446
  }
447
447
 
448
+ [Test]
449
+ public void NextWeightedElement()
450
+ {
451
+ List<string> items = new() { "rare", "common" };
452
+ List<float> weights = new() { 1f, 99f };
453
+ HashSet<string> seen = new();
454
+ int commonCount = 0;
455
+ int rareCount = 0;
456
+ for (int i = 0; i < 1000; ++i)
457
+ {
458
+ string result = PRNG.Instance.NextWeightedElement(items, weights);
459
+ seen.Add(result);
460
+ if (result == "common")
461
+ {
462
+ commonCount++;
463
+ }
464
+ else if (result == "rare")
465
+ {
466
+ rareCount++;
467
+ }
468
+ }
469
+
470
+ Assert.AreEqual(2, seen.Count);
471
+ Assert.Greater(commonCount, rareCount);
472
+ Assert.Greater(commonCount, 900);
473
+ }
474
+
475
+ [Test]
476
+ public void NextWeightedElementThrowsOnNullItems()
477
+ {
478
+ List<float> weights = new() { 1f };
479
+ Assert.Throws<ArgumentNullException>(() =>
480
+ PRNG.Instance.NextWeightedElement<string>(null, weights)
481
+ );
482
+ }
483
+
484
+ [Test]
485
+ public void NextWeightedElementThrowsOnNullWeights()
486
+ {
487
+ List<string> items = new() { "item" };
488
+ Assert.Throws<ArgumentNullException>(() =>
489
+ PRNG.Instance.NextWeightedElement(items, (IReadOnlyList<float>)null)
490
+ );
491
+ }
492
+
493
+ [Test]
494
+ public void NextWeightedElementThrowsOnMismatchedCounts()
495
+ {
496
+ List<string> items = new() { "item" };
497
+ List<float> weights = new() { 1f, 2f };
498
+ Assert.Throws<ArgumentException>(() =>
499
+ PRNG.Instance.NextWeightedElement(items, weights)
500
+ );
501
+ }
502
+
448
503
  [Test]
449
504
  public void NextWeighted()
450
505
  {