feat: add deferred structural mutations and entity iterators
Implement deferred structural mutations (AddComponent, RemoveComponent, DestroyEntity) to allow safe modification of the world during iteration. Additionally, introduce a new `EntityIterator` API providing zero- allocation `ref struct` iterators (`Select<T1>`, `Select<T1, T2>`, etc.) to support manual iteration with early-exit capabilities. As part of these changes, component access via `GetComponent<T>` during iteration now automatically marks components as modified.
This commit is contained in:
@@ -20,20 +20,20 @@ public struct PlaceMarkCommand : ICommand
|
||||
if (state.Status != GameStatus.Playing)
|
||||
return;
|
||||
|
||||
// Copy to locals so the lambda in ForEach can capture them
|
||||
// (this is a struct, so `this` cannot be captured directly).
|
||||
int row = Row;
|
||||
int col = Col;
|
||||
|
||||
// Find the cell entity at (Row, Col) that has no Mark.
|
||||
// Use the iterator API with early-exit via break.
|
||||
var query = world.Query().With<Cell>().Without<Mark>().Build();
|
||||
Entity? target = null;
|
||||
|
||||
world.ForEach(query, (Entity entity, ref Cell cell) =>
|
||||
using var iter = world.Select<Cell>(query);
|
||||
while (iter.MoveNext())
|
||||
{
|
||||
if (cell.Row == row && cell.Col == col)
|
||||
target = entity;
|
||||
});
|
||||
if (iter.Current1.Row == Row && iter.Current1.Col == Col)
|
||||
{
|
||||
target = iter.CurrentEntity;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (target == null)
|
||||
return; // Cell already occupied or invalid position.
|
||||
|
||||
@@ -24,12 +24,14 @@ public class RenderSystem : ISystem
|
||||
for (int c = 0; c < 3; c++)
|
||||
grid[r, c] = '.';
|
||||
|
||||
// Fill in placed marks.
|
||||
// Fill in placed marks using the iterator API.
|
||||
var markQuery = world.Query().With<Cell>().With<Mark>().Build();
|
||||
world.ForEach(markQuery, (Entity entity, ref Cell cell, ref Mark mark) =>
|
||||
using var markIter = world.Select<Cell, Mark>(markQuery);
|
||||
while (markIter.MoveNext())
|
||||
{
|
||||
grid[cell.Row, cell.Col] = mark.Player == Player.X ? 'X' : 'O';
|
||||
});
|
||||
grid[markIter.Current1.Row, markIter.Current1.Col] =
|
||||
markIter.Current2.Player == Player.X ? 'X' : 'O';
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
Console.WriteLine(" Tic-Tac-Toe");
|
||||
|
||||
@@ -22,13 +22,14 @@ public class WinCheckSystem : ISystem
|
||||
if (state.Status != GameStatus.Playing)
|
||||
return;
|
||||
|
||||
// Build a 3×3 grid of marks.
|
||||
// Build a 3×3 grid of marks using the iterator API.
|
||||
var grid = new Player[3, 3];
|
||||
|
||||
world.ForEach(Query, (Entity entity, ref Cell cell, ref Mark mark) =>
|
||||
using var iter = world.Select<Cell, Mark>(Query);
|
||||
while (iter.MoveNext())
|
||||
{
|
||||
grid[cell.Row, cell.Col] = mark.Player;
|
||||
});
|
||||
grid[iter.Current1.Row, iter.Current1.Col] = iter.Current2.Player;
|
||||
}
|
||||
|
||||
// Check rows.
|
||||
for (int r = 0; r < 3; r++)
|
||||
|
||||
Reference in New Issue
Block a user