Introduce IInterrupt marker interface, IInterruptHandlerCommand for
resolving
interrupts, and InterruptStore. When a pending interrupt exists at the
start
of a tick, system execution is skipped until resolved. Only one
interrupt of
a given type may be pending at a time.
Replace the empty placeholder design.md with comprehensive
design-basegame.md
and design-factions.md detailing game rules, setup, and mechanics for
the
card game 魔烬纷争.
Introduces `RelationshipReordered` change kind and `ReorderSources`
method to allow reordering the source set of a relationship without
removing and re-adding components. This optimizes shuffling operations
like deck setup in Blackjack.
Refactor the blackjack test suite to utilize the centralized
`TestHelpers`
from `OECS.PlayTest` instead of local implementations. This includes:
- Replacing local `SetupGame`, `FindEntity`, and `SnapshotWorld` with
`TestHelpers` equivalents.
- Moving `PlayLog` logic and round running into the `OECS.PlayTest`
framework.
- Updating project references to include `OECS.PlayTest`.
Refactor the TicTacToe test suite by moving shared logic, such as
game setup, snapshotting, and win checking, into a new
`TestHelpers` class. This simplifies `PlayTests.cs` and
`GameFlowTests.cs`
by removing redundant private methods and local agent implementations,
replacing them with standardized utility calls from `OECS.PlayTest`.
Introduce a new PlayTest project containing tools for simulating
gameplay, including:
- Agent abstractions (IAgent, GreedyAgent, WeightedAgentPool)
- ObservableCapture for logging entity changes
- PlayLog for generating and saving formatted play logs
- 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
Refactor code to use `Val1` and `Val2` instead of `Item1` and `Item2`
for
iterator access. Simplify `PlaceMarkCommand` and `WinCheckSystem` by
replacing `while` loops with `foreach` and removing redundant comments.
Introduce nested batching scopes to automate component dirty-marking
and defer structural mutations.
- Replace manual `MarkModified` with auto-tracking via `RefN` properties
in `Select` iterators and `GetComponent`/`GetSingleton` calls.
- Implement nested batching scopes: `SystemGroup` (tick level),
`ISystem.Run`
(system level), `CommandQueue.ExecuteAll` (command level), and
`Select`
(iteration level).
- Update `ISystem` and `ITickedSystem` to use `RunImpl` to separate
implementation from the batching-aware `Run` extension method.
- Add `ValN` properties to iterators for read-only, non-tracked access.
- Update documentation to reflect the new iteration and batching model.
Introduce `TrackAccess` in `World` to record component access
during batching scopes. Update `SelectN` iterators to provide
`RefN` for mutable, tracked access and `ValN` for read-only,
untracked access.
- Replace manual `while (iter.MoveNext())` loops with `foreach` loops in
tests
- Implement batching and mutation flushing in `CommandQueue.ExecuteAll`
to
ensure chained commands see each other's changes
Rename `BeginIteration`/`EndIteration` to `BeginBatching`/`EndBatching`
to reflect that the mechanism now covers both entity iteration and
system execution.
- Update `ISystem` and `ITickedSystem` to use `RunImpl` for logic.
- Add `SystemExtensions.Run` to wrap system execution in a batching
scope.
- Update `SystemGroup` to wrap system execution in a batching scope.
- Update `WorldQueryExtensions` to use the new batching terminology.
Update the ECS engine to support automatic mutation tracking for
singletons during iteration, removing the need for manual
`MarkModified` calls.
- Update `ComponentDiscoveryGenerator` to detect singleton components.
- Refactor `PlaceMarkCommand` and `WinCheckSystem` to leverage
automatic mutation marking.
- Replace `ForEach` usage with `Select` and `ItemN` access in tests
and systems to align with the updated iterator API.
Replace the old `QueryBuilder` and `ForEach` callback pattern with a
more
performant, zero-allocation `Select` API using `ref struct` iterators.
This change also updates the singleton implementation to use dedicated
entities per component type rather than a single reserved entity.
- Replace `QueryBuilder`/`QueryDescriptor` with generic `Query<T1..T6>`
- Replace `ForEach` callbacks with `world.Select<T1..T6>()` iterators
- Replace `EntityIterator` with `WorldQueryExtensions`
- Update singleton logic to allocate one entity per component type
- Add `FindEntity<T>` and `FindEntities<T>` lookup methods
Replace the delegate-based ForEach pattern with zero-allocation ref
struct Select iterators. This change moves iteration logic from
QueryExecutor to WorldQueryExtensions and introduces a new fluent
Query<T> API.
Other changes:
- Update singleton handling to use a dictionary instead of a reserved
ID.
- Add IsSingleton flag to ComponentDescriptor.
- Replace QueryDescriptor with type-safe Query<T> structs.
- Update tests to use the new Select API.
Remove the redundant `Source` property from `IRelationship` and its
implementations. Since the relationship component is inherently
stored on the source entity, the `Source` field was unnecessary and
required manual synchronization during deserialization.
This change simplifies the relationship model, reduces memory usage,
and removes the need for reflection-based fixups in the serializer.
Implement the core CardWars game logic using an ECS-based architecture.
This includes:
- Card effect registry and various card effect implementations.
- Game phase management (Setup, Play, Flip, Scoring, Cleanup).
- Command system for player actions (PlayCard, FlipCard, etc.).
- Component-based game state and entity relationships.
- Automated game setup and scoring systems.
- Unit tests for game setup, card effects, and play logs.
Add new skill documentation files for developing OECS, testing games,
and writing games. Also update the API surface documentation to include
guidance on component and command definitions.
Update the API surface and implementation plan to reflect architectural
changes, including new iterator overloads, system design refinements,
and the introduction of a source generator.
Refactor `RunRound` to `RunUntilDone` to allow for multi-round
simulations
until a win/loss condition is met. Added round summaries, win/loss/push
tracking, and improved log formatting to provide better visibility into
agent performance.
Implement play tests for Blackjack and TicTacToe that simulate games
using various AI agents (Basic Strategy, Random, Greedy) and record
the results, decisions, and reactivity into playlogs for debugging
and LLM analysis. Update documentation to reflect the purpose of
these tests.
Enhance the OECS framework to support more robust component
deserialization during world serialization. This includes adding
boxed component support and a runtime fallback for component
discovery.
Additionally, introduces snapshot testing patterns for Blackjack
and TicTacToe to allow for manual verification of world state and
reactivity logs.
- Add xUnit test projects for both games
- Implement game flow tests for Blackjack
- Implement game flow tests for TicTacToe
- Rename namespaces and projects to follow `Game.*` convention
- Add documentation for testing games
- Move examples (Blackjack, TicTacToe) to the root directory
- Convert example projects from Console applications to Libraries
- Add Directory.Build.props for shared build settings
- Update solution file and project references to reflect new paths
Introduce an incremental source generator that automatically discovers
component types used with the World API. This allows the
WorldSerializer to perform serialization and deserialization without
relying on reflection, improving performance and stability.
Remove the mandatory Query property from the ISystem interface,
allowing systems to manage their own queries locally or via other
means. Update all implementing systems and tests to use local
query descriptors instead.
Add `where TSelf : struct where TTarget : struct` constraints to
the `Relationship` struct to ensure type safety and consistency with
the ECS architecture. Also remove unused `IterateThree` method in
`QueryExecutor`.
- Optimize `QueryExecutor` to use the smallest sparse set as a driver
for multi-component queries, reducing iteration overhead.
- Implement automatic cleanup of unused `Subject` instances in
`ChangeBuffer` using a subscriber count.
- Improve `ChangeSet` deduplication to correctly handle rapid
add/remove transitions for the same component.
- Add validation to ensure `IRelationship` components are added to
their declared `Source` entity.
- Update documentation to reflect correct `Entity` bit layout.
- Optimize Select2 and Select3 iterators to drive from the smallest
sparse set to minimize probes.
- Use a constrained generic in CommandQueue.Enqueue to avoid boxing
struct commands at the call site.
- Ensure singleton infrastructure is initialized during world
deserialization if the singleton entity is loaded.
- Change EnsureSingleton to internal.
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.
- Add serialization support to `World`, `EntityAllocator`, and
`SparseSet`
- Implement `SaveGame` and `LoadGame` functionality in the TicTacToe
example
- Add ability to resume a game from a saved state
- Implement auto-save after every move in the game loop
Implement a complete Tic-Tac-Toe game using OECS to demonstrate
ECS patterns, including:
- Command pattern for placing marks
- System groups for logical updates and rendering
- CSV loading for initial board state
- Reactivity logging for observing entity and component changes
fix: notify change buffer when removing components in World
docs: add caution about structural changes during ForEach
fix: prevent multiple disposals in World