Files
Project-M/Assets/_Project/Tests/EditMode/SystemOrderingCycleTests.cs
T
kronic 7571091394 LANTERN feel pass (DR-052 + gap list): SoD facing, underwater feel, Bathynaut kit, walk/run gait, suit lamp + new Synty anim packs
- SoD facing: PlayerFacing = body-yaw only (move-facing / cast-turn / idle-hold); every fire
  direction re-sourced to FacingMath.ResolveAim (pre-code review blocking catch); TickWindowMath
  shared windows with Movement-skip; reticle/FX coupled to the damage direction; cursor-dash kept.
- Underwater feel: sharpness 15->6, turn 720->360, MoveSpeed 6->4.2; TuningKnob 26-28
  (0 = no-override sentinels, dev-protocol bump on DebugTuningReport); stride footsteps + silt +
  cadence floor; bubbles; underwater ambience bed + distant groans; camera drag + dev scroll zoom.
- Bathynaut kit in-engine: dome/tank/shoulder-lamp + bare head grafted (GraftSmr rigid rebase,
  RecalculateTangents); EmissiveGloamSkinned shader (Rukhanka deformation); shoulder lamp CASTS
  (warm steady spot on body yaw).
- Gait: two-ring walk/run FreeformDirectional tree (walk @0.35, run @1.0) + blended-natural
  StrideScale; additive Posture(Bank) + Lead(chest-lead) layers; idle = AnimationIdles Base;
  banking driven from facing turn rate; flat terrain (Env_SeabedKit seabed squashed - CC is planar).
- New packs: Synty AnimationIdles + AnimationSwordCombat (combat pass queued) + SyntyPropBoneTool;
  four authored clips (sway/trudge/banks/lean) + Anim_Player_Underwater.blend + suit-kit FBX.
- Validation: 411/411 EditMode green; Play smokes (server==client facing, Aim-true projectile,
  bank/stride live-sampled, lamp beam verified); pre-code + post-impl adversarial reviews applied.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 13:56:02 -07:00

68 lines
3.9 KiB
C#

using NUnit.Framework;
using ProjectM.Server;
using ProjectM.Simulation;
using Unity.Entities;
namespace ProjectM.Tests
{
/// <summary>
/// Guards the ComponentSystemSorter "circular dependency" hazard that is INVISIBLE to the rest of the suite:
/// every other fixture registers a single system then sorts, so a cross-system [UpdateBefore/After] cycle can
/// never surface — it only throws at world creation in Play. This registers the REAL ordered server-sim set
/// (every system that participates in an UpdateBefore/After relation, or its constraint is silently ignored)
/// into one SimulationSystemGroup and sorts, reproducing the Play-time sort headlessly. Only SortSystems runs
/// (never Update), so a bare world with no entities/singletons suffices.
/// </summary>
public class SystemOrderingCycleTests
{
[Test]
public void RunCycleCombatChain_Sorts_Without_A_Dependency_Cycle()
{
using var world = new World("OrderCycleGuard");
var group = world.GetOrCreateSystemManaged<SimulationSystemGroup>();
void Add<T>() where T : unmanaged, ISystem
=> group.AddSystemToUpdateList(world.GetOrCreateSystem<T>());
// RPC-receive systems ordered before the run director
Add<ReadyToggleSystem>(); Add<RouteSelectSystem>(); Add<PortalInteractReceiveSystem>();
Add<MetaSpendSystem>(); Add<ClassSelectReceiveSystem>(); Add<BoonApplySystem>(); Add<PrepPurchaseSystem>();
// Run director + the systems ordered around it (the cycle/siege spine is deleted — LANTERN purge)
Add<RunDirectorSystem>(); Add<RoomFieldSystem>();
Add<RoomEnemyDirectorSystem>(); Add<BoonOfferSystem>();
Add<WaveSystem>();
// Combat sub-chain in the same group
Add<EnemyAISystem>(); Add<BossAISystem>();
Add<EnemyProjectileMoveSystem>(); Add<EnemyProjectileDamageSystem>();
Assert.DoesNotThrow(() => group.SortSystems(),
"A [UpdateBefore/After] cycle in the run/cycle/combat chain throws here instead of only at Play world-creation.");
}
[Test]
public void PredictedCombatChain_Sorts_Without_A_Dependency_Cycle()
{
// Phase 1.7 added DashTrailDamageSystem ([UpdateAfter(DashSystem)][UpdateBefore(HealthApplyDamageSystem)])
// and KillRewardSystem ([UpdateAfter(HealthApplyDamageSystem)]) to the predicted combat chain. A cycle in
// these [UpdateBefore/After] edges is INVISIBLE to per-system fixtures — it only throws at Play world
// creation. Co-register the chain and sort to reproduce that headlessly (SortSystems only, never Update).
using var world = new World("OrderCyclePredicted");
var group = world.GetOrCreateSystemManaged<SimulationSystemGroup>();
void Add<T>() where T : unmanaged, ISystem
=> group.AddSystemToUpdateList(world.GetOrCreateSystem<T>());
Add<StatRecomputeSystem>(); Add<MeleeComboSystem>(); Add<DashSystem>(); Add<DashTrailDamageSystem>();
Add<AbilityFireSystem>(); Add<ProjectileMoveSystem>(); Add<ProjectileDamageSystem>();
Add<HealthApplyDamageSystem>(); Add<KillRewardSystem>();
// 07-15 facing rework: PlayerAimSystem gained [UpdateAfter(MeleeComboSystem)] (plus the existing
// StatRecompute/PlayerDeathState UpdateBefore edges) - co-register the full facing neighborhood so a
// cycle in these edges throws here instead of only at Play world-creation.
Add<PlayerAimSystem>(); Add<PlayerControlSystem>(); Add<BlinkSystem>(); Add<PlayerDeathStateSystem>();
Assert.DoesNotThrow(() => group.SortSystems(),
"A cycle in the Phase 1.7 predicted combat chain throws here instead of only at Play world-creation.");
}
}
}