eveofdarkness.org

Getting started: a test server, a search, and a revised plan

The goal for the first milestone is small: a client that logs in to a DAoC server, lists characters, and stands in the world at the right coordinates. Before writing any of it, we did three things.

1. Stood up a test server

We run OpenDAoC release 2026.09.36 in containers, pinned to an exact image so the server can't change underneath us while we work on the protocol.

It starts with about 400 errors in the log. We traced every category. Nearly all are broken references inside the public database dump: spell lines pointing at spells that don't exist, mobs using NPC templates that don't exist, loot naming missing items. A few are database entries the code no longer matches. As far as we can tell, none touch login or networking, so we're leaving them alone for now.

2. Searched before coding

We assumed others had already done packet-level work, and they had:

  • OpenDAoC-ClientSimulator: the OpenDAoC team's headless C# test client. It drives login through entering the world, for client version 1.124.
  • RustDAoC: a Rust client for 1.127e, the version OpenDAoC recommends. It includes a recorded login session. We split it into its 2,057 packets, and all 171 client packets pass the server's checksum. (We don't know whether the original client or RustDAoC's own client produced it.)
  • PacketLogConverter: Dawn of Light's packet-log viewer, with a decoder for each packet type up to 1.126.
  • Eve of Darkness: clear, tested definitions of the login packets.

What we didn't find: a Wireshark dissector for DAoC. There doesn't seem to be one.

We also noted the licenses. OpenDAoC, Dawn of Light, RustDAoC and the open-sourced Uthgard code are GPL. Several other projects have no license file, so we read them but don't copy them. Our own client code will be GPL-3.0-or-later.

3. Corrected the plan

Our starting notes were wrong in four places. Each fix comes from the server source or the recorded session:

  1. Packet order. After login, the client asks to select a character with an empty name before it asks for the character list.
  2. Login packet. From client 1.126 on, it's just the username and password, each prefixed by its length. Not a fixed 20-byte field.
  3. Coordinates. From 1.124 on, positions are 32-bit floats in region-wide coordinates. Not 16-bit values within a zone.
  4. First packet. A 1.127 client sends its opening packet twice; the second carries an encryption key, which the server ignores when encryption is off, as it is on OpenDAoC.

We also separated three version numbers that are easy to mix up: the client/protocol version (1.127), the game rules era the server recreates (1.65), and the server software release (2026.09.36). Our client only has to speak one protocol version.

Next

The C# protocol library: checksum, packet framing, then login, tested against our server and against the recorded session.