Simulation engine and execution pipeline for EpochSim, including replay, snapshots, and run limits.
$ dotnet add package EpochSim.ExecutionDeterministic tick simulation engine for .NET 10.
Recommended package for embedding:
dotnet add package EpochSim
EpochSim.All is useful when you want one dependency that brings the full module graph (EpochSim, Execution, Serialization, Observability, Kernel):
dotnet add package EpochSim.All
Russian version: README.ru.md
using EpochSim;
var state = new WorldState();
var engine = Epoch.CreateEngine<WorldState>();
engine.AddSystem("World", tick: ctx => ctx.State.Population++);
using var run = Epoch.QuickRun(state, rootDir: "artifacts");
engine.Attach(run);
engine.RunTicks(state, seed: 1, endTickInclusive: 100);
Console.WriteLine(state.Population);
public sealed class WorldState
{
public int Population { get; set; }
}
This is the fastest path: useful artifacts, deterministic run, almost zero wiring.
QuickRun:
using var run = Epoch.QuickRun(state, rootDir: "artifacts");
RecommendedRun:
using var run = Epoch.RecommendedRun(state, rootDir: "artifacts", invariants: null);
Advanced overloads stay available when you want full control:
Epoch.RecommendedRun(state, codec, serializer, rootDir, invariants)EpochSimRun.For(state)...Build()Event log is optional and intended for replay workflows (verify-run, bisect, fast-replay).
using EpochSim;
using EpochSim.Kernel.Messaging;
var codec = Epoch.JsonCodecFromAssembly<Program>(t => t == typeof(Changed));
var serializer = Epoch.JsonStateSerializer<WorldState>();
using var run = Epoch.RecommendedRun(state, codec, serializer, rootDir: "artifacts");
[MessageKind("Changed")]
public sealed record Changed(int Delta) : IEvent;
Use RunTicks for batch jobs:
engine.RunTicks(state, seed: 1, endTickInclusive: 1000);
Use SimulationSession<TState> for long-lived loops (games, servers, interactive stepping):
var inbox = new CommandInbox();
engine.AttachInbox(inbox);
using var session = engine.CreateSession(state, seed: 1, startTick: 0);
inbox.Enqueue(new AddPopulation(5));
session.TickOnce();
session.RunUntil(100);
using EpochSim.Kernel.Messaging;
[MessageKind("AddPopulation")]
public sealed record AddPopulation(int Delta) : ICommand;
Use inboxes to feed external commands deterministically into the sim thread:
CommandInbox: commands for the next tick.ScheduledCommandInbox: commands scheduled at a specific tick with stable ordering:
var scheduled = new ScheduledCommandInbox();
engine.AttachScheduledInbox(scheduled);
scheduled.Enqueue(10, new AddPopulation(3));
scheduled.Enqueue(10, new AddPopulation(7));
scheduled.Enqueue(12, new AddPopulation(1));
See full integration recipes: Embedding
Create a starter app:
dotnet run --project src/EpochSim.Cli -- init .
Run and inspect artifacts:
dotnet run --project src/EpochSim.Cli -- run artifacts
dotnet run --project src/EpochSim.Cli -- list-runs artifacts
dotnet run --project src/EpochSim.Cli -- inspect-run artifacts <runId>
Determinism debugging:
dotnet run --project src/EpochSim.Cli -- verify-run artifacts <runId>
dotnet run --project src/EpochSim.Cli -- bisect artifacts <runId>
src/EpochSim.Samples/Quickstart/QuickstartSample.cssrc/EpochSim.Samples/Population/ (event-heavy diagnostic domain)dotnet build EpochSim.slnx -m:1
dotnet test EpochSim.slnx -m:1
English:
Russian: