Skip to content

C# port of DistrictServer (DistrictServerCSharp/): full reimplementation, status + verification #12

Description

@eaxiumnet

C# port of DistrictServer (DistrictServerCSharp/) — full reimplementation, status + verification

This issue documents a complete C# (.NET 8) reimplementation of DistrictServer.cpp (~14k lines → ~40 modular service files) that has been developed in parallel with the C++ tree. It is informational / a proposal for discussion — the C++ DistrictServer/ remains the protocol oracle and the rollback path.

What it is

A wire-identical port of the C++ district server, structured by responsibility (modern C# idioms, no global mutable state):

  • Handshake/ — AUTH/USES/WELCOME/JOIN/ANS, channel-sequencing, binary NMT control
  • WorldControl/ — world registration + character handoffs
  • Core/ — reliable TX queue + retry/ACK, transport-state tracking, packet diagnostics
  • Gri/, Streaming/, SpawnZone/ — GRI match-start, level-streaming plan, spawn-zone markers/selection
  • Pawn/ — ACK-gated pawn bootstrap + possession, remote-pawn multiplayer + dead-peer lifecycle
  • Packages/ — cooked-package net-index resolver (parses cooked .u packages directly)
  • Controller/ — controller field decoding, customisation replicator request dispatch
  • Protocol/, Bits/, Crypto/, Net/ — UE3 wire layer, bit primitives, XTEA/BTEA, UDP listener

Port status (drift-gated)

Tools/check_port_sync.py inventories every C++ function and asserts it has a C# home:

  • DistrictServer.cpp: 175 functions — 175 mapped / 0 not-ported / 0 unmapped (complete)
  • ApbUdp.cpp wire layer covered by a file map; the only intentionally-unported items are dead Unreal.cpp (not in the C++ build, zero callers) and 3 zero-caller raw-float helpers

Verification

  • dotnet build -c Release — 0 warnings / 0 errors
  • --selftest — byte-identical wire output vs the C++ self-test vectors
  • --drive (two-player) — full join path: AUTH → WELCOME → JOIN → 371 spawn-zone → district-enter answer → pawn-open → all 8 ACK-gated possession stages, remote pawns on both viewers, and the customisation transfer driven to ClientNotifyTransferComplete
  • --resolver-check — parses a real cooked APBGame.u and reproduces the live C++ net indices exactly (controller 12426, holdable 15985→47088, storage 25478→56581)
  • Tools/check_port_sync.py (default + --all) and Tools/check_deploy_sync.py — both green

Deploy state

The C# port is currently the deployed live district server in the local stack (Social 6969 / Financial 6970 / Waterfront 6971, world control 2108; win-x64 apphost, sha 526e3d64…, boot 2026-08-17 13:31). It is not yet committed to git — the DistrictServerCSharp/ tree is untracked, so nothing here is a merge request yet.

What is NOT yet proven

  • A live-client smoke test: the deployed C# port has not yet been validated end-to-end against the real 1.1 client (all current verification is in-process/simulated). This is the last open verification gap.

Proposed path to a PR (for discussion)

  1. Commit DistrictServerCSharp/ (+ the Tools/check_port_sync.py / check_deploy_sync.py gates) to a feature branch on the fork with incremental, reviewable history.
  2. Run a live-client smoke test against the deployed C# port and capture the milestones.
  3. Open a PR with the full diff + verification summary, keeping the C++ tree as the oracle for review.

Happy to restructure, split into smaller PRs, or adjust the architecture based on maintainer feedback before anything is merged.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions