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
|
@@ -2,6 +2,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Tags
|
|
|
2
2
|
{
|
|
3
3
|
using System.Collections;
|
|
4
4
|
using System.Collections.Generic;
|
|
5
|
+
using System.Text.RegularExpressions;
|
|
5
6
|
using NUnit.Framework;
|
|
6
7
|
using UnityEngine;
|
|
7
8
|
using UnityEngine.TestTools;
|
|
@@ -16,6 +17,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Tags
|
|
|
16
17
|
{
|
|
17
18
|
ResetEffectHandleId();
|
|
18
19
|
RecordingCosmeticComponent.ResetCounters();
|
|
20
|
+
RecordingEffectBehavior.Reset();
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
[UnityTest]
|
|
@@ -276,6 +278,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Tags
|
|
|
276
278
|
e =>
|
|
277
279
|
{
|
|
278
280
|
e.durationType = ModifierDurationType.Infinite;
|
|
281
|
+
e.stackingMode = EffectStackingMode.Stack;
|
|
279
282
|
}
|
|
280
283
|
);
|
|
281
284
|
|
|
@@ -291,6 +294,158 @@ namespace WallstopStudios.UnityHelpers.Tests.Tags
|
|
|
291
294
|
Assert.AreEqual(0, handler.GetEffectStackCount(effect));
|
|
292
295
|
}
|
|
293
296
|
|
|
297
|
+
[UnityTest]
|
|
298
|
+
public IEnumerator StackingModeIgnoreReturnsExistingHandle()
|
|
299
|
+
{
|
|
300
|
+
(
|
|
301
|
+
GameObject entity,
|
|
302
|
+
EffectHandler handler,
|
|
303
|
+
TestAttributesComponent attributes,
|
|
304
|
+
TagHandler tags
|
|
305
|
+
) = CreateEntity();
|
|
306
|
+
yield return null;
|
|
307
|
+
|
|
308
|
+
AttributeEffect effect = CreateEffect(
|
|
309
|
+
"Ignore",
|
|
310
|
+
e =>
|
|
311
|
+
{
|
|
312
|
+
e.durationType = ModifierDurationType.Infinite;
|
|
313
|
+
e.stackingMode = EffectStackingMode.Ignore;
|
|
314
|
+
e.modifications.Add(
|
|
315
|
+
new AttributeModification
|
|
316
|
+
{
|
|
317
|
+
attribute = nameof(TestAttributesComponent.health),
|
|
318
|
+
action = ModificationAction.Addition,
|
|
319
|
+
value = 5f,
|
|
320
|
+
}
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
);
|
|
324
|
+
|
|
325
|
+
EffectHandle first = handler.ApplyEffect(effect).Value;
|
|
326
|
+
float afterFirst = attributes.health.CurrentValue;
|
|
327
|
+
|
|
328
|
+
EffectHandle? second = handler.ApplyEffect(effect);
|
|
329
|
+
Assert.IsTrue(second.HasValue);
|
|
330
|
+
Assert.AreEqual(first, second.Value);
|
|
331
|
+
Assert.AreEqual(afterFirst, attributes.health.CurrentValue);
|
|
332
|
+
|
|
333
|
+
handler.RemoveEffect(first);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
[UnityTest]
|
|
337
|
+
public IEnumerator RefreshModeWithoutResetDurationPreservesTimer()
|
|
338
|
+
{
|
|
339
|
+
(
|
|
340
|
+
GameObject entity,
|
|
341
|
+
EffectHandler handler,
|
|
342
|
+
TestAttributesComponent attributes,
|
|
343
|
+
TagHandler tags
|
|
344
|
+
) = CreateEntity();
|
|
345
|
+
yield return null;
|
|
346
|
+
|
|
347
|
+
AttributeEffect effect = CreateEffect(
|
|
348
|
+
"RefreshNoReset",
|
|
349
|
+
e =>
|
|
350
|
+
{
|
|
351
|
+
e.duration = 0.3f;
|
|
352
|
+
e.stackingMode = EffectStackingMode.Refresh;
|
|
353
|
+
e.resetDurationOnReapplication = false;
|
|
354
|
+
}
|
|
355
|
+
);
|
|
356
|
+
|
|
357
|
+
EffectHandle handle = handler.ApplyEffect(effect).Value;
|
|
358
|
+
yield return new WaitForSeconds(0.05f);
|
|
359
|
+
Assert.IsTrue(handler.TryGetRemainingDuration(handle, out float beforeReapply));
|
|
360
|
+
|
|
361
|
+
EffectHandle? reapplied = handler.ApplyEffect(effect);
|
|
362
|
+
Assert.IsTrue(reapplied.HasValue);
|
|
363
|
+
Assert.AreEqual(handle, reapplied.Value);
|
|
364
|
+
|
|
365
|
+
Assert.IsTrue(handler.TryGetRemainingDuration(handle, out float afterReapply));
|
|
366
|
+
Assert.LessOrEqual(afterReapply, beforeReapply + 0.01f);
|
|
367
|
+
|
|
368
|
+
handler.RemoveEffect(handle);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
[UnityTest]
|
|
372
|
+
public IEnumerator CustomStackGroupStackAcrossAssets()
|
|
373
|
+
{
|
|
374
|
+
(
|
|
375
|
+
GameObject entity,
|
|
376
|
+
EffectHandler handler,
|
|
377
|
+
TestAttributesComponent attributes,
|
|
378
|
+
TagHandler tags
|
|
379
|
+
) = CreateEntity();
|
|
380
|
+
yield return null;
|
|
381
|
+
|
|
382
|
+
AttributeEffect effectA = CreateEffect(
|
|
383
|
+
"GroupA",
|
|
384
|
+
e =>
|
|
385
|
+
{
|
|
386
|
+
e.durationType = ModifierDurationType.Infinite;
|
|
387
|
+
e.stackGroup = EffectStackGroup.CustomKey;
|
|
388
|
+
e.stackGroupKey = "shared";
|
|
389
|
+
e.stackingMode = EffectStackingMode.Stack;
|
|
390
|
+
}
|
|
391
|
+
);
|
|
392
|
+
|
|
393
|
+
AttributeEffect effectB = CreateEffect(
|
|
394
|
+
"GroupB",
|
|
395
|
+
e =>
|
|
396
|
+
{
|
|
397
|
+
e.durationType = ModifierDurationType.Infinite;
|
|
398
|
+
e.stackGroup = EffectStackGroup.CustomKey;
|
|
399
|
+
e.stackGroupKey = "shared";
|
|
400
|
+
e.stackingMode = EffectStackingMode.Stack;
|
|
401
|
+
}
|
|
402
|
+
);
|
|
403
|
+
|
|
404
|
+
EffectHandle a1 = handler.ApplyEffect(effectA).Value;
|
|
405
|
+
EffectHandle b1 = handler.ApplyEffect(effectB).Value;
|
|
406
|
+
EffectHandle a2 = handler.ApplyEffect(effectA).Value;
|
|
407
|
+
|
|
408
|
+
List<EffectHandle> active = handler.GetActiveEffects();
|
|
409
|
+
Assert.AreEqual(3, active.Count);
|
|
410
|
+
Assert.AreEqual(2, handler.GetEffectStackCount(effectA));
|
|
411
|
+
Assert.AreEqual(1, handler.GetEffectStackCount(effectB));
|
|
412
|
+
|
|
413
|
+
handler.RemoveAllEffects();
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
[UnityTest]
|
|
417
|
+
public IEnumerator StackedTagsPersistUntilFinalStackRemoved()
|
|
418
|
+
{
|
|
419
|
+
(
|
|
420
|
+
GameObject entity,
|
|
421
|
+
EffectHandler handler,
|
|
422
|
+
TestAttributesComponent attributes,
|
|
423
|
+
TagHandler tags
|
|
424
|
+
) = CreateEntity();
|
|
425
|
+
yield return null;
|
|
426
|
+
|
|
427
|
+
AttributeEffect effect = CreateEffect(
|
|
428
|
+
"Tagged",
|
|
429
|
+
e =>
|
|
430
|
+
{
|
|
431
|
+
e.durationType = ModifierDurationType.Infinite;
|
|
432
|
+
e.stackingMode = EffectStackingMode.Stack;
|
|
433
|
+
e.effectTags.Add("Shielded");
|
|
434
|
+
}
|
|
435
|
+
);
|
|
436
|
+
|
|
437
|
+
EffectHandle first = handler.ApplyEffect(effect).Value;
|
|
438
|
+
EffectHandle second = handler.ApplyEffect(effect).Value;
|
|
439
|
+
|
|
440
|
+
Assert.IsTrue(tags.HasTag("Shielded"));
|
|
441
|
+
|
|
442
|
+
handler.RemoveEffect(first);
|
|
443
|
+
Assert.IsTrue(tags.HasTag("Shielded"));
|
|
444
|
+
|
|
445
|
+
handler.RemoveEffect(second);
|
|
446
|
+
Assert.IsFalse(tags.HasTag("Shielded"));
|
|
447
|
+
}
|
|
448
|
+
|
|
294
449
|
[UnityTest]
|
|
295
450
|
public IEnumerator GetActiveEffectsPopulatesBuffer()
|
|
296
451
|
{
|
|
@@ -307,6 +462,7 @@ namespace WallstopStudios.UnityHelpers.Tests.Tags
|
|
|
307
462
|
e =>
|
|
308
463
|
{
|
|
309
464
|
e.durationType = ModifierDurationType.Infinite;
|
|
465
|
+
e.stackingMode = EffectStackingMode.Stack;
|
|
310
466
|
}
|
|
311
467
|
);
|
|
312
468
|
|
|
@@ -325,6 +481,168 @@ namespace WallstopStudios.UnityHelpers.Tests.Tags
|
|
|
325
481
|
handler.RemoveEffect(second);
|
|
326
482
|
}
|
|
327
483
|
|
|
484
|
+
[UnityTest]
|
|
485
|
+
public IEnumerator PeriodicEffectHonorsInitialDelayAndMaxTicks()
|
|
486
|
+
{
|
|
487
|
+
(
|
|
488
|
+
GameObject entity,
|
|
489
|
+
EffectHandler handler,
|
|
490
|
+
TestAttributesComponent attributes,
|
|
491
|
+
TagHandler tags
|
|
492
|
+
) = CreateEntity();
|
|
493
|
+
yield return null;
|
|
494
|
+
|
|
495
|
+
AttributeEffect effect = CreateEffect(
|
|
496
|
+
"PeriodicLimited",
|
|
497
|
+
e =>
|
|
498
|
+
{
|
|
499
|
+
e.durationType = ModifierDurationType.Infinite;
|
|
500
|
+
PeriodicEffectDefinition definition = new()
|
|
501
|
+
{
|
|
502
|
+
initialDelay = 0.05f,
|
|
503
|
+
interval = 0.05f,
|
|
504
|
+
maxTicks = 2,
|
|
505
|
+
};
|
|
506
|
+
definition.modifications.Add(
|
|
507
|
+
new AttributeModification
|
|
508
|
+
{
|
|
509
|
+
attribute = nameof(TestAttributesComponent.health),
|
|
510
|
+
action = ModificationAction.Addition,
|
|
511
|
+
value = -10f,
|
|
512
|
+
}
|
|
513
|
+
);
|
|
514
|
+
e.periodicEffects.Add(definition);
|
|
515
|
+
}
|
|
516
|
+
);
|
|
517
|
+
|
|
518
|
+
EffectHandle handle = handler.ApplyEffect(effect).Value;
|
|
519
|
+
yield return null;
|
|
520
|
+
Assert.AreEqual(100f, attributes.health.CurrentValue, 0.01f);
|
|
521
|
+
|
|
522
|
+
yield return new WaitForSeconds(0.03f);
|
|
523
|
+
Assert.AreEqual(100f, attributes.health.CurrentValue, 0.01f);
|
|
524
|
+
|
|
525
|
+
yield return new WaitForSeconds(0.06f);
|
|
526
|
+
Assert.AreEqual(90f, attributes.health.CurrentValue, 0.01f);
|
|
527
|
+
|
|
528
|
+
yield return new WaitForSeconds(0.06f);
|
|
529
|
+
Assert.AreEqual(80f, attributes.health.CurrentValue, 0.01f);
|
|
530
|
+
|
|
531
|
+
yield return new WaitForSeconds(0.06f);
|
|
532
|
+
Assert.AreEqual(80f, attributes.health.CurrentValue, 0.01f);
|
|
533
|
+
|
|
534
|
+
handler.RemoveEffect(handle);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
[UnityTest]
|
|
538
|
+
public IEnumerator PeriodicEffectUnlimitedTicksStopOnRemoval()
|
|
539
|
+
{
|
|
540
|
+
(
|
|
541
|
+
GameObject entity,
|
|
542
|
+
EffectHandler handler,
|
|
543
|
+
TestAttributesComponent attributes,
|
|
544
|
+
TagHandler tags
|
|
545
|
+
) = CreateEntity();
|
|
546
|
+
yield return null;
|
|
547
|
+
|
|
548
|
+
AttributeEffect effect = CreateEffect(
|
|
549
|
+
"PeriodicUnlimited",
|
|
550
|
+
e =>
|
|
551
|
+
{
|
|
552
|
+
e.durationType = ModifierDurationType.Infinite;
|
|
553
|
+
PeriodicEffectDefinition definition = new() { interval = 0.05f, maxTicks = 0 };
|
|
554
|
+
definition.modifications.Add(
|
|
555
|
+
new AttributeModification
|
|
556
|
+
{
|
|
557
|
+
attribute = nameof(TestAttributesComponent.health),
|
|
558
|
+
action = ModificationAction.Addition,
|
|
559
|
+
value = -5f,
|
|
560
|
+
}
|
|
561
|
+
);
|
|
562
|
+
e.periodicEffects.Add(definition);
|
|
563
|
+
}
|
|
564
|
+
);
|
|
565
|
+
|
|
566
|
+
EffectHandle handle = handler.ApplyEffect(effect).Value;
|
|
567
|
+
yield return new WaitForSeconds(0.16f);
|
|
568
|
+
float afterTicks = attributes.health.CurrentValue;
|
|
569
|
+
Assert.Less(afterTicks, 100f);
|
|
570
|
+
|
|
571
|
+
handler.RemoveEffect(handle);
|
|
572
|
+
float afterRemoval = attributes.health.CurrentValue;
|
|
573
|
+
yield return new WaitForSeconds(0.1f);
|
|
574
|
+
Assert.AreEqual(afterRemoval, attributes.health.CurrentValue, 0.01f);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
[UnityTest]
|
|
578
|
+
public IEnumerator MultiplePeriodicDefinitionsAffectAttributesIndependently()
|
|
579
|
+
{
|
|
580
|
+
(
|
|
581
|
+
GameObject entity,
|
|
582
|
+
EffectHandler handler,
|
|
583
|
+
TestAttributesComponent attributes,
|
|
584
|
+
TagHandler tags
|
|
585
|
+
) = CreateEntity();
|
|
586
|
+
yield return null;
|
|
587
|
+
|
|
588
|
+
AttributeEffect effect = CreateEffect(
|
|
589
|
+
"PeriodicMulti",
|
|
590
|
+
e =>
|
|
591
|
+
{
|
|
592
|
+
e.durationType = ModifierDurationType.Infinite;
|
|
593
|
+
|
|
594
|
+
PeriodicEffectDefinition damage = new()
|
|
595
|
+
{
|
|
596
|
+
initialDelay = 0.05f,
|
|
597
|
+
interval = 0.05f,
|
|
598
|
+
maxTicks = 2,
|
|
599
|
+
};
|
|
600
|
+
damage.modifications.Add(
|
|
601
|
+
new AttributeModification
|
|
602
|
+
{
|
|
603
|
+
attribute = nameof(TestAttributesComponent.health),
|
|
604
|
+
action = ModificationAction.Addition,
|
|
605
|
+
value = -5f,
|
|
606
|
+
}
|
|
607
|
+
);
|
|
608
|
+
|
|
609
|
+
PeriodicEffectDefinition armorGain = new()
|
|
610
|
+
{
|
|
611
|
+
initialDelay = 0.02f,
|
|
612
|
+
interval = 0.1f,
|
|
613
|
+
maxTicks = 3,
|
|
614
|
+
};
|
|
615
|
+
armorGain.modifications.Add(
|
|
616
|
+
new AttributeModification
|
|
617
|
+
{
|
|
618
|
+
attribute = nameof(TestAttributesComponent.armor),
|
|
619
|
+
action = ModificationAction.Addition,
|
|
620
|
+
value = 1f,
|
|
621
|
+
}
|
|
622
|
+
);
|
|
623
|
+
|
|
624
|
+
e.periodicEffects.Add(damage);
|
|
625
|
+
e.periodicEffects.Add(armorGain);
|
|
626
|
+
}
|
|
627
|
+
);
|
|
628
|
+
|
|
629
|
+
EffectHandle handle = handler.ApplyEffect(effect).Value;
|
|
630
|
+
|
|
631
|
+
yield return new WaitForSeconds(0.06f);
|
|
632
|
+
Assert.AreEqual(95f, attributes.health.CurrentValue, 0.01f);
|
|
633
|
+
Assert.AreEqual(51f, attributes.armor.CurrentValue, 0.01f);
|
|
634
|
+
|
|
635
|
+
yield return new WaitForSeconds(0.1f);
|
|
636
|
+
Assert.AreEqual(90f, attributes.health.CurrentValue, 0.01f);
|
|
637
|
+
Assert.AreEqual(52f, attributes.armor.CurrentValue, 0.01f);
|
|
638
|
+
|
|
639
|
+
yield return new WaitForSeconds(0.2f);
|
|
640
|
+
Assert.AreEqual(90f, attributes.health.CurrentValue, 0.01f);
|
|
641
|
+
Assert.AreEqual(53f, attributes.armor.CurrentValue, 0.01f);
|
|
642
|
+
|
|
643
|
+
handler.RemoveEffect(handle);
|
|
644
|
+
}
|
|
645
|
+
|
|
328
646
|
[UnityTest]
|
|
329
647
|
public IEnumerator TryGetRemainingDurationReportsTime()
|
|
330
648
|
{
|
|
@@ -429,6 +747,306 @@ namespace WallstopStudios.UnityHelpers.Tests.Tags
|
|
|
429
747
|
handler.RemoveEffect(handle);
|
|
430
748
|
}
|
|
431
749
|
|
|
750
|
+
[UnityTest]
|
|
751
|
+
public IEnumerator PeriodicEffectAppliesTicksAndStops()
|
|
752
|
+
{
|
|
753
|
+
(
|
|
754
|
+
GameObject entity,
|
|
755
|
+
EffectHandler handler,
|
|
756
|
+
TestAttributesComponent attributes,
|
|
757
|
+
TagHandler tags
|
|
758
|
+
) = CreateEntity();
|
|
759
|
+
yield return null;
|
|
760
|
+
|
|
761
|
+
AttributeEffect effect = CreateEffect(
|
|
762
|
+
"Periodic",
|
|
763
|
+
e =>
|
|
764
|
+
{
|
|
765
|
+
e.durationType = ModifierDurationType.Infinite;
|
|
766
|
+
PeriodicEffectDefinition periodic = new() { interval = 0.1f, maxTicks = 3 };
|
|
767
|
+
periodic.modifications.Add(
|
|
768
|
+
new AttributeModification
|
|
769
|
+
{
|
|
770
|
+
attribute = nameof(TestAttributesComponent.health),
|
|
771
|
+
action = ModificationAction.Addition,
|
|
772
|
+
value = -10f,
|
|
773
|
+
}
|
|
774
|
+
);
|
|
775
|
+
e.periodicEffects.Add(periodic);
|
|
776
|
+
}
|
|
777
|
+
);
|
|
778
|
+
|
|
779
|
+
EffectHandle handle = handler.ApplyEffect(effect).Value;
|
|
780
|
+
yield return new WaitForSeconds(0.35f);
|
|
781
|
+
Assert.AreEqual(70f, attributes.health.CurrentValue, 0.01f);
|
|
782
|
+
|
|
783
|
+
yield return new WaitForSeconds(0.2f);
|
|
784
|
+
handler.RemoveEffect(handle);
|
|
785
|
+
Assert.AreEqual(70f, attributes.health.CurrentValue, 0.01f);
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
[UnityTest]
|
|
789
|
+
public IEnumerator EffectBehaviorReceivesCallbacks()
|
|
790
|
+
{
|
|
791
|
+
(
|
|
792
|
+
GameObject entity,
|
|
793
|
+
EffectHandler handler,
|
|
794
|
+
TestAttributesComponent attributes,
|
|
795
|
+
TagHandler tags
|
|
796
|
+
) = CreateEntity();
|
|
797
|
+
yield return null;
|
|
798
|
+
|
|
799
|
+
AttributeEffect effect = CreateEffect(
|
|
800
|
+
"Behavior",
|
|
801
|
+
e =>
|
|
802
|
+
{
|
|
803
|
+
e.duration = 0.25f;
|
|
804
|
+
e.periodicEffects.Add(
|
|
805
|
+
new PeriodicEffectDefinition { interval = 0.05f, maxTicks = 2 }
|
|
806
|
+
);
|
|
807
|
+
}
|
|
808
|
+
);
|
|
809
|
+
|
|
810
|
+
RecordingEffectBehavior behavior = Track(
|
|
811
|
+
ScriptableObject.CreateInstance<RecordingEffectBehavior>()
|
|
812
|
+
);
|
|
813
|
+
effect.behaviors.Add(behavior);
|
|
814
|
+
|
|
815
|
+
EffectHandle handle = handler.ApplyEffect(effect).Value;
|
|
816
|
+
Assert.AreEqual(1, RecordingEffectBehavior.ApplyCount);
|
|
817
|
+
|
|
818
|
+
yield return null;
|
|
819
|
+
Assert.Greater(RecordingEffectBehavior.TickCount, 0);
|
|
820
|
+
|
|
821
|
+
yield return new WaitForSeconds(0.12f);
|
|
822
|
+
Assert.GreaterOrEqual(RecordingEffectBehavior.PeriodicTickCount, 1);
|
|
823
|
+
|
|
824
|
+
handler.RemoveEffect(handle);
|
|
825
|
+
Assert.AreEqual(1, RecordingEffectBehavior.RemoveCount);
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
[UnityTest]
|
|
829
|
+
public IEnumerator EffectBehaviorClonesPerHandle()
|
|
830
|
+
{
|
|
831
|
+
(
|
|
832
|
+
GameObject entity,
|
|
833
|
+
EffectHandler handler,
|
|
834
|
+
TestAttributesComponent attributes,
|
|
835
|
+
TagHandler tags
|
|
836
|
+
) = CreateEntity();
|
|
837
|
+
yield return null;
|
|
838
|
+
|
|
839
|
+
AttributeEffect effect = CreateEffect(
|
|
840
|
+
"BehaviorStacks",
|
|
841
|
+
e =>
|
|
842
|
+
{
|
|
843
|
+
e.durationType = ModifierDurationType.Infinite;
|
|
844
|
+
e.stackingMode = EffectStackingMode.Stack;
|
|
845
|
+
}
|
|
846
|
+
);
|
|
847
|
+
|
|
848
|
+
RecordingEffectBehavior behavior = Track(
|
|
849
|
+
ScriptableObject.CreateInstance<RecordingEffectBehavior>()
|
|
850
|
+
);
|
|
851
|
+
effect.behaviors.Add(behavior);
|
|
852
|
+
|
|
853
|
+
int startingInstances = RecordingEffectBehavior.InstanceCount;
|
|
854
|
+
|
|
855
|
+
EffectHandle first = handler.ApplyEffect(effect).Value;
|
|
856
|
+
Assert.AreEqual(startingInstances + 1, RecordingEffectBehavior.InstanceCount);
|
|
857
|
+
|
|
858
|
+
EffectHandle second = handler.ApplyEffect(effect).Value;
|
|
859
|
+
Assert.AreEqual(startingInstances + 2, RecordingEffectBehavior.InstanceCount);
|
|
860
|
+
Assert.AreEqual(2, RecordingEffectBehavior.ApplyCount);
|
|
861
|
+
|
|
862
|
+
handler.RemoveEffect(first);
|
|
863
|
+
handler.RemoveEffect(second);
|
|
864
|
+
Assert.AreEqual(2, RecordingEffectBehavior.RemoveCount);
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
[UnityTest]
|
|
868
|
+
public IEnumerator EffectBehaviorWithoutPeriodicSkipsPeriodicCallbacks()
|
|
869
|
+
{
|
|
870
|
+
(
|
|
871
|
+
GameObject entity,
|
|
872
|
+
EffectHandler handler,
|
|
873
|
+
TestAttributesComponent attributes,
|
|
874
|
+
TagHandler tags
|
|
875
|
+
) = CreateEntity();
|
|
876
|
+
yield return null;
|
|
877
|
+
|
|
878
|
+
AttributeEffect effect = CreateEffect(
|
|
879
|
+
"BehaviorNoPeriodic",
|
|
880
|
+
e =>
|
|
881
|
+
{
|
|
882
|
+
e.durationType = ModifierDurationType.Infinite;
|
|
883
|
+
}
|
|
884
|
+
);
|
|
885
|
+
|
|
886
|
+
RecordingEffectBehavior behavior = Track(
|
|
887
|
+
ScriptableObject.CreateInstance<RecordingEffectBehavior>()
|
|
888
|
+
);
|
|
889
|
+
effect.behaviors.Add(behavior);
|
|
890
|
+
|
|
891
|
+
EffectHandle handle = handler.ApplyEffect(effect).Value;
|
|
892
|
+
yield return new WaitForSeconds(0.1f);
|
|
893
|
+
|
|
894
|
+
Assert.AreEqual(0, RecordingEffectBehavior.PeriodicTickCount);
|
|
895
|
+
|
|
896
|
+
handler.RemoveEffect(handle);
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
[UnityTest]
|
|
900
|
+
public IEnumerator StackingModeStackRespectsMaximumStacks()
|
|
901
|
+
{
|
|
902
|
+
(
|
|
903
|
+
GameObject entity,
|
|
904
|
+
EffectHandler handler,
|
|
905
|
+
TestAttributesComponent attributes,
|
|
906
|
+
TagHandler tags
|
|
907
|
+
) = CreateEntity();
|
|
908
|
+
yield return null;
|
|
909
|
+
|
|
910
|
+
AttributeEffect effect = CreateEffect(
|
|
911
|
+
"Stacking",
|
|
912
|
+
e =>
|
|
913
|
+
{
|
|
914
|
+
e.durationType = ModifierDurationType.Infinite;
|
|
915
|
+
e.stackingMode = EffectStackingMode.Stack;
|
|
916
|
+
e.maximumStacks = 2;
|
|
917
|
+
}
|
|
918
|
+
);
|
|
919
|
+
|
|
920
|
+
EffectHandle first = handler.ApplyEffect(effect).Value;
|
|
921
|
+
EffectHandle second = handler.ApplyEffect(effect).Value;
|
|
922
|
+
EffectHandle third = handler.ApplyEffect(effect).Value;
|
|
923
|
+
|
|
924
|
+
List<EffectHandle> active = handler.GetActiveEffects();
|
|
925
|
+
Assert.AreEqual(2, active.Count);
|
|
926
|
+
CollectionAssert.DoesNotContain(active, first);
|
|
927
|
+
CollectionAssert.Contains(active, second);
|
|
928
|
+
CollectionAssert.Contains(active, third);
|
|
929
|
+
|
|
930
|
+
handler.RemoveAllEffects();
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
[UnityTest]
|
|
934
|
+
public IEnumerator InstantEffectWithPeriodicLogsWarning()
|
|
935
|
+
{
|
|
936
|
+
(
|
|
937
|
+
GameObject entity,
|
|
938
|
+
EffectHandler handler,
|
|
939
|
+
TestAttributesComponent attributes,
|
|
940
|
+
TagHandler tags
|
|
941
|
+
) = CreateEntity();
|
|
942
|
+
yield return null;
|
|
943
|
+
|
|
944
|
+
AttributeEffect effect = CreateEffect(
|
|
945
|
+
"InstantPeriodic",
|
|
946
|
+
e =>
|
|
947
|
+
{
|
|
948
|
+
e.durationType = ModifierDurationType.Instant;
|
|
949
|
+
PeriodicEffectDefinition definition = new() { interval = 0.05f, maxTicks = 1 };
|
|
950
|
+
definition.modifications.Add(
|
|
951
|
+
new AttributeModification
|
|
952
|
+
{
|
|
953
|
+
attribute = nameof(TestAttributesComponent.health),
|
|
954
|
+
action = ModificationAction.Addition,
|
|
955
|
+
value = -10f,
|
|
956
|
+
}
|
|
957
|
+
);
|
|
958
|
+
e.periodicEffects.Add(definition);
|
|
959
|
+
}
|
|
960
|
+
);
|
|
961
|
+
|
|
962
|
+
LogAssert.Expect(
|
|
963
|
+
LogType.Warning,
|
|
964
|
+
new Regex("defines periodic or behaviour data but is Instant")
|
|
965
|
+
);
|
|
966
|
+
|
|
967
|
+
EffectHandle? handle = handler.ApplyEffect(effect);
|
|
968
|
+
Assert.IsFalse(handle.HasValue);
|
|
969
|
+
|
|
970
|
+
yield return new WaitForSeconds(0.1f);
|
|
971
|
+
Assert.AreEqual(100f, attributes.health.CurrentValue, 0.01f);
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
[UnityTest]
|
|
975
|
+
public IEnumerator StackingModeReplaceSwapsHandles()
|
|
976
|
+
{
|
|
977
|
+
(
|
|
978
|
+
GameObject entity,
|
|
979
|
+
EffectHandler handler,
|
|
980
|
+
TestAttributesComponent attributes,
|
|
981
|
+
TagHandler tags
|
|
982
|
+
) = CreateEntity();
|
|
983
|
+
yield return null;
|
|
984
|
+
|
|
985
|
+
AttributeEffect effect = CreateEffect(
|
|
986
|
+
"Replace",
|
|
987
|
+
e =>
|
|
988
|
+
{
|
|
989
|
+
e.durationType = ModifierDurationType.Infinite;
|
|
990
|
+
e.stackingMode = EffectStackingMode.Replace;
|
|
991
|
+
}
|
|
992
|
+
);
|
|
993
|
+
|
|
994
|
+
EffectHandle first = handler.ApplyEffect(effect).Value;
|
|
995
|
+
EffectHandle second = handler.ApplyEffect(effect).Value;
|
|
996
|
+
|
|
997
|
+
List<EffectHandle> active = handler.GetActiveEffects();
|
|
998
|
+
Assert.AreEqual(1, active.Count);
|
|
999
|
+
Assert.AreEqual(second, active[0]);
|
|
1000
|
+
Assert.AreNotEqual(first, second);
|
|
1001
|
+
|
|
1002
|
+
handler.RemoveAllEffects();
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
[UnityTest]
|
|
1006
|
+
public IEnumerator CustomStackGroupSharesAcrossEffects()
|
|
1007
|
+
{
|
|
1008
|
+
(
|
|
1009
|
+
GameObject entity,
|
|
1010
|
+
EffectHandler handler,
|
|
1011
|
+
TestAttributesComponent attributes,
|
|
1012
|
+
TagHandler tags
|
|
1013
|
+
) = CreateEntity();
|
|
1014
|
+
yield return null;
|
|
1015
|
+
|
|
1016
|
+
AttributeEffect effectA = CreateEffect(
|
|
1017
|
+
"GroupA",
|
|
1018
|
+
e =>
|
|
1019
|
+
{
|
|
1020
|
+
e.durationType = ModifierDurationType.Infinite;
|
|
1021
|
+
e.stackGroup = EffectStackGroup.CustomKey;
|
|
1022
|
+
e.stackGroupKey = "shared";
|
|
1023
|
+
e.stackingMode = EffectStackingMode.Replace;
|
|
1024
|
+
}
|
|
1025
|
+
);
|
|
1026
|
+
AttributeEffect effectB = CreateEffect(
|
|
1027
|
+
"GroupB",
|
|
1028
|
+
e =>
|
|
1029
|
+
{
|
|
1030
|
+
e.durationType = ModifierDurationType.Infinite;
|
|
1031
|
+
e.stackGroup = EffectStackGroup.CustomKey;
|
|
1032
|
+
e.stackGroupKey = "shared";
|
|
1033
|
+
e.stackingMode = EffectStackingMode.Replace;
|
|
1034
|
+
}
|
|
1035
|
+
);
|
|
1036
|
+
|
|
1037
|
+
EffectHandle first = handler.ApplyEffect(effectA).Value;
|
|
1038
|
+
EffectHandle second = handler.ApplyEffect(effectB).Value;
|
|
1039
|
+
|
|
1040
|
+
List<EffectHandle> active = handler.GetActiveEffects();
|
|
1041
|
+
Assert.AreEqual(1, active.Count);
|
|
1042
|
+
Assert.AreEqual(second, active[0]);
|
|
1043
|
+
Assert.IsFalse(handler.IsEffectActive(effectA));
|
|
1044
|
+
Assert.IsTrue(handler.IsEffectActive(effectB));
|
|
1045
|
+
Assert.AreNotEqual(first, second);
|
|
1046
|
+
|
|
1047
|
+
handler.RemoveAllEffects();
|
|
1048
|
+
}
|
|
1049
|
+
|
|
432
1050
|
private (
|
|
433
1051
|
GameObject entity,
|
|
434
1052
|
EffectHandler handler,
|