Psst... Lumi the AI assistant says hi! You're awesome for using accessibility tools.Skip to content
luinbytes.dev
← Back to projects
Game ModOpen Source

perkaholic.

Hybrid trainer for BO3 Zombies under Wine/Proton. An XInput proxy DLL inside the game owns reads, writes, aim, visibility, and ESP command production. A native Wayland layer-shell overlay owns drawing and input routing. Both halves communicate through a binary IPC frame at /tmp/perkaholic-ipc.bin.

Source langs3
Internal LOC~4.3k
Overlay LOC~18k
Crates5
01 / Features

Two processes, one trainer. The DLL owns everything that needs engine state; the overlay owns everything the user sees. Neither side crashes when the other is missing.

01

Hybrid Architecture

DLL-internal hooks own fragile game state reads, writes, aimbot, and ESP command production. The native overlay owns drawing and input. Keeps engine-facing work where engine state lives and Wayland rendering out of Wine.

  • DLL lives inside the game process — no cross-process guessing for engine state
  • Overlay is a native Linux Wayland process — no Wine windowing path for drawing
  • Both halves can start and stop independently without crashing the other
  • IPC frame at /tmp/perkaholic-ipc.bin bridges the two with seq numbers and overflow tracking
02

XInput Proxy Loader

XINPUT9_1_0.dll exports the full XInput entry-point surface and defers runtime startup until BO3 calls into it. DllMain stays minimal so loader-lock under Proton cannot bite.

  • Exports XInputGetState, XInputSetState, and companion entry points
  • Runtime startup deferred to first XInput call — DllMain does nothing
  • Installed via WINEDLLOVERRIDES=xinput9_1_0=n,b in Steam launch options
  • objdump import check verifies no eager d3d / dxgi / dwmapi dependencies
03

Internal ESP Queue

DLL reads zombie slots from the Zombies actor table, projects positions with BO3 refdef, runs visibility through the internal engine path, and queues primitives into a shared draw format consumed by the overlay.

  • Zombie actor table walk — slots read from live BO3 engine state
  • World-to-screen projection via captured refdef data
  • Internal-engine visibility check where available
  • Queues boxes, lines, circles, and labels into imgui_esp_text_queue format
04

Binary IPC Frame

DLL publishes the latest draw frame to Z:\\tmp\\perkaholic-ipc.bin — the same path the Linux overlay reads as /tmp/perkaholic-ipc.bin. Seq numbers and overflow fields let the overlay detect stale frames.

  • Atomic write via temp file + rename to avoid half-read frames
  • Seq number increments every publish — overlay detects staleness by seq delta
  • Overflow field carries count when the command queue exceeds one frame
  • Publish failures (open, move, short write) are logged and ignored — no crash
05

Wayland Layer-Shell Overlay

wlr-layer-shell overlay surface sits above fullscreen toplevels. Default keyboard_interactivity=NONE with an empty input region so all events pass through to BO3. Input region recomputes only when the menu opens.

  • Layer: overlay — composited above fullscreen game surfaces
  • Empty input region by default — click-through at all times outside the menu
  • Input region set to menu rect when menu is open, cleared on close
  • No mouse grab while scanning; grab only inside the active menu rectangle
06

Aimbot + Trainer Internals

Aimbot and trainer writes run inside the game process where engine state is live. Projection, visibility, and target picking all happen engine-side. Raw memory access is a fallback diagnostic path only.

  • Aimbot target selection from the same actor table the ESP queue walks
  • Trainer writes (ammo, health, round state) go through engine paths where available
  • Internal engine visibility used for target filtering — avoids cross-process reads
  • Verbose hook log written to AppData/Local/Temp/perkaholic-internal.log
07

IPC-Only Drawing

The overlay is a pure draw-only IPC consumer. When the DLL frame is missing or stale the overlay draws nothing — it logs the transition and waits. It does not attach to BO3 and does not grab mouse input.

  • Draws nothing when the IPC frame is missing or stale — logs the transition, no crash, no scan
  • No BO3 attach and no mouse grab — click-through always, draw-only consumer
  • DLL keeps publishing even when the overlay is absent; IPC write failures are logged and ignored
  • Legacy external reader crates remain in the repo as reference/diagnostic code only, not a runtime fallback
08

Verbose Debug Trail

Both halves emit a structured log trail. The overlay prints IPC state transitions to stdout. The DLL writes every publish result to the Proton prefix log file. Import table check confirms no eager graphics dependencies.

  • Overlay: internal ipc active seq=... / internal ipc inactive or stale; falling back
  • DLL: ipc publish seq=... count=... overflow=... / ipc publish open failed ...
  • DLL log: AppData/Local/Temp/perkaholic-internal.log inside the Proton prefix
  • objdump -p XINPUT9_1_0.dll | rg 'd3d|dxgi|dwmapi' should return nothing
02 / IPC Bridge

Why the split, and how the halves coordinate

The hybrid split is not an aesthetic choice — it is forced by the constraints of Wine windowing, Wayland compositing, and BO3 engine state availability. A shared binary frame at /tmp/perkaholic-ipc.bin carries draw commands from the DLL to the overlay on every game tick.

Why hybrid

  • Wine windowing path cannot host a wlr-layer-shell surface — Wayland extension is compositor-side only
  • Engine state (actor table, refdef, visibility) is only coherent inside the game process
  • A native Linux process can create a Wayland layer-shell surface above a Wine fullscreen window
  • IPC file-based transport costs one rename per frame — cheap enough for game-tick rates

DLL responsibilities

  • Captures live BO3 engine state via internal hooks at game-tick rate
  • Reads zombie slots from the actor table; projects positions with refdef
  • Runs internal-engine visibility check for ESP and aimbot target filtering
  • Queues ESP primitives and publishes a binary draw frame to Z:\\tmp\\perkaholic-ipc.bin

Overlay responsibilities

  • Creates a wlr-layer-shell surface above fullscreen toplevels via Wayland
  • Maintains click-through (empty input region) unless the menu is open
  • Reads /tmp/perkaholic-ipc.bin each frame and draws the queued ESP primitives
  • Draws nothing when the IPC frame is missing or stale — logs the transition, does not scan for BO3

Failure modes handled

  • DLL alive, no overlay: IPC publish failures logged and ignored — game runs normally
  • Overlay alive, no DLL: overlay draws nothing, logs stale-frame transitions, no crash
  • Stale IPC frame: overlay logs the transition and draws nothing until a fresh frame arrives
  • Menu closed: full pointer pass-through — BO3 receives all mouse and keyboard events
03 / Technical Details

How it's built

C / C++

Internal DLL — hooks, BO3 engine state, refdef projection, ESP command queue (~4.3k LOC across 8 files in internal/src/)

Rust

Linux overlay process and five helper crates: overlay, game, mem, math, config (~18k LOC across the workspace)

MinGW

DLL build toolchain via make internal — cross-compiles the C/C++ DLL for Win64 from Linux

wgpu + egui

Overlay rendering through egui-wgpu on a Wayland surface — egui menu, ESP draw calls, click-through input regions

wlr-layer-shell

Overlay layer above fullscreen toplevels — conditional input region, keyboard_interactivity=NONE by default

Wine / Proton

WINEDLLOVERRIDES=xinput9_1_0=n,b loads the proxy DLL; Z: drive maps /tmp for the IPC path shared between halves

Verification path

objdump -p target/internal/XINPUT9_1_0.dll | rg 'd3d|dxgi|dwmapi' should return nothing — the DLL must not eagerly import any graphics runtime. Run make internal-test for the focused C helper tests and cargo test --workspace for the Rust crate suite. Both must pass before installing the DLL next to the game.

04 / Controls

Default binds

Default binds
InsertToggle menu open / close
aim_masterHold — master aim enable
esp_zombiesAlways — ESP on zombies
Config
~/.config/perkaholic/config.tomlShared config — overlay TOML schema
menu = "toggle"Plain string bind mode (current)

Both plain string mode (menu = "toggle") and legacy table form (menu = { key = "INSERT", mode = "toggle" }) are accepted. Config lives at ~/.config/perkaholic/config.toml.

05 / Setup

Installation

01

Build the overlay

Run cargo build --release in the repo root. The perkaholic binary lands in target/release/ and is the process you run alongside BO3.

02

Build and install the DLL

Run make internal to cross-compile the proxy DLL with MinGW, then make internal-install to copy XINPUT9_1_0.dll next to BlackOps3.exe. Verify with objdump -p target/internal/XINPUT9_1_0.dll | rg 'd3d|dxgi|dwmapi' — output should be empty.

03

Launch BO3 with the proxy override

Set the Steam launch options to: PERKAHOLIC_INTERNAL_VERBOSE=1 WINEDLLOVERRIDES=xinput9_1_0=n,b gamescope -f -r 144 -w 1920 -h 1080 -- %command%

04

Run the overlay

Start perkaholic in a terminal alongside BO3. The overlay creates the Wayland layer-shell surface immediately and begins polling the IPC file. After any rebuild, restart both the perkaholic process and BO3 so each half loads the new binaries.

Get the trainer

Open source. Grab a release build or pull the source and build both halves with cargo build --release and make internal.