Turbo.Cloud.sln is the main emulator solution. Turbo.Main is the runtime host and composition root.
Turbo.Main/- Host startup and wiring (
Program.cs), configuration, lifetime, and console commands.
- Host startup and wiring (
Turbo.Plugins/- Runtime discovery, loading, start/stop, and unload lifecycle for plugins.
Turbo.PacketHandlers/- Incoming message handling orchestration and domain dispatch.
Turbo.Events/- Event behavior/handler pipeline registration and execution.
Turbo.*domain modules (Rooms,Players,Catalog,Inventory, etc.)- Domain services, snapshot providers, and Orleans grain orchestration.
Turbo.Database/- EF Core context and persistence infrastructure.
Turbo.Primitives/- Cross-module contracts, identifiers, snapshots, and message types.
- Keep host composition and module registration in
Turbo.Main; avoid leaking host concerns into domain modules. - Keep packet handlers focused on request/response orchestration, not persistence infrastructure wiring.
- Keep database querying and persistence access out of packet handlers.
- Keep grain lifecycle/state logic within grain modules; do not bypass grain boundaries with direct cross-layer shortcuts.
- Keep plugin lifecycle operations inside
Turbo.Plugins; do not duplicate plugin loading logic in unrelated modules. - Protocol revision parser/serializer trees are owned by the plugin repo at:
../turbo-sample-plugin/TurboSamplePlugin/Revision/**- Do not create
Revision<id>/ParsersorRevision<id>/Serializerstrees inturbo-cloud.
- Extended profile flow boundary:
Turbo.PacketHandlers/Users/*ExtendedProfile*Handler.csorchestrates lookup + response mapping only.Turbo.Players/Grains/PlayerDirectoryGrain.csowns username/id lookup semantics and cache coherence.Turbo.Players/Grains/PlayerGrain.csexposes profile snapshots consumed by handlers.
- Username-to-id lookup behavior is case-insensitive.
- Directory cache updates must keep forward and reverse mappings consistent across set/invalidate paths.
- Avoid adding handler-level fallbacks that bypass directory-grain lookup responsibilities.
- Connection accepted:
- session is added to gateway/session tracking.
- After SSO success:
- session is registered to
PlayerPresenceGrainfor that player id.
- session is registered to
- Player outbound targeting:
- resolve target player's presence grain
- call
SendComposerAsync - fan-out to subscribed sessions happens inside presence flow.
- Room activity:
- active room indexing/lookup and keepalive ping responsibilities stay in
RoomDirectoryGrain.
- active room indexing/lookup and keepalive ping responsibilities stay in
- Lifecycle:
- inactive grains are Orleans-managed and can deactivate automatically unless explicitly marked
[KeepAlive].
- inactive grains are Orleans-managed and can deactivate automatically unless explicitly marked
- New host startup/wiring behavior:
Turbo.Main/(usuallyProgram.cs,Extensions/, orConsole/)
- New incoming packet behavior:
Turbo.PacketHandlers/<Domain>/<Name>MessageHandler.cs
- New domain service/provider:
Turbo.<Domain>/...in the existing service/provider structure
- New grain behavior:
Turbo.<Domain>/Grains/...
Use and adapt these examples before inventing new structure:
docs/patterns/ServicePattern.csdocs/patterns/HandlerPattern.csdocs/patterns/UnitTestPattern.cs