Aion DPS

Passive combat tracking with Npcap and .NET 10

Most damage meters get their numbers by reading the game's memory or by injecting a hook into the game process. That works, but it is fragile (every patch moves addresses), it can get you banned, and anti-cheat software has good reasons to dislike it. Aion DPS Meter takes the other route for AION 2: it never touches the game process. It listens to the game's own network traffic on your machine, the way a packet analyser would, and rebuilds the combat log from that. This article describes the architecture, the pitfalls and what we would do again.

The principle

The server already tells your client everything: who hit whom, for how much, who healed, who died. If you can read those bytes, you do not need the game process at all. The meter only ever receives a copy of packets that already arrived; it never sends one.

The capture layer: SharpPcap on Npcap

On Windows, Npcap is the packet capture driver, and SharpPcap is its .NET wrapper, with PacketDotNet to parse the headers. The meter targets .NET 10, and the capture loop is small:

  1. Listen on the network adapters. By default that is every adapter, because a player may have Wi-Fi, Ethernet and a VPN at once.
  2. Set a BPF filter in the driver, so only the game server's TCP traffic reaches user mode. Everything else is dropped in the kernel and costs us nothing.
  3. In the callback, parse the headers, build a small segment record (stream key, TCP sequence number, payload) and hand it on.

Two lessons from production:

Keep the callback tiny. Our first version decoded frames inside the capture callback. During a world boss fight the burst of traffic overflowed the driver's buffer and packets were lost. Now the capture threads only parse and enqueue into a bounded queue, a single worker does the decoding, and the kernel buffer is raised to 32 MB. A packet lost at capture time is the one failure you cannot repair later.

Never let one bad packet end the capture thread. An unhandled exception inside a capture callback can silently stop capturing. We count and skip the failures and show the last error in the interface instead.

From segments to frames: TCP reassembly

A game frame does not line up with a TCP segment. One segment can carry several frames, and one frame can span several segments. So the next layer is a small TCP reassembler:

That last point matters: design for loss on the capture side. A meter that stops working after the first missed packet is a meter nobody trusts.

Decoding: understanding the protocol

Once you have frames, the work is reverse engineering what they mean: which message is which, how the fields are laid out, which frames are compressed, which numbers are damage and which are healing. That part is patient observation rather than clever engineering: record a session, fight one known enemy, and compare what you did with what the stream says. Two habits made it tractable:

We deliberately do not publish message tables or field layouts here. They change with every patch, and the interesting part is the method.

What this design cannot do

Why we would choose it again

The source code is MIT licensed: github.com/SkeeveAN/Aion-DPS-Meter. The meter, the leaderboards and the feature tour are on aiondps.com, and how it compares with other AION 2 meters is written down as well. Every push runs the type check and all backend tests in public and builds the client: the test results.