Fantasy-net
Fantasy is a high-performance C# distributed game server framework based on ECS architecture, using FTask for async operations.
Core Principles
Fantasy Technical Specifications
- Use
FTaskfor all async operations, notTask - Separate Entity data from logic (Handler/System); multi-assembly projects must separate to support hot reload
- Name Component business extension classes
{ComponentFullName}System; add a static{Domain}Helperonly when other systems need a shared business entry point - All registration is done at compile-time by source generators; don't manually register, don't modify
.g.cs - Entities, components, and Handlers use
sealed class; all classes except structs must be created via Entity - Use file-scoped namespaces (
namespace Fantasy;) - Use
Log.Debug/Info/Error()for logging; return error codes viaresponse.ErrorCode; business logic should not throw exceptions - Use Event system for module decoupling: publish events instead of direct calls; prefer Struct events (zero GC), use Entity events for complex logic; use EventSystem for sync, AsyncEventSystem for async
- Name Event listeners
{EventName}_{BusinessAction}, such asOnHpChange_ExitGame; never suffix them withSystem,Async, orHandler - When Control Center is enabled, use
ServiceDiscoveryfor dynamic Root Scene and SubScene routing; keep strict account-to-node affinity in business storage rather than the service registry - Before planned Scene shutdown, call
ServiceDiscovery.SetSceneOfflineAsync, reject new business allocations, wait one discovery cache cycle, then drain and close the Scene - Strictly follow SOLID principles
Development Behavioral Guidelines
Tradeoff: These guidelines bias toward caution over speed. For trivial tasks, use judgment.
See references/guidelines-examples.md for detailed Fantasy scenario examples.
1. Think Before Coding
Don't assume. Don't hide confusion. Surface tradeoffs.
Before implementing:
- State your assumptions explicitly. If uncertain, ask.
- If multiple interpretations exist, present them - don't pick silently.
- If a simpler approach exists, say so. Push back when warranted.
- If something is unclear, stop. Name what's confusing. Ask.
Fantasy Key Points: Before implementing, clarify: architecture pattern (single-server/distributed), Entity ownership (which Scene), communication method (Roaming/Address/SphereEvent), configuration source (local Fantasy.config or Control Center), and whether dynamic discovery or strict persistent affinity is required. When uncertain, ask; don't assume.
2. Simplicity First
Minimum code that solves the problem. Nothing speculative.
- No features beyond what was asked.
- No abstractions for single-use code.
- No "flexibility" or "configurability" that wasn't requested.
- No error handling for impossible scenarios.
- If you write 200 lines and it could be 50, rewrite it.
Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.
Fantasy Key Points: Avoid premature abstraction of Entity/Component structures; don't design factory/strategy patterns for single scenarios. When users only need basic functionality, write Component + necessary AwakeSystem directly; refactor when extension is needed.
3. Surgical Changes
Touch only what you must. Clean up only your own mess.
When editing existing code:
- Don't "improve" adjacent code, comments, or formatting.
- Don't refactor things that aren't broken.
- Match existing style, even if you'd do it differently.
- If you notice unrelated dead code, mention it - don't delete it.
When your changes create orphans:
- Remove imports/variables/functions that YOUR changes made unused.
- Don't remove pre-existing dead code unless asked.
The test: Every changed line should trace directly to the user's request.
Fantasy Key Points: Never modify .g.cs generated files (if you find issues, modify source files and regenerate). Don't manually adjust source generator registration code. Don't "optimize" existing Entity/Component structures unless user explicitly requests refactoring.
4. Goal-Driven Execution
Define success criteria. Loop until verified.
Transform tasks into verifiable goals:
- "Add validation" → "Write tests for invalid inputs, then make them pass"
- "Fix the bug" → "Write a test that reproduces it, then make it pass"
- "Refactor X" → "Ensure tests pass before and after"
For multi-step tasks, state a brief plan:
1. [Step] → verify: [check]
2. [Step] → verify: [check]
3. [Step] → verify: [check]
Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification.
Fantasy Key Points: Define verifiable steps and criteria: protocol export (dotnet fantasy-export successfully generates .g.cs), compilation passes (dotnet build with no errors), Handler registration (check generated registration code), message flow (Log.Debug outputs key nodes, confirm request/response correctness).
Reference File Navigation
Read the corresponding file based on the requirement; for complex tasks, read multiple files.
| File | When to Use |
|---|---|
references/ecs/index.md |
ECS entry: routes to Scene / SubScene / Entity definition / component operations / object pool / lifecycle; shared by server and Unity; read this first when Entity definition, component management, or ECS mechanism selection is involved |
references/review.md |
Fantasy code review entry: routes checks by ECS / Event / Timer / Protocol / Roaming / SphereEvent / HTTP / Database / Config; read this first when user wants review, code check, or Fantasy compliance verification |
references/guidelines-examples.md |
Development behavioral guidelines Fantasy scenario examples: Think Before Coding (clarify assumptions), Simplicity First (avoid over-engineering), Surgical Changes (precise modifications), Goal-Driven Execution (verifiable goals) with detailed comparison cases; read when understanding guideline application in Fantasy, or when code review reveals guideline violations |
references/ecs/scene.md |
Scene is the container and lifecycle boundary for all Entity/Component: cascade destruction when Scene disposes, OnCreateScene event, access system components via self.Scene (TimerComponent/EventComponent/NetworkMessagingComponent etc.); read when Scene concept, Scene initialization, OnCreateScene event, or Entity ownership is involved |
references/ecs/ecs-check.md |
ECS review checklist: Entity / Component / System / Scene / object pool / lifecycle common issues; read when user wants to check ECS code for Fantasy compliance |
references/ecs/entity-definition.md |
Entity / Component definitions: fields, ComponentSystem naming, optional cross-system Helper, and lifecycle System selection; read when creating Entity / Component types |
references/timer/index.md |
Timer entry: routes to async wait / callback timers / event integration / best practices; read first when user needs delayed execution, repeated tasks, countdown, Wait, OnceTimer, RepeatedTimer |
references/timer/implement.md |
Timer implementation: FTask.Wait, WaitTill, WaitFrame, OnceTimer, RepeatedTimer, cancel timers; read only when directly writing Timer code |
references/timer/event.md |
Timer and Event integration: event-based timers, hot reload differences, when to use events instead of Action; read only when hot-reload-friendly Timer logic is needed |
references/timer/best-practices.md |
Timer best practices and troubleshooting: performance tips, common errors, Scene destruction, precision, cancel strategies; read only when optimizing or troubleshooting Timer code |
references/ecs/subscene.md |
SubScene dynamic child scenes: lightweight isolated spaces created at runtime from parent Scene, sharing parent Scene core components but with independent entity lists; Scene.CreateSubScene() callback and registration order, Control Center discovery by parent Address, Address messaging, and active offline on Close(); read when needing instances, match rooms, instanced maps, dynamic battlefields, player private spaces, or on-demand scene creation/destruction |
references/ecs/lifecycle.md |
ECS lifecycle Systems: AwakeSystem, UpdateSystem, DestroySystem, DeserializeSystem, TransferOutSystem/TransferInSystem (cross-server transfer only) and trigger order; read when responding to Entity lifecycle events |
references/event/index.md |
Event entry: determine whether to use EventAwaiter or Event, then follow Workflow to corresponding doc; read first when requirement involves "wait for result" or "publish event" mechanism selection |
references/event/event-awaiter.md |
EventAwaiter entry: routes to implementation / modeling / troubleshooting; read first when user needs to wait for a condition, wait for player action, do request-response async flow, or explicitly mentions EventAwaiter/EventAwaiterComponent |
references/event/struct-event.md |
Struct event full workflow: Step 1 define event → Step 2 create listener → Step 3 publish event; recommended for most scenarios, read when creating Struct events |
references/event/entity-event.md |
Entity event full workflow: Step 1 create listener → Step 2 publish existing Entity (note isDisposed param); read only when passing existing Entity |
references/event/check-event.md |
Event system code review: Struct event checklist, Entity event checklist, listener naming, common error comparisons; read when checking existing event code |
references/server/setup-server.md |
Create new Fantasy server project, integrate Fantasy into existing project (.NET/NuGet), three-layer structure setup, logging system quick config |
references/server/entry-initialize-hook.md |
Entry initialization hook: inject custom startup logic via IEntryInitializeHook after config loading but before serializer init; read when user needs pre-startup validation, additional config loading, environment-specific setup, or wants to execute logic before any Scene is created |
references/server/entry-initialize-hook-check.md |
Entry initialization hook review checklist: interface implementation, timing understanding, responsibility boundary, exception handling, Hook independence; read when user wants to check IEntryInitializeHook code |
references/server/kubernetes.md |
Kubernetes deployment: StatefulSet Pod DNS, Headless Service, innerBindIP / outerBindIP, TCP/KCP protocol mapping, multi-replica and Control Center constraints; read first when Kubernetes, K8s, Pod, Service, container DNS, or cluster deployment is involved |
references/unity/index.md |
Unity client entry: routes to installation, connection, Session, receiving pushes; read first when Fantasy Unity client is involved |
references/unity/unity-check.md |
Unity review checklist: version consistency, compile macros, connection methods, Session usage, push Handler common issues; read when user wants to check Unity client code |
references/unity/setup-unity.md |
Unity client install Fantasy.Unity, configure compile symbols, import protocols; read only during installation or initial integration |
references/unity/unity-connection.md |
Unity client connect to server: FantasyRuntime component, scene.Connect, Runtime.Connect, protocol selection; read only during connection initialization |
references/unity/unity-session.md |
Unity client Session usage: send messages, RPC, connection holding, disconnect; read only for how to send messages after connection |
references/logging.md |
Logging system details: Fantasy.NLog setup, appId and per-Scene files, Develop/Release flush behavior, NLog.config, custom ILog implementation (Serilog etc.) |
references/logging-check.md |
Logging review checklist: initialization signature, NLog rules, config copy, mode switching, per-Scene output, custom ILog completeness; read when user wants to check logging integration |
references/protocol/index.md |
Protocol entry: define .proto, export C#, install export tool routing; read first when .proto, Outer/Inner, protocol export is involved |
references/protocol/protocol-check.md |
Protocol review checklist: Outer/Inner selection, interface matching, naming, export, Handler alignment; read when user wants to check protocol or Handler definitions |
references/protocol/define.md |
Protocol definition entry: locate protocol root directory and route to Outer/Inner; read when creating new protocol files or determining where to place protocols |
references/protocol/define-outer.md |
Outer protocol: client↔server messages, IMessage / IRequest / IResponse; read only when defining Outer protocols |
references/protocol/define-inner.md |
Inner protocol: server↔server messages, IAddressMessage / IAddressRequest / IAddressResponse; read only when defining Inner protocols |
references/protocol/define-common.md |
Protocol common features: fields, collections, Map, enums, serialization, code injection; read only when field or serialization details are needed |
references/protocol/export.md |
Protocol export: check tool, run export, verify results; read after protocol definition is complete or when user requests re-export |
references/protocol/export-install.md |
Export tool installation and ExporterSettings.json configuration; read when tool is not installed or paths are not configured |
references/server/server-message-handler.md |
Server-side Handler for client messages, only for messages implementing IMessage/IRequest/IResponse interfaces; Message<T>/MessageRPC<TReq,TRes> templates, reply() usage, error code patterns, Session push; see respective files for Addressable/Roaming |
references/server/server-message-handler-check.md |
Server message Handler review checklist: base class selection, error codes, reply(), Session lifecycle, duplicate Handler common issues; read when user wants to check client message Handlers |
references/unity/unity-message-handler.md |
Unity client Handler for server push messages: Message<Session,T>, file location conventions, compile verification; read when user needs to create a Handler in Unity to receive server messages |
references/server/address.md |
Server-to-server messaging based on Entity.Address (RuntimeId), including dynamic Root Scene/SubScene endpoint discovery and transparent route resolution: only for messages implementing IAddressMessage/IAddressRequest/IAddressResponse interfaces; read when defining Address message Handlers |
references/server/address-check.md |
Address review checklist: message patterns, dynamic entry retrieval, SubScene parent routing, Handler types, first communication and cached address common errors; read when user wants to check Address code |
references/service-discovery/index.md |
Control Center and service discovery entry: mechanism boundary and routing to configuration, Root Scene/SubScene discovery, routing strategy, and troubleshooting; read first when dynamic Scene registration, discovery, multi-machine deployment, Namespace, WorldGroup, parent-child Scene routing, or online instances are involved |
references/service-discovery/implement.md |
Service discovery integration: controlCenter and sceneTypes, topology creation order, Release/Develop startup, Root Scene/SubScene discovery APIs, transparent Address routing, automatic registration, heartbeat, planned drain, and offline lifecycle; read when enabling or directly using service discovery |
references/service-discovery/routing.md |
Service discovery scope and routing: Namespace/WorldGroup/World filters, SubScene parent scope, random vs Rendezvous Hash vs persistent binding, local configuration compatibility, cache and performance semantics; read when choosing a dynamic target or designing affinity |
references/service-discovery/service-discovery-check.md |
Service discovery review and troubleshooting checklist: configuration, Root Scene/SubScene APIs, empty results, registration timing, heartbeats, endpoint connectivity, recovery, public deployment security, and acceptance tests; read when checking or diagnosing service discovery |
references/server/sphere-event/index.md |
SphereEvent entry: cross-server domain events, subscribe, publish, unsubscribe, choosing between Event/Roaming; read first when cross-server event notifications, SphereEventComponent, SphereEventArgs, SphereEventSystem are involved |
references/server/sphere-event/implement.md |
SphereEvent implementation: define event class, implement handler, subscribe to remote events, publish events, unsubscribe; read only when directly writing SphereEvent code |
references/server/sphere-event/best-practices.md |
SphereEvent best practices and troubleshooting: object pool, hot reload, event size, disconnect cleanup, differences from Event/Roaming; read only when optimizing or troubleshooting SphereEvent logic |
references/server/roaming/index.md |
Roaming concept entry: core concepts (SessionRoamingComponent/Terminus/RoamingType) and Workflow decision tree; read this first, then sub-files as needed |
references/server/roaming/roaming-check.md |
Roaming review checklist: protocol, link establishment, Terminus lifecycle, message flow, transfer common issues; read when user wants to check Roaming code |
references/server/roaming/protocol.md |
Define roaming protocols: RoamingType.Config configuration, IRoamingMessage/IRoamingRequest/IRoamingResponse format; read only when defining protocols and adding roaming types or servers |
references/server/roaming/setup.md |
Establish roaming routes: Gate-side GetOrCreateRoaming/Link, reconnect window, dynamic Gate ownership, parameter passing; read only when establishing routes |
references/server/roaming/on-create-terminus.md |
OnCreateTerminus event: event parameters, LinkTerminusEntity API, Args memory management rules, independent Handler implementation per server; read only when handling Terminus creation/reconnection |
references/server/roaming/on-dispose-terminus.md |
OnDisposeTerminus event: trigger timing, DisposeTerminusType distinction, independent Handler implementation per server; read only when handling Terminus disposal |
references/server/roaming/handler.md |
Roaming Handler entry: routes to message handling / push / cross-server send / transfer; read first when user wants to write Roaming Handlers or do transfers |
references/server/roaming/messaging.md |
Roaming message handling: client send, Gate proactive send to backend, Roaming Handler, backend push to client, cross-server send; read only when implementing message flow |
references/server/roaming/transfer.md |
Terminus transfer: StartTransfer, TransferOutSystem, TransferInSystem, lifecycle and considerations; read only when implementing cross-server transfer |
references/server/roaming/error-codes.md |
Roaming error codes: meanings and troubleshooting methods; read only when encountering Roaming-related errors |
references/http.md |
HTTP entry: routes to server configuration events and Controller writing; read first when HTTP server, Controller, OnConfigureHttpServices, OnConfigureHttpApplication are involved |
references/http-check.md |
HTTP review checklist: service configuration phase, middleware order, SceneContextFilter, return patterns, route mapping common issues; read when user wants to check HTTP code |
references/http-server.md |
HTTP server configuration: OnConfigureHttpServices, OnConfigureHttpApplication, authentication, authorization, CORS, middleware; read only when configuring HTTP services and middleware |
references/http-controller.md |
HTTP Controller writing: SceneContextFilter, Scene injection, Action return values, thread switching, Controller examples; read only when writing or troubleshooting Controllers |
references/database/index.md |
Database entry: MongoDB configuration, getting database instance, persistence, queries, indexes, concurrent modification routing; read first when MongoDB, IDatabase, scene.World.Database, data persistence is involved |
references/database/database-check.md |
Database review checklist: scene.World access, ISupportedSerialize, isDeserialize, coroutine locks, SeparateTable applicability; read when user wants to check database code |
references/database/mongodb.md |
MongoDB usage: ISupportedSerialize, Save, Insert, Query, Remove, indexes, isDeserialize, concurrent modification; read only when directly writing database code |
references/database/separate-table.md |
SeparateTable separate storage: aggregate entity split storage, [SeparateTable], PersistAggregate, LoadWithSeparateTables; read only when aggregate entity child data is too large and needs table separation optimization |
references/database/best-practices.md |
MongoDB best practices and troubleshooting: config association, query optimization, save strategies, common issues; read only when optimizing or troubleshooting database logic |
references/config.md |
Fantasy.config entry: routes by "add machine / process / World / Scene / database / port"; read first when Fantasy.config is involved |
references/config-check.md |
Fantasy.config review checklist: machine/process/world/scene/database reference relationships, ports, World mode ID range common issues; read when user wants to check configuration correctness |
references/config-scenarios.md |
Fantasy.config common scenarios: new project, add/remove Scene, change database, change port, multi-zone; read when modifying config for specific scenarios |
references/server/setup-server-check.md |
Server project integration review checklist: three-layer structure, target framework, Fantasy-Net reference, compile macros, AssemblyHelper, Program entry common issues; read when user wants to check server project Fantasy integration |
templates/Fantasy.config |
Full annotated template: all nodes, attributes, possible values, and examples; read only when writing actual XML |