Contributing to Avalon.Server¶
Thank you for your interest in contributing. This document covers how to set up a development environment, the conventions used in this codebase, and the process for submitting changes.
Table of Contents¶
- Prerequisites
- Local Setup
- Project Structure
- Development Workflow
- Coding Conventions
- Testing
- Submitting a Pull Request
- Reporting Issues
Prerequisites¶
- .NET 10 SDK
- Docker (for infrastructure services)
- A PostgreSQL client (optional, for direct DB inspection)
Zero-Config Dev Environment¶
The repository is intentionally set up so that cloning and running is enough to get started — no manual configuration required. Specifically:
appsettings.jsonfiles contain hardcoded local-dev credentials (Postgres password123, Redis password123, JWT signing key, etc.). These are development-only defaults, safe to use locally, and deliberately committed so contributors can run the project immediately.certs/cert-tcp.pfxis a pre-generated self-signed TLS certificate (passwordavalon) used by the Auth TCP server. It is committed for the same reason — so no manual cert generation is needed.docker-compose.ymluses matching credentials so the infra spins up in sync with the app config.
None of these values are intended for production. For any real deployment, override all secrets via environment variables or a secrets manager.
Local Setup¶
-
Clone with submodules (the
vendor/DotRecastnavmesh library is a git submodule): -
Start infrastructure (Redis + PostgreSQL):
Optionally include Redis Insight: -
Restore and build:
-
Run the servers (separate terminals):
-
API docs are served at
https://localhost:<port>/scalar.
Project Structure¶
| Area | Path | Notes |
|---|---|---|
| REST API | src/Server/Avalon.Api |
ASP.NET Core, JWT, OpenAPI |
| Auth Server | src/Server/Avalon.Server.Auth |
TCP login, MFA, world-key issuance |
| World Server | src/Server/Avalon.Server.World |
60 Hz simulation loop |
| Core world logic | src/Server/Avalon.World |
Maps, entities, spells, AI scripts |
| Shared libraries | src/Shared/ |
Domain, networking, config, metrics |
| Database projects | src/Server/Avalon.Database.* |
EF Core contexts + migrations |
| Infrastructure | src/Server/Avalon.Infrastructure |
Redis wrapper, MFA, cache keys |
| Tools | tools/ |
Migration CLI, benchmarks |
| Tests | tests/ |
Unit tests per component |
For a full architectural walkthrough see README.md and the documents under docs/.
Development Workflow¶
Adding a ValueObject<T>¶
- Create a class deriving from
ValueObject<TPrimitive>insrc/Shared/Avalon.Common. - Add validation rules in the constructor or factory method.
- OpenAPI schema and JSON serialization are handled automatically — no extra registration needed.
Adding a packet handler¶
- Define the packet contract in
src/Shared/Avalon.Network.Packetsand add aNetworkPacketTypeenum value. - For Auth: implement
IAuthPacketHandler<TPacket>insrc/Server/Avalon.Server.Auth/Handlers/. - For World (server layer): implement
IWorldPacketHandler<TPacket>insrc/Server/Avalon.Server.World/Handlers/and decorate with[PacketHandler(NetworkPacketType.X)]. - For World (core layer): implement
WorldPacketHandler<TPacket>insrc/Server/Avalon.World/Handlers/.
See networking-packet-protocol.md for the full protocol reference.
Adding a world script¶
- Define the contract in
src/Server/Avalon.World.Scripts.Abstractions. - Implement in
src/Server/Avalon.World.Scripts. - Register via the DI extension method in
Avalon.World'sServiceExtensions.
Adding a chat command¶
- Implement
ICommandinsrc/Server/Avalon.World/Chat/. - Register it as
services.AddSingleton<ICommand, YourCommand>()inServiceExtensions.AddWorldServices.
Adding a database migration¶
Avalon.Api is used as the EF design-time startup project. This is intentional for the current early stage of
development; migration execution will be decoupled to the deployment/hosting solution as the project matures.
dotnet ef migrations add <Name> \
--project src/Server/Avalon.Database.Auth \
--startup-project src/Server/Avalon.Api \
--context AuthDbContext
Replace Auth / AuthDbContext with Character / CharacterDbContext or World / WorldDbContext as needed.
Convenience add-migration.ps1 scripts in each Avalon.Database.* project wrap this command.
Migrations are applied automatically when Avalon.Api starts — no separate apply step is needed in development.
Coding Conventions¶
- Framework: .NET 10 / C#. Follow standard C# naming conventions.
- Value objects: Wrap primitive IDs in
ValueObject<T>(seesrc/Shared/Avalon.Common). Do not pass rawint/longIDs across layer boundaries. - No raw strings for Redis keys: all key patterns live in
CacheKeysinsrc/Server/Avalon.Infrastructure. - Public abstractions: if a type is consumed by more than one project, it belongs in a
*.Publicor*.Abstractionsproject, not in the implementation project. - No direct cross-context DB access: each
DbContext(Auth,Character,World) is owned by its server. Cross-context data exchange goes through Redis or a service interface. - Comments: only where the logic is non-obvious. Avoid restating what the code already says.
- Security: never embed credentials, keys, or connection strings in source. Use
appsettings.Development.json(gitignored) or environment variables.
Testing¶
# Run all tests
dotnet test --no-build
# Run a single project
dotnet test tests/Avalon.Server.Auth.UnitTests
# Run a specific class
dotnet test tests/Avalon.Server.Auth.UnitTests --filter "FullyQualifiedName~CAuthHandlerShould"
- Framework: xUnit + NSubstitute.
- Test files are named
<Subject>Should.cs; methods followShould_<verb>_<condition>. - No real infrastructure in unit tests — substitute all external dependencies.
- New behaviour should be accompanied by tests. Bug fixes should include a regression test where practical.
Submitting a Pull Request¶
-
Fork the repository and create a branch from
main: -
Make your changes, following the conventions above.
-
Ensure all tests pass and the solution builds in Release:
-
Push your branch and open a PR against
main. -
In the PR description, explain:
- What changed and why.
- Any design trade-offs or alternatives you considered.
-
Steps to test the change manually (if applicable).
-
Keep PRs focused. If you have unrelated improvements, open separate PRs.
Reporting Issues¶
- Use GitHub Issues to report bugs or request features.
- For bugs, include the component (API / Auth Server / World Server), steps to reproduce, expected vs. actual behaviour, and relevant log output.
- Check
TODO.mdbefore opening a feature request — it may already be tracked there.
License¶
By contributing you agree that your contributions will be licensed under the MIT License.