com.wallstop-studios.unity-helpers 2.0.4 → 2.1.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.
- package/Docs/DATA_STRUCTURES.md +7 -7
- package/Docs/EFFECTS_SYSTEM.md +836 -8
- package/Docs/EFFECTS_SYSTEM_TUTORIAL.md +77 -18
- package/Docs/HULLS.md +2 -2
- package/Docs/ILIST_SORTING_PERFORMANCE.md +92 -0
- package/Docs/ILIST_SORTING_PERFORMANCE.md.meta +7 -0
- package/Docs/INDEX.md +10 -1
- package/Docs/Images/random_generators.svg +7 -7
- package/Docs/RANDOM_PERFORMANCE.md +18 -15
- package/Docs/REFLECTION_HELPERS.md +1 -1
- package/Docs/RELATIONAL_COMPONENTS.md +51 -6
- package/Docs/SERIALIZATION.md +1 -1
- package/Docs/SINGLETONS.md +2 -2
- package/Docs/SPATIAL_TREES_2D_GUIDE.md +3 -3
- package/Docs/SPATIAL_TREES_3D_GUIDE.md +3 -3
- package/Docs/SPATIAL_TREE_2D_PERFORMANCE.md +64 -64
- package/Docs/SPATIAL_TREE_3D_PERFORMANCE.md +64 -64
- package/Docs/SPATIAL_TREE_SEMANTICS.md +7 -7
- package/Editor/Core/Helper/AnimationEventHelpers.cs +1 -1
- package/Editor/CustomDrawers/WShowIfPropertyDrawer.cs +131 -41
- package/Editor/Utils/ScriptableObjectSingletonCreator.cs +175 -18
- package/README.md +42 -18
- package/Runtime/Core/Extension/IListExtensions.cs +720 -12
- package/Runtime/Core/Helper/UnityMainThreadDispatcher.cs +2 -3
- package/Runtime/Core/Random/AbstractRandom.cs +52 -5
- package/Runtime/Core/Random/DotNetRandom.cs +3 -3
- package/Runtime/Core/Random/FlurryBurstRandom.cs +285 -0
- package/Runtime/Core/Random/FlurryBurstRandom.cs.meta +3 -0
- package/Runtime/Core/Random/IllusionFlow.cs +3 -3
- package/Runtime/Core/Random/LinearCongruentialGenerator.cs +3 -3
- package/Runtime/Core/Random/PcgRandom.cs +6 -6
- package/Runtime/Core/Random/PhotonSpinRandom.cs +387 -0
- package/Runtime/Core/Random/PhotonSpinRandom.cs.meta +3 -0
- package/Runtime/Core/Random/RomuDuo.cs +3 -3
- package/Runtime/Core/Random/SplitMix64.cs +3 -3
- package/Runtime/Core/Random/SquirrelRandom.cs +6 -4
- package/Runtime/Core/Random/StormDropRandom.cs +271 -0
- package/Runtime/Core/Random/StormDropRandom.cs.meta +3 -0
- package/Runtime/Core/Random/UnityRandom.cs +3 -3
- package/Runtime/Core/Random/WyRandom.cs +6 -4
- package/Runtime/Core/Random/XorShiftRandom.cs +3 -3
- package/Runtime/Core/Random/XoroShiroRandom.cs +3 -3
- package/Runtime/Tags/Attribute.cs +144 -24
- package/Runtime/Tags/AttributeEffect.cs +119 -16
- package/Runtime/Tags/AttributeMetadataCache.cs +312 -3
- package/Runtime/Tags/AttributeModification.cs +59 -29
- package/Runtime/Tags/AttributesComponent.cs +20 -0
- package/Runtime/Tags/EffectBehavior.cs +171 -0
- package/Runtime/Tags/EffectBehavior.cs.meta +4 -0
- package/Runtime/Tags/EffectHandle.cs +5 -0
- package/Runtime/Tags/EffectHandler.cs +385 -39
- package/Runtime/Tags/EffectStackKey.cs +79 -0
- package/Runtime/Tags/EffectStackKey.cs.meta +4 -0
- package/Runtime/Tags/PeriodicEffectDefinition.cs +102 -0
- package/Runtime/Tags/PeriodicEffectDefinition.cs.meta +4 -0
- package/Runtime/Tags/PeriodicEffectRuntimeState.cs +40 -0
- package/Runtime/Tags/PeriodicEffectRuntimeState.cs.meta +4 -0
- package/Samples~/DI - Zenject/README.md +0 -2
- package/Tests/Editor/Attributes/WShowIfPropertyDrawerTests.cs +285 -0
- package/Tests/Editor/Attributes/WShowIfPropertyDrawerTests.cs.meta +11 -0
- package/Tests/Editor/Core/Attributes/RelationalComponentAssignerTests.cs +2 -2
- package/Tests/Editor/Tags/AttributeMetadataCacheTests.cs +192 -0
- package/Tests/Editor/Tags/AttributeMetadataCacheTests.cs.meta +11 -0
- package/{node_modules.meta → Tests/Editor/Tags.meta} +1 -1
- package/Tests/Editor/Utils/ScriptableObjectSingletonTests.cs +41 -0
- package/Tests/Runtime/Extensions/IListExtensionTests.cs +187 -1
- package/Tests/Runtime/Helper/ObjectsTests.cs +3 -3
- package/Tests/Runtime/Integrations/Reflex/RelationalComponentsReflexTests.cs +2 -2
- package/Tests/Runtime/Performance/IListSortingPerformanceTests.cs +346 -0
- package/Tests/Runtime/Performance/IListSortingPerformanceTests.cs.meta +11 -0
- package/Tests/Runtime/Performance/RandomPerformanceTests.cs +3 -0
- package/Tests/Runtime/Random/FlurryBurstRandomTests.cs +12 -0
- package/Tests/Runtime/Random/FlurryBurstRandomTests.cs.meta +3 -0
- package/Tests/Runtime/Random/PhotonSpinRandomTests.cs +12 -0
- package/Tests/Runtime/Random/PhotonSpinRandomTests.cs.meta +3 -0
- package/Tests/Runtime/Random/RandomProtoSerializationTests.cs +14 -0
- package/Tests/Runtime/Random/RandomTestBase.cs +39 -4
- package/Tests/Runtime/Random/StormDropRandomTests.cs +12 -0
- package/Tests/Runtime/Random/StormDropRandomTests.cs.meta +3 -0
- package/Tests/Runtime/Serialization/JsonSerializationTest.cs +4 -3
- package/Tests/Runtime/Serialization/ProtoInterfaceResolutionEdgeTests.cs +2 -2
- package/Tests/Runtime/Serialization/ProtoRootRegistrationTests.cs +1 -1
- package/Tests/Runtime/Serialization/ProtoSerializeBehaviorTests.cs +1 -1
- package/Tests/Runtime/Tags/AttributeEffectTests.cs +135 -0
- package/Tests/Runtime/Tags/AttributeEffectTests.cs.meta +3 -0
- package/Tests/Runtime/Tags/AttributeModificationTests.cs +137 -0
- package/Tests/Runtime/Tags/AttributeTests.cs +192 -0
- package/Tests/Runtime/Tags/AttributeTests.cs.meta +3 -0
- package/Tests/Runtime/Tags/EffectBehaviorTests.cs +184 -0
- package/Tests/Runtime/Tags/EffectBehaviorTests.cs.meta +3 -0
- package/Tests/Runtime/Tags/EffectHandlerTests.cs +618 -0
- package/Tests/Runtime/Tags/Helpers/RecordingEffectBehavior.cs +89 -0
- package/Tests/Runtime/Tags/Helpers/RecordingEffectBehavior.cs.meta +4 -0
- package/Tests/Runtime/Tags/PeriodicEffectDefinitionSerializationTests.cs +92 -0
- package/Tests/Runtime/Tags/PeriodicEffectDefinitionSerializationTests.cs.meta +3 -0
- package/package.json +1 -1
- package/scripts/lint-doc-links.ps1 +156 -11
- package/Tests/Runtime/Tags/AttributeDataTests.cs +0 -312
- /package/Tests/Runtime/Tags/{AttributeDataTests.cs.meta → AttributeModificationTests.cs.meta} +0 -0
|
@@ -61,8 +61,9 @@ public class PlayerStats : AttributesComponent
|
|
|
61
61
|
{
|
|
62
62
|
// Define attributes that effects can modify
|
|
63
63
|
public Attribute Speed = 5f;
|
|
64
|
-
public Attribute
|
|
65
|
-
public Attribute
|
|
64
|
+
public Attribute MaxHealth = 100f;
|
|
65
|
+
public Attribute AttackDamage = 10f;
|
|
66
|
+
public Attribute Defense = 5f;
|
|
66
67
|
|
|
67
68
|
void Start()
|
|
68
69
|
{
|
|
@@ -80,6 +81,15 @@ public class PlayerStats : AttributesComponent
|
|
|
80
81
|
- Calculates final value automatically (Add → Multiply → Override)
|
|
81
82
|
- Raises events when value changes
|
|
82
83
|
|
|
84
|
+
**⚠️ Important: Use Attributes for "max" or "rate" values, NOT "current" depleting values!**
|
|
85
|
+
|
|
86
|
+
- ✅ **MaxHealth** - modified by buffs (good)
|
|
87
|
+
- ❌ **CurrentHealth** - modified by damage/healing from many systems (bad - causes state conflicts)
|
|
88
|
+
- ✅ **AttackDamage** - modified by strength buffs (good)
|
|
89
|
+
- ✅ **Speed** - modified by haste/slow effects (good)
|
|
90
|
+
|
|
91
|
+
If a value is frequently modified by systems outside the effects system (like health being reduced by damage), use a regular field instead. See the main documentation for details.
|
|
92
|
+
|
|
83
93
|
---
|
|
84
94
|
|
|
85
95
|
## Step 2: Add Stats to Your Player (30 seconds)
|
|
@@ -88,8 +98,9 @@ public class PlayerStats : AttributesComponent
|
|
|
88
98
|
2. Add Component → `PlayerStats`
|
|
89
99
|
3. Set values in Inspector:
|
|
90
100
|
- Speed: `5`
|
|
91
|
-
-
|
|
92
|
-
-
|
|
101
|
+
- MaxHealth: `100`
|
|
102
|
+
- AttackDamage: `10`
|
|
103
|
+
- Defense: `5`
|
|
93
104
|
|
|
94
105
|
That's it! Your player now has modifiable attributes.
|
|
95
106
|
|
|
@@ -282,8 +293,8 @@ One effect can modify multiple attributes:
|
|
|
282
293
|
**Create "Berserker Rage" effect:**
|
|
283
294
|
|
|
284
295
|
- Modification 1: Speed × 1.3
|
|
285
|
-
- Modification 2:
|
|
286
|
-
- Modification 3:
|
|
296
|
+
- Modification 2: AttackDamage × 2.0
|
|
297
|
+
- Modification 3: Defense × 0.5 (trade-off - more damage but less defense!)
|
|
287
298
|
- Duration: 10 seconds
|
|
288
299
|
- Tags: `"Berserker"`, `"Buff"`
|
|
289
300
|
|
|
@@ -312,23 +323,63 @@ if (handle.HasValue)
|
|
|
312
323
|
|
|
313
324
|
```csharp
|
|
314
325
|
// Create "Poison" effect:
|
|
315
|
-
// -
|
|
326
|
+
// - periodicEffects: interval = 1s, maxTicks = 10, modifications = []
|
|
327
|
+
// - behaviors: PoisonDamageBehavior (below)
|
|
316
328
|
// - Duration: 10 seconds
|
|
317
|
-
// - Tags: "
|
|
329
|
+
// - Tags: "Poisoned", "DoT", "Debuff"
|
|
330
|
+
|
|
331
|
+
void ApplyPoison(GameObject target)
|
|
332
|
+
{
|
|
333
|
+
target.ApplyEffect(poisonEffect);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
[CreateAssetMenu(menuName = "Combat/Effects/Poison Damage")]
|
|
337
|
+
public sealed class PoisonDamageBehavior : EffectBehavior
|
|
338
|
+
{
|
|
339
|
+
[SerializeField]
|
|
340
|
+
private float damagePerTick = 2f;
|
|
341
|
+
|
|
342
|
+
public override void OnPeriodicTick(
|
|
343
|
+
EffectBehaviorContext context,
|
|
344
|
+
PeriodicEffectTickContext tickContext
|
|
345
|
+
)
|
|
346
|
+
{
|
|
347
|
+
if (!context.Target.TryGetComponent(out PlayerHealth health))
|
|
348
|
+
{
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
318
351
|
|
|
319
|
-
|
|
320
|
-
|
|
352
|
+
health.ApplyDamage(damagePerTick);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
321
355
|
|
|
322
|
-
|
|
323
|
-
void Update()
|
|
356
|
+
public sealed class PlayerHealth : MonoBehaviour
|
|
324
357
|
{
|
|
325
|
-
|
|
358
|
+
[SerializeField]
|
|
359
|
+
private float currentHealth = 100f;
|
|
360
|
+
|
|
361
|
+
public float CurrentHealth => currentHealth;
|
|
362
|
+
|
|
363
|
+
public void ApplyDamage(float amount)
|
|
326
364
|
{
|
|
327
|
-
|
|
365
|
+
currentHealth -= amount;
|
|
366
|
+
|
|
367
|
+
if (currentHealth <= 0f)
|
|
368
|
+
{
|
|
369
|
+
currentHealth = 0f;
|
|
370
|
+
Die();
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
private void Die()
|
|
375
|
+
{
|
|
376
|
+
// Handle player death
|
|
328
377
|
}
|
|
329
378
|
}
|
|
330
379
|
```
|
|
331
380
|
|
|
381
|
+
This keeps `CurrentHealth` as a regular gameplay field while the effect system triggers damage through behaviours.
|
|
382
|
+
|
|
332
383
|
### Cooldown Reduction
|
|
333
384
|
|
|
334
385
|
```csharp
|
|
@@ -376,6 +427,13 @@ void TryApplyBuff(AttributeEffect effect)
|
|
|
376
427
|
|
|
377
428
|
## Troubleshooting
|
|
378
429
|
|
|
430
|
+
### "Should I use CurrentHealth as an Attribute?"
|
|
431
|
+
|
|
432
|
+
- **No!** Use `MaxHealth` as an Attribute (modified by buffs), but keep `CurrentHealth` as a regular field (modified by damage/healing)
|
|
433
|
+
- **Why:** CurrentHealth is modified by many systems (combat, regeneration, etc.). Using it as an Attribute causes state conflicts when effects and other systems both try to modify it
|
|
434
|
+
- **Pattern:** Attribute for max/cap, regular field for current/depleting value
|
|
435
|
+
- **See:** "Understanding Attributes: What to Model and What to Avoid" in main documentation
|
|
436
|
+
|
|
379
437
|
### "Attribute 'Speed' not found"
|
|
380
438
|
|
|
381
439
|
- **Cause:** Attribute name in effect doesn't match field name in AttributesComponent
|
|
@@ -409,11 +467,12 @@ You now have a complete buff/debuff system! Here are some ideas to expand:
|
|
|
409
467
|
|
|
410
468
|
### Create More Effects
|
|
411
469
|
|
|
412
|
-
- **Shield:**
|
|
470
|
+
- **Shield:** MaxHealth × 1.5, visual shield sprite
|
|
413
471
|
- **Slow:** Speed × 0.5, "Slowed" tag
|
|
414
|
-
- **Critical:**
|
|
415
|
-
- **Invisibility:** Just tags ("Invisible"), no stat changes
|
|
416
|
-
- **
|
|
472
|
+
- **Critical Strike:** AttackDamage × 2.0, "CriticalHit" tag, brief flash effect
|
|
473
|
+
- **Invisibility:** Just tags ("Invisible"), no stat changes, transparency effect
|
|
474
|
+
- **Armor Buff:** Defense + 10, metallic sheen cosmetic
|
|
475
|
+
- **Strength Potion:** AttackDamage × 1.5, red particle aura
|
|
417
476
|
|
|
418
477
|
### Build Systems Around Tags
|
|
419
478
|
|
package/Docs/HULLS.md
CHANGED
|
@@ -18,7 +18,7 @@ This guide explains convex and concave hulls, when to use each, and how they dif
|
|
|
18
18
|
|
|
19
19
|
Illustration:
|
|
20
20
|
|
|
21
|
-

|
|
22
22
|
|
|
23
23
|
## Concave Hull
|
|
24
24
|
|
|
@@ -31,7 +31,7 @@ Illustration:
|
|
|
31
31
|
|
|
32
32
|
Illustration:
|
|
33
33
|
|
|
34
|
-

|
|
35
35
|
|
|
36
36
|
## Choosing Between Them
|
|
37
37
|
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# IList Sorting Performance Benchmarks
|
|
2
|
+
|
|
3
|
+
Unity Helpers ships several custom sorting algorithms for `IList<T>` that cover different trade-offs between adaptability, allocation patterns, and stability. This page gathers context and benchmark snapshots so you can choose the right algorithm for your workload and compare results across operating systems.
|
|
4
|
+
|
|
5
|
+
## Algorithm Cheatsheet
|
|
6
|
+
|
|
7
|
+
| Algorithm | Stable? | Best For | Reference |
|
|
8
|
+
| --------------------------- | ------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
|
|
9
|
+
| Ghost Sort | No | Mixed workloads that benefit from adaptive gap sorting and few allocations | Upstream project by Will Stafford Parsons (public repository currently offline) |
|
|
10
|
+
| Meteor Sort | No | Almost-sorted data where gap shrinking beats plain insertion sort | [meteorsort by Wiley Looper](https://github.com/wileylooper/meteorsort) |
|
|
11
|
+
| Pattern-Defeating QuickSort | No | General-purpose quicksort with protections against worst-case inputs | [pdqsort by Orson Peters](https://github.com/orlp/pdqsort) |
|
|
12
|
+
| Grail Sort | Yes | Large datasets where stability + low allocations matter | [GrailSort](https://github.com/Mrrl/GrailSort) |
|
|
13
|
+
| Power Sort | Yes | Partially ordered data that benefits from adaptive run detection | [PowerSort (Munro & Wild)](https://arxiv.org/abs/1805.04154) |
|
|
14
|
+
| Insertion Sort | Yes | Tiny or nearly sorted collections where O(n²) is acceptable | [Wikipedia - Insertion sort](https://en.wikipedia.org/wiki/Insertion_sort) |
|
|
15
|
+
|
|
16
|
+
> **What does “stable” mean?** Stable sorting algorithms preserve the relative order of elements that compare as equal. This matters when items carry secondary keys (e.g., sorting people by last name but keeping first-name order deterministic). Unstable algorithms can reshuffle equal entries, which is usually fine for numeric keys but can break deterministic pipelines.
|
|
17
|
+
>
|
|
18
|
+
> **Heads up:** The original Ghost Sort repository was formerly hosted on GitHub under `wstaffordp/ghostsort`, but it currently returns 404. The Unity Helpers implementation remains based on that source; we will relink if/when an official mirror returns.
|
|
19
|
+
|
|
20
|
+
## Dataset Scenarios
|
|
21
|
+
|
|
22
|
+
- **Sorted** – ascending integers, verifying best-case behavior.
|
|
23
|
+
- **Nearly Sorted (2% swaps)** – deterministic neighbor swaps introduce light disorder to expose adaptive optimizations.
|
|
24
|
+
- **Shuffled (deterministic)** – Fisher–Yates shuffle using a fixed seed for reproducibility across runs and machines.
|
|
25
|
+
|
|
26
|
+
Each benchmark sorts a fresh copy of the dataset once and reports wall-clock duration. Insertion sort is skipped for lists larger than 10,000 elements because O(n²) quickly becomes impractical; the table shows `n/a` for those entries.
|
|
27
|
+
|
|
28
|
+
Run the `IListSortingPerformanceTests.Benchmark` test inside Unity’s Test Runner to refresh the tables below. Results automatically land in the section that matches the current operating system.
|
|
29
|
+
|
|
30
|
+
## Windows (Editor/Player)
|
|
31
|
+
|
|
32
|
+
<!-- ILIST_SORT_WINDOWS_START -->
|
|
33
|
+
|
|
34
|
+
_Last updated 2025-10-26 18:00 UTC on Windows 11 (10.0.26200) 64bit_
|
|
35
|
+
|
|
36
|
+
Times are single-pass measurements in milliseconds (lower is better). `n/a` indicates the algorithm was skipped for the dataset size.
|
|
37
|
+
|
|
38
|
+
### Sorted
|
|
39
|
+
|
|
40
|
+
| List Size | Ghost | Meteor | Pattern-Defeating QuickSort | Grail | Power | Insertion |
|
|
41
|
+
| --------- | -------- | -------- | --------------------------- | -------- | -------- | --------- |
|
|
42
|
+
| 100 | 0.373 ms | 0.072 ms | 0.422 ms | 2.04 ms | 0.907 ms | 0.071 ms |
|
|
43
|
+
| 1,000 | 0.021 ms | 0.025 ms | 0.007 ms | 0.040 ms | 0.005 ms | 0.005 ms |
|
|
44
|
+
| 10,000 | 0.288 ms | 0.368 ms | 0.067 ms | 0.555 ms | 0.041 ms | 0.054 ms |
|
|
45
|
+
| 100,000 | 3.35 ms | 4.81 ms | 0.703 ms | 10.7 ms | 0.424 ms | n/a |
|
|
46
|
+
| 1,000,000 | 37.0 ms | 57.1 ms | 6.70 ms | 11.4 ms | 4.08 ms | n/a |
|
|
47
|
+
|
|
48
|
+
### Nearly Sorted (2% swaps)
|
|
49
|
+
|
|
50
|
+
| List Size | Ghost | Meteor | Pattern-Defeating QuickSort | Grail | Power | Insertion |
|
|
51
|
+
| --------- | -------- | -------- | --------------------------- | -------- | -------- | --------- |
|
|
52
|
+
| 100 | 0.002 ms | 0.002 ms | 0.007 ms | 0.145 ms | 0.053 ms | 0.001 ms |
|
|
53
|
+
| 1,000 | 0.021 ms | 0.025 ms | 0.032 ms | 0.009 ms | 0.020 ms | 0.006 ms |
|
|
54
|
+
| 10,000 | 0.279 ms | 0.355 ms | 0.383 ms | 0.072 ms | 0.223 ms | 0.057 ms |
|
|
55
|
+
| 100,000 | 3.17 ms | 4.64 ms | 4.61 ms | 0.689 ms | 3.47 ms | n/a |
|
|
56
|
+
| 1,000,000 | 37.3 ms | 57.3 ms | 53.9 ms | 7.45 ms | 44.8 ms | n/a |
|
|
57
|
+
|
|
58
|
+
### Shuffled (deterministic)
|
|
59
|
+
|
|
60
|
+
| List Size | Ghost | Meteor | Pattern-Defeating QuickSort | Grail | Power | Insertion |
|
|
61
|
+
| --------- | -------- | -------- | --------------------------- | -------- | -------- | --------- |
|
|
62
|
+
| 100 | 0.009 ms | 0.007 ms | 0.007 ms | 0.011 ms | 0.010 ms | 0.015 ms |
|
|
63
|
+
| 1,000 | 0.143 ms | 0.123 ms | 0.089 ms | 0.106 ms | 0.111 ms | 1.34 ms |
|
|
64
|
+
| 10,000 | 1.97 ms | 1.76 ms | 1.16 ms | 1.38 ms | 1.41 ms | 131 ms |
|
|
65
|
+
| 100,000 | 28.3 ms | 23.5 ms | 14.4 ms | 17.3 ms | 17.5 ms | n/a |
|
|
66
|
+
| 1,000,000 | 395 ms | 296 ms | 171 ms | 207 ms | 212 ms | n/a |
|
|
67
|
+
|
|
68
|
+
<!-- ILIST_SORT_WINDOWS_END -->
|
|
69
|
+
|
|
70
|
+
## macOS
|
|
71
|
+
|
|
72
|
+
<!-- ILIST_SORT_MACOS_START -->
|
|
73
|
+
|
|
74
|
+
Pending — run the IList sorting benchmark suite on macOS to capture results.
|
|
75
|
+
|
|
76
|
+
<!-- ILIST_SORT_MACOS_END -->
|
|
77
|
+
|
|
78
|
+
## Linux
|
|
79
|
+
|
|
80
|
+
<!-- ILIST_SORT_LINUX_START -->
|
|
81
|
+
|
|
82
|
+
Pending — run the IList sorting benchmark suite on Linux to capture results.
|
|
83
|
+
|
|
84
|
+
<!-- ILIST_SORT_LINUX_END -->
|
|
85
|
+
|
|
86
|
+
## Other Platforms
|
|
87
|
+
|
|
88
|
+
<!-- ILIST_SORT_OTHER_START -->
|
|
89
|
+
|
|
90
|
+
Pending — run the IList sorting benchmark suite on the target platform to capture results.
|
|
91
|
+
|
|
92
|
+
<!-- ILIST_SORT_OTHER_END -->
|
package/Docs/INDEX.md
CHANGED
|
@@ -139,6 +139,9 @@ Alphabetical index of all Unity Helpers features with quick links to documentati
|
|
|
139
139
|
**Fit Texture Size** - Auto-adjust texture max size to source dimensions
|
|
140
140
|
→ [Editor Tools Guide](EDITOR_TOOLS_GUIDE.md#fit-texture-size)
|
|
141
141
|
|
|
142
|
+
**FlurryBurstRandom** - Six-word ARX generator (FlurryBurst32 port)
|
|
143
|
+
→ [README - Random Generators](../README.md#random-number-generators) | [Random Performance](RANDOM_PERFORMANCE.md)
|
|
144
|
+
|
|
142
145
|
---
|
|
143
146
|
|
|
144
147
|
## G
|
|
@@ -262,6 +265,9 @@ Alphabetical index of all Unity Helpers features with quick links to documentati
|
|
|
262
265
|
**PcgRandom** - High-quality PCG random generator
|
|
263
266
|
→ [README - Random Generators](../README.md#random-number-generators) | [Random Performance](RANDOM_PERFORMANCE.md)
|
|
264
267
|
|
|
268
|
+
**PhotonSpinRandom** - SHISHUA-inspired bulk generator
|
|
269
|
+
→ [README - Random Generators](../README.md#random-number-generators) | [Random Performance](RANDOM_PERFORMANCE.md)
|
|
270
|
+
|
|
265
271
|
**Point-in-Polygon** - 2D/3D containment tests
|
|
266
272
|
→ [Math & Extensions](MATH_AND_EXTENSIONS.md#geometry)
|
|
267
273
|
|
|
@@ -306,7 +312,7 @@ Alphabetical index of all Unity Helpers features with quick links to documentati
|
|
|
306
312
|
**Random Extensions** - Random vectors, colors, weighted selection, subset sampling
|
|
307
313
|
→ [Math & Extensions](MATH_AND_EXTENSIONS.md#random-generators)
|
|
308
314
|
|
|
309
|
-
**Random Generators** -
|
|
315
|
+
**Random Generators** - 15 high-performance PRNG implementations
|
|
310
316
|
→ [README - Random Generators](../README.md#random-number-generators) | [Random Performance](RANDOM_PERFORMANCE.md)
|
|
311
317
|
|
|
312
318
|
**Range<T>** - Inclusive/exclusive range helper
|
|
@@ -352,6 +358,9 @@ Alphabetical index of all Unity Helpers features with quick links to documentati
|
|
|
352
358
|
**Singletons** - Runtime and ScriptableObject singleton patterns
|
|
353
359
|
→ [Singletons Guide](SINGLETONS.md) | [README](../README.md#singleton-utilities-odin-compatible)
|
|
354
360
|
|
|
361
|
+
**StormDropRandom** - Large-buffer ARX generator
|
|
362
|
+
→ [README - Random Generators](../README.md#random-number-generators) | [Random Performance](RANDOM_PERFORMANCE.md)
|
|
363
|
+
|
|
355
364
|
**Sparse Set** - O(1) membership with dense iteration
|
|
356
365
|
→ [Data Structures](DATA_STRUCTURES.md#sparse-set) | [README](../README.md#data-structures)
|
|
357
366
|
|
|
@@ -82,14 +82,14 @@
|
|
|
82
82
|
<!-- pip patterns 1,2,5,6 -->
|
|
83
83
|
<circle cx="392" cy="267" r="2"/>
|
|
84
84
|
<circle cx="420" cy="262" r="2"/>
|
|
85
|
-
<circle cx="424" cy="
|
|
85
|
+
<circle cx="424" cy="272" r="2"/>
|
|
86
86
|
<circle cx="450" cy="260" r="2"/>
|
|
87
|
-
<circle cx="
|
|
88
|
-
<circle cx="
|
|
89
|
-
<circle cx="
|
|
90
|
-
<circle cx="
|
|
91
|
-
<circle cx="
|
|
92
|
-
<circle cx="
|
|
87
|
+
<circle cx="453" cy="266" r="2"/>
|
|
88
|
+
<circle cx="456" cy="272" r="2"/>
|
|
89
|
+
<circle cx="478" cy="262" r="2"/>
|
|
90
|
+
<circle cx="488" cy="262" r="2"/>
|
|
91
|
+
<circle cx="478" cy="272" r="2"/>
|
|
92
|
+
<circle cx="488" cy="272" r="2"/>
|
|
93
93
|
</g>
|
|
94
94
|
<g font-family="Verdana,Arial,sans-serif" font-size="10" fill="#9fb3c8">
|
|
95
95
|
<text x="390" y="315">discrete outcomes</text>
|
|
@@ -71,7 +71,7 @@ Threading
|
|
|
71
71
|
|
|
72
72
|
Visual
|
|
73
73
|
|
|
74
|
-

|
|
75
75
|
|
|
76
76
|
This document contains performance benchmarks for the various random number generators included in Unity Helpers.
|
|
77
77
|
|
|
@@ -81,18 +81,21 @@ This document contains performance benchmarks for the various random number gene
|
|
|
81
81
|
|
|
82
82
|
| Random | NextBool | Next | NextUInt | NextFloat | NextDouble | NextUint - Range | NextInt - Range |
|
|
83
83
|
| --------------------------- | ----------- | ----------- | ------------- | ----------- | ----------- | ---------------- | --------------- |
|
|
84
|
-
| DotNetRandom |
|
|
85
|
-
| LinearCongruentialGenerator |
|
|
86
|
-
| IllusionFlow |
|
|
87
|
-
| PcgRandom |
|
|
88
|
-
| RomuDuo |
|
|
89
|
-
| SplitMix64 |
|
|
90
|
-
|
|
|
91
|
-
|
|
|
92
|
-
|
|
|
93
|
-
|
|
|
94
|
-
|
|
|
95
|
-
|
|
|
84
|
+
| DotNetRandom | 535,000,000 | 54,400,000 | 56,700,000 | 45,200,000 | 28,200,000 | 52,200,000 | 51,800,000 |
|
|
85
|
+
| LinearCongruentialGenerator | 798,300,000 | 823,200,000 | 1,329,100,000 | 179,900,000 | 402,000,000 | 577,800,000 | 493,300,000 |
|
|
86
|
+
| IllusionFlow | 778,000,000 | 662,100,000 | 895,100,000 | 178,000,000 | 331,100,000 | 444,000,000 | 384,900,000 |
|
|
87
|
+
| PcgRandom | 762,500,000 | 668,400,000 | 892,700,000 | 179,700,000 | 345,200,000 | 450,000,000 | 400,200,000 |
|
|
88
|
+
| RomuDuo | 758,600,000 | 579,300,000 | 767,300,000 | 167,200,000 | 255,900,000 | 446,500,000 | 397,400,000 |
|
|
89
|
+
| SplitMix64 | 800,900,000 | 670,400,000 | 943,700,000 | 179,000,000 | 346,600,000 | 473,300,000 | 432,800,000 |
|
|
90
|
+
| FlurryBurstRandom | 762,800,000 | 603,800,000 | 863,700,000 | 183,000,000 | 305,200,000 | 456,400,000 | 412,400,000 |
|
|
91
|
+
| SquirrelRandom | 759,700,000 | 393,600,000 | 413,500,000 | 172,300,000 | 187,800,000 | 329,600,000 | 307,100,000 |
|
|
92
|
+
| SystemRandom | 138,400,000 | 144,300,000 | 63,200,000 | 127,600,000 | 135,800,000 | 59,600,000 | 60,400,000 |
|
|
93
|
+
| UnityRandom | 655,300,000 | 85,000,000 | 87,800,000 | 62,200,000 | 41,500,000 | 81,500,000 | 82,400,000 |
|
|
94
|
+
| WyRandom | 758,600,000 | 390,600,000 | 457,100,000 | 166,800,000 | 191,100,000 | 293,600,000 | 274,700,000 |
|
|
95
|
+
| XorShiftRandom | 766,300,000 | 554,600,000 | 586,100,000 | 181,100,000 | 259,100,000 | 443,300,000 | 393,600,000 |
|
|
96
|
+
| XoroShiroRandom | 766,200,000 | 522,900,000 | 714,100,000 | 167,200,000 | 243,300,000 | 428,400,000 | 381,000,000 |
|
|
97
|
+
| PhotonSpinRandom | 677,900,000 | 232,100,000 | 258,000,000 | 116,900,000 | 114,800,000 | 209,700,000 | 201,100,000 |
|
|
98
|
+
| StormDropRandom | 758,100,000 | 538,100,000 | 698,600,000 | 184,100,000 | 271,800,000 | 406,300,000 | 365,900,000 |
|
|
96
99
|
|
|
97
100
|
<!-- RANDOM_BENCHMARKS_END -->
|
|
98
101
|
|
|
@@ -110,8 +113,8 @@ This document contains performance benchmarks for the various random number gene
|
|
|
110
113
|
|
|
111
114
|
Based on the benchmarks:
|
|
112
115
|
|
|
113
|
-
- **For general use**: `IllusionFlow` (via `PRNG.Instance`) - Great balance of speed and quality
|
|
114
|
-
- **For maximum speed**: `
|
|
116
|
+
- **For general use**: `IllusionFlow` (via `PRNG.Instance`) or `PCG` - Great balance of speed and quality
|
|
117
|
+
- **For maximum speed**: `LinearCongruentialGenerator` - Fastest overall (but not recommended for statistical quality)
|
|
115
118
|
- **For compatibility**: `DotNetRandom` - Uses .NET's built-in Random
|
|
116
119
|
- **Avoid for performance**: `UnityRandom` - Significantly slower than alternatives
|
|
117
120
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
Visual
|
|
9
9
|
|
|
10
|
-

|
|
11
11
|
|
|
12
12
|
ReflectionHelpers is a set of utilities for high‑performance reflection in Unity projects. It generates and caches delegates to access fields and properties, call methods and constructors, and quickly create common collections — with safe fallbacks when dynamic IL isn’t available.
|
|
13
13
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Visual
|
|
4
4
|
|
|
5
|
-

|
|
6
6
|
|
|
7
7
|
Auto-wire components in your hierarchy without `GetComponent` boilerplate. These attributes make common relationships explicit, robust, and easy to maintain.
|
|
8
8
|
|
|
@@ -10,7 +10,14 @@ Auto-wire components in your hierarchy without `GetComponent` boilerplate. These
|
|
|
10
10
|
- `ParentComponent` — up the transform hierarchy
|
|
11
11
|
- `ChildComponent` — down the transform hierarchy (breadth-first)
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
**Collection Type Support:** Each attribute works with:
|
|
14
|
+
|
|
15
|
+
- Single fields (e.g., `Transform`)
|
|
16
|
+
- Arrays (e.g., `Collider2D[]`)
|
|
17
|
+
- **Lists** (e.g., `List<Rigidbody2D>`)
|
|
18
|
+
- **HashSets** (e.g., `HashSet<Renderer>`)
|
|
19
|
+
|
|
20
|
+
All attributes support optional assignment, filters (tag/name), depth limits, max results, and interface/base-type resolution.
|
|
14
21
|
|
|
15
22
|
Having issues? Jump to Troubleshooting: see [Troubleshooting](#troubleshooting).
|
|
16
23
|
|
|
@@ -197,7 +204,8 @@ Examples:
|
|
|
197
204
|
[SiblingComponent] private Animator animator; // required by default
|
|
198
205
|
[SiblingComponent(Optional = true)] private Rigidbody2D rb; // optional
|
|
199
206
|
[SiblingComponent(TagFilter = "Visual", NameFilter = "Sprite")] private Component[] visuals;
|
|
200
|
-
[SiblingComponent(MaxCount = 2)] private List<Collider2D> firstTwo;
|
|
207
|
+
[SiblingComponent(MaxCount = 2)] private List<Collider2D> firstTwo; // List<T> supported
|
|
208
|
+
[SiblingComponent] private HashSet<Renderer> allRenderers; // HashSet<T> supported
|
|
201
209
|
```
|
|
202
210
|
|
|
203
211
|
### ParentComponent
|
|
@@ -232,7 +240,10 @@ Examples:
|
|
|
232
240
|
// First matching descendant with a tag
|
|
233
241
|
[ChildComponent(OnlyDescendants = true, TagFilter = "Weapon")] private Collider2D weaponCollider;
|
|
234
242
|
|
|
235
|
-
// Gather into a
|
|
243
|
+
// Gather into a List (preserves insertion order)
|
|
244
|
+
[ChildComponent(OnlyDescendants = true)] private List<MeshRenderer> childRenderers;
|
|
245
|
+
|
|
246
|
+
// Gather into a HashSet (unique results, no duplicates) and limit count
|
|
236
247
|
[ChildComponent(OnlyDescendants = true, MaxCount = 10)] private HashSet<Rigidbody2D> firstTenRigidbodies;
|
|
237
248
|
```
|
|
238
249
|
|
|
@@ -261,6 +272,39 @@ Examples:
|
|
|
261
272
|
- `AllowInterfaces` (default: true)
|
|
262
273
|
- If `true`, can assign by interface or base type; set `false` to restrict to concrete types
|
|
263
274
|
|
|
275
|
+
### Choosing the Right Collection Type
|
|
276
|
+
|
|
277
|
+
**Use Arrays (`T[]`)** when:
|
|
278
|
+
|
|
279
|
+
- Collection size is fixed or rarely changes
|
|
280
|
+
- Need the smallest memory footprint
|
|
281
|
+
- Interoperating with APIs that require arrays
|
|
282
|
+
|
|
283
|
+
**Use Lists (`List<T>`)** when:
|
|
284
|
+
|
|
285
|
+
- Need insertion order preserved
|
|
286
|
+
- Plan to add/remove elements after assignment
|
|
287
|
+
- Want indexed access with `[]` operator
|
|
288
|
+
- Need compatibility with most LINQ operations
|
|
289
|
+
|
|
290
|
+
**Use HashSets (`HashSet<T>`)** when:
|
|
291
|
+
|
|
292
|
+
- Need guaranteed uniqueness (no duplicates)
|
|
293
|
+
- Performing frequent membership tests (`Contains()`)
|
|
294
|
+
- Order doesn't matter
|
|
295
|
+
- Want O(1) lookup performance
|
|
296
|
+
|
|
297
|
+
```csharp
|
|
298
|
+
// Arrays: Fixed size, minimal overhead
|
|
299
|
+
[ChildComponent] private Collider2D[] colliders;
|
|
300
|
+
|
|
301
|
+
// Lists: Dynamic, ordered, index-based access
|
|
302
|
+
[ChildComponent] private List<Renderer> renderers;
|
|
303
|
+
|
|
304
|
+
// HashSets: Unique, fast lookups, unordered
|
|
305
|
+
[ChildComponent] private HashSet<AudioSource> audioSources;
|
|
306
|
+
```
|
|
307
|
+
|
|
264
308
|
## Recipes
|
|
265
309
|
|
|
266
310
|
- UI hierarchy references
|
|
@@ -564,7 +608,8 @@ Common pitfalls and how to avoid them
|
|
|
564
608
|
|
|
565
609
|
**DI Integration Samples:**
|
|
566
610
|
|
|
567
|
-
- [VContainer Integration](Samples~/DI%20-%20VContainer/README.md) - Complete VContainer setup guide
|
|
568
|
-
- [Zenject Integration](Samples~/DI%20-%20Zenject/README.md) - Complete Zenject setup guide
|
|
611
|
+
- [VContainer Integration](../Samples~/DI%20-%20VContainer/README.md) - Complete VContainer setup guide
|
|
612
|
+
- [Zenject Integration](../Samples~/DI%20-%20Zenject/README.md) - Complete Zenject setup guide
|
|
613
|
+
- [Reflex Integration](../Samples~/DI%20-%20Reflex/README.md) - Complete Reflex setup guide
|
|
569
614
|
|
|
570
615
|
**Need help?** [Open an issue](https://github.com/wallstop/unity-helpers/issues) | [Troubleshooting](#troubleshooting)
|
package/Docs/SERIALIZATION.md
CHANGED
package/Docs/SINGLETONS.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Visual
|
|
4
4
|
|
|
5
|
-

|
|
6
6
|
|
|
7
7
|
This package includes two lightweight, production‑ready singleton helpers that make global access patterns safe, consistent, and testable:
|
|
8
8
|
|
|
@@ -403,7 +403,7 @@ Use alternatives when one or more of these apply:
|
|
|
403
403
|
|
|
404
404
|
Use this chart to pick an approach based on constraints:
|
|
405
405
|
|
|
406
|
-

|
|
407
407
|
|
|
408
408
|
<a id="troubleshooting"></a>
|
|
409
409
|
|
|
@@ -188,7 +188,7 @@ See [Buffering Pattern](../README.md#buffering-pattern) for the complete guide a
|
|
|
188
188
|
- Pros: Simple structure; predictable performance; incremental updates straightforward.
|
|
189
189
|
- Cons: Data hotspots deepen local trees; nearest neighbors slower than KDTree.
|
|
190
190
|
|
|
191
|
-
Diagram: 
|
|
192
192
|
|
|
193
193
|
### KDTree2D
|
|
194
194
|
|
|
@@ -197,7 +197,7 @@ Diagram: 
|
|
|
197
197
|
- Pros: Strong NN performance; balanced variant gives consistent query time.
|
|
198
198
|
- Cons: Costly to maintain under heavy churn; unbalanced variant can degrade.
|
|
199
199
|
|
|
200
|
-
Diagram: 
|
|
201
201
|
|
|
202
202
|
### RTree2D
|
|
203
203
|
|
|
@@ -206,7 +206,7 @@ Diagram: 
|
|
|
206
206
|
- Pros: Great for large bounds queries; matches bounds semantics.
|
|
207
207
|
- Cons: Overlapping MBRs can increase node visits; not optimal for point NN.
|
|
208
208
|
|
|
209
|
-
Diagram: 
|
|
210
210
|
|
|
211
211
|
## Choosing a Structure
|
|
212
212
|
|
|
@@ -178,7 +178,7 @@ See [Buffering Pattern](../README.md#buffering-pattern) for the complete guide a
|
|
|
178
178
|
- Pros: Good spatial locality; intuitive partitioning; balanced performance.
|
|
179
179
|
- Cons: Nearest neighbors slower than KDTree on pure point data.
|
|
180
180
|
|
|
181
|
-

|
|
182
182
|
|
|
183
183
|
### KDTree3D
|
|
184
184
|
|
|
@@ -187,7 +187,7 @@ See [Buffering Pattern](../README.md#buffering-pattern) for the complete guide a
|
|
|
187
187
|
- Pros: Strong NN performance; balanced variant gives consistent query time.
|
|
188
188
|
- Cons: Costly to maintain under heavy churn; unbalanced variant can degrade.
|
|
189
189
|
|
|
190
|
-

|
|
191
191
|
|
|
192
192
|
### RTree3D
|
|
193
193
|
|
|
@@ -196,7 +196,7 @@ See [Buffering Pattern](../README.md#buffering-pattern) for the complete guide a
|
|
|
196
196
|
- Pros: Great for large bounds queries; matches volumetric semantics.
|
|
197
197
|
- Cons: Overlapping boxes can increase node visits; not optimal for point NN.
|
|
198
198
|
|
|
199
|
-

|
|
200
200
|
|
|
201
201
|
## Choosing a Structure
|
|
202
202
|
|