refactor: simplify entity lookups and clean up state updates

- Replace manual entity iteration with `world.FindEntity<T>()`
- Remove redundant `MarkModified<GameState>` calls
- Add safety counters to prevent infinite loops in tests and systems
- Call `FlushPendingMutations` after card transfers to ensure
  consistency
- Rename `Run` to `RunImpl` in several systems
This commit is contained in:
2026-07-21 13:57:11 +08:00
parent 4cdfe9c957
commit cbb7edd472
12 changed files with 35 additions and 69 deletions
+9 -13
View File
@@ -11,7 +11,7 @@ public struct HitCommand : ICommand
{
public void Execute(World world)
{
ref var state = ref world.GetSingleton<GameState>();
var state = world.ReadSingleton<GameState>();
if (state.Phase != GamePhase.PlayerTurn)
return;
@@ -25,9 +25,8 @@ public struct HitCommand : ICommand
internal static void DrawCard<THand>(World world)
where THand : struct
{
var singletonEntity = World.SingletonEntity;
var deckEntity = FindEntity<Deck>(world, singletonEntity);
var handEntity = FindEntity<THand>(world, singletonEntity);
var deckEntity = world.FindEntity<Deck>();
var handEntity = world.FindEntity<THand>();
if (deckEntity == Entity.Null || handEntity == Entity.Null)
return;
@@ -42,17 +41,14 @@ public struct HitCommand : ICommand
// Remove from deck, add to hand.
world.RemoveComponent<InDeck>(cardEntity);
world.AddComponent(cardEntity, new Holds { Target = handEntity });
// Flush so subsequent DrawCard calls see the updated state.
world.FlushPendingMutations();
}
internal static Entity FindEntity<T>(World world, Entity singletonEntity)
internal static Entity FindEntity<T>(World world)
where T : struct
{
using var iter = world.Select<T>();
while (iter.MoveNext())
{
if (iter.CurrentEntity != singletonEntity)
return iter.CurrentEntity;
}
return Entity.Null;
return world.FindEntity<T>();
}
}
}
+3 -7
View File
@@ -17,28 +17,25 @@ public struct NewRoundCommand : ICommand
return;
// Clear hands from previous round.
var singletonEntity = World.SingletonEntity;
var handEntities = new List<Entity>();
using (var iter = world.Select<PlayerHand>())
{
while (iter.MoveNext())
{
if (iter.CurrentEntity != singletonEntity)
handEntities.Add(iter.CurrentEntity);
handEntities.Add(iter.Entity);
}
}
using (var iter = world.Select<DealerHand>())
{
while (iter.MoveNext())
{
if (iter.CurrentEntity != singletonEntity)
handEntities.Add(iter.CurrentEntity);
handEntities.Add(iter.Entity);
}
}
foreach (var hand in handEntities)
{
var cards = world.GetSources<Holds>(hand);
var deckEntity = HitCommand.FindEntity<Deck>(world, singletonEntity);
var deckEntity = world.FindEntity<Deck>();
foreach (var card in cards)
{
world.RemoveComponent<Holds>(card);
@@ -49,6 +46,5 @@ public struct NewRoundCommand : ICommand
state.RoundNumber++;
state.Phase = GamePhase.Betting;
state.Result = RoundResult.None;
world.MarkModified<GameState>(World.SingletonEntity);
}
}
@@ -24,6 +24,5 @@ public struct PlaceBetCommand : ICommand
state.CurrentBet = Amount;
state.Chips -= Amount;
state.Phase = GamePhase.Dealing;
world.MarkModified<GameState>(World.SingletonEntity);
}
}
-1
View File
@@ -17,6 +17,5 @@ public struct StandCommand : ICommand
return;
state.Phase = GamePhase.DealerTurn;
world.MarkModified<GameState>(World.SingletonEntity);
}
}