| name | fantasy-net |
| description | This guide applies to development and code review for Fantasy / Fantasy.Net / Fantasy.Unity written in C#. Use it when a task involves Fantasy server code or Unity client code using Fantasy, ECS entities/components/systems, scenes and subscenes, FTask, network handlers/messages/protocols, Address or Roaming routing, Control Center and service discovery, Kubernetes deployment and Pod DNS binding, Namespace/WorldGroup/World isolation, dynamic Scene registration or routing, cross-server events and subscriptions, Fantasy.config, scene or database access, HTTP controllers/services, session or client connection logic, or distributed runtime architecture. It may also be used for Fantasy-related code review, troubleshooting, compliance checks, risk analysis, and best practices, even when the user does not explicitly mention Fantasy. |
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
FTask for all async operations, not Task
- 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}Helper only 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 via response.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 as OnHpChange_ExitGame; never suffix them with System, Async, or Handler
- When Control Center is enabled, use
ServiceDiscovery for 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; |