RUEN
Start a project

Engineering case

Game client automation

A panel, a loader agent and a module inside the game process: performs in-game actions without a human and hides the signs that the client already knows this machine.

parts, one shared layer
3
bits, mandatory
32
protocol description
1

Three parts: a panel, a loader agent on the machine, and a module inside the game process with an overlay interface. The module performs in-game actions without a human; hardware identifiers are substituted at the level of system queries — without that the client recognises the machine.

Three parts, one description of the protocol

Panel, agent and client module are separate executables with separate lifecycles. Everything shared lives in its own header layer: the startup protocol, environment handling, logging, the crash handler.

The description therefore lives in one place for three parts. Three separate implementations would drift apart on the first changed field — and the drift would surface not at build time but at run time, when one part no longer understands another.

Startup is a handshake, not a blind wait

Paths, the log directory, the proxy address and the substitution flags reach the module through environment variables, while readiness travels through named events: the agent says “I am ready”, the client module says “I am loaded”.

The obvious route — wait a second and carry on — breaks on a slow machine and on a fast one: too early in the first case, wasted time in the second. An event removes the question: we wait exactly until ready.

The build is forced to 32-bit, and the build itself says so

The game client is 32-bit, so the module has to be as well. The build configuration checks this and emits a warning at configure time if another architecture is selected.

Otherwise the mistake surfaces late and reads as nonsense — the build succeeds and the module simply refuses to load into the other process. An hour of searching against one line of warning.

Its own crash handler

A crash inside someone else’s process leaves no usable report: the game just closes. So the shared layer carries a handler of its own — a memory dump through the system debug library, interception of unhandled exceptions, allocation failures and signals, and its own log next to it.

Without it the only evidence of a failure would be “everything closed on me”.

The interface lives inside the game

The overlay is built on Dear ImGui and drawn inside the game window; entry points are patched with MinHook. Both libraries are fetched by the build at a pinned version — a specific tag, not “whatever is newest”.

For a project that lives for years and is built rarely, that is the difference between “it built as it did back then” and “it built out of something unknown”.

Each copy routes its traffic separately

The shared layer holds a proxy client, SOCKS5 and tunnel startup: every copy reaches the network its own way. This is part of the same task — the machines have to look independent rather than like one.

What was done in a hurry

The environment variable names for substitution are duplicated across two headers to break a circular include, and they are kept in sync by hand. The code says so plainly — but nothing checks that they have not drifted apart.

C++20 · CMake · MSVC · Dear ImGui · MinHook · Windows API