Repository navigation
Server architecture processes and projects
The server's processes, their ports, databases and broker queues, how they're configured and started, and how the 44 projects in the solution are layered. How it all fits together is on Server architecture.
As declared by the Aspire host:
| Aspire name | Project | Listens on | Databases | Broker queue | Also needs |
|---|---|---|---|---|---|
sts-server |
StsServer |
TCP 6600 | Auth | ||
auth-server |
AuthServer |
TCP 23115 | Auth | ||
world-server |
WorldServer |
TCP 24000, HTTP 5000 | Auth, Character, World | WorldServer_1 |
Tables, maps, scripts, Realm:RealmId
|
character-api |
API.Character |
HTTP 4000 | Auth, Character | ||
account-api |
API.Account |
HTTP 4001 | Auth | ||
chat-server |
Server.ChatServer |
Chat | ChatServer |
Character API, tables | |
group-server |
Server.GroupServer |
Group | GroupServer |
Character API | |
friendship-server |
Server.Friendship |
Friendship | FriendshipServer |
Account API, Character API, tables | |
character-server |
Server.Character |
Query | CharacterServer |
Character API | |
database-migrations |
Aspire.Database.Migrations |
All seven | Runs once: migrations, a starter account, the world database import |
Under Aspire, the three game ports bind to 127.0.0.1 on stable and to every interface upstream. The HTTP ports bind to localhost.
- The MySQL and RabbitMQ containers.
-
database-migrations, to completion. - Every server and API. The broker-only servers also wait for the Character API, and
friendship-serverfor the Account API too.character-serverwaits for its database and the Character API, but not for the migrations.
Each process reads <Name>.json from its own folder, then environment variables, which win. The Aspire host sets these per process:
| Key | Set from |
|---|---|
Network:Host, Network:Port
|
The host's TCP endpoint for that server |
Database:<Name>:ConnectionString, Database:<Name>:Provider
|
The MySQL container's database for that name |
Network:Internal:Broker, Network:Internal:ConnectionString, Network:Internal:InputQueue
|
The RabbitMQ container, and the queue in the table above |
API:<Name>:Host |
The Character or Account API's address |
Realm:RealmId |
1, for the world server |
urls |
The HTTP endpoint, for anything with a web host |
Everything else, such as table and map paths, still comes from the JSON file.
Each layer depends only on the layers above it.
| Layer | Projects | Holds |
|---|---|---|
| Leaves |
Game.Static, Shared, IO, Cryptography, Network.Sts
|
Enums and flags; configuration and the world thread; file readers; SRP6; STS messages |
| Wire |
Network, Network.World, Network.Auth, Network.Internal
|
Sessions, framing and the opcode list; client message models; auth messages; broker message contracts |
| Data |
GameTable, Database, Database.Auth, Database.Character, Database.World, Database.Chat, Database.Group, Database.Friendship, Database.Query
|
Game table readers and row models; database contexts, models and migrations |
| Contracts | Game.Abstract |
An interface for every game system |
| Script engine | Script |
Compiling, loading, watching and binding scripts |
| Logic | Game |
The implementations, one folder per system |
| Hosts |
WorldServer, AuthServer, StsServer, Server.*, API.*
|
Composition, message handlers, GM commands |
| Content |
Script.Main, Script.Instance, Script.Alizar, Script.Olyssia, Script.Arcterra, Script.Farside, Script.Isigrol
|
Content scripts |
| Tools |
MapGenerator, ClientConnector, Aspire.AppHost, Aspire.Database.Migrations
|
Table and map extraction, client launching, orchestration, migrations |
All project names start with NexusForever..
| Question | Look in |
|---|---|
| What does this client packet look like? | Source/NexusForever.Network.World/Message/Model/<Feature>/ |
| What's its opcode? | Source/NexusForever.Network/Message/GameMessageOpcode.cs |
| Who handles it? | Source/NexusForever.WorldServer/Network/Message/Handler/ |
| What crosses the broker? |
Source/NexusForever.Network.Internal/Message/, handled in Source/NexusForever.WorldServer/Network/Internal/Handler/ or the owning Server.* project |
| What is this enum value? | Source/NexusForever.Game.Static/ |
| What does this game table row hold? | Source/NexusForever.GameTable/Model/ |
| How does this system behave? |
Source/NexusForever.Game/<System>/, with its interface in Source/NexusForever.Game.Abstract/
|
| What does this GM command do? | Source/NexusForever.WorldServer/Command/ |
| What's in this database table? |
Source/NexusForever.Database.<Name>/Model/, with migrations beside it |
| Piece | Version |
|---|---|
| .NET and C# | .NET 10, C# 14 |
| Aspire hosting | 13.4.6 |
| EF Core | 10.0.10, on Microting.EntityFrameworkCore.MySql 10.0.9 |
| Rebus | 8.9.2, with RabbitMQ or Azure Service Bus transports |
| Quartz | 3.18.2 |
| NLog | 6.1.4 |
Nexus.Archive |
1.0.1, for the client's index and archive files |
Package versions are pinned centrally in Source/Directory.Packages.props. The solution has no test project.
| Piece | Path |
|---|---|
| The deployment | Source/NexusForever.Aspire.AppHost/Program.cs |
| How the host sets each process's keys | Source/NexusForever.Aspire.AppHost/ResourceBuilderExtensions.cs |
| The solution | Source/NexusForever.slnx |
| Package versions | Source/Directory.Packages.props |
| Example configs | Source/NexusForever.<Project>/<Name>.example.json |
Guides
- Running it locally
- Using the web console
- Adding a player feature
- Verifying a feature
- Taking a change upstream
- Syncing with upstream
Explanation
- Server architecture
- Login handshake
- Game tables
- Branches and workflow
- Upstream branches
- Contributing
- Galactic Archive
- Account entitlements
Reference
- Processes and projects
- File formats
- Databases
- Web console
- Galactic Archive messages and storage
- Code style
- Code patterns
- Pull requests
Design
About this wiki