Skip to content

aowlspt_debugui.h

Source: abi/aowlspt_debugui.h — 1105 lines, 69 file-scope functions.

What this header owns

Reproduced verbatim from the header's own banner comment — these notes are frequently the only written record of why the subsystem is shaped the way it is.

text
 aowlspt_debugui.h -- the C half of the in-game, UNITY-NATIVE debug overlay:
a Minecraft-F3-style info panel and in-world markers over AI bots.

===========================================================================
WHY THIS IS NOT A D3D OVERLAY
===========================================================================

The host already HAS a D3D11 Present overlay (`aowlspt_overlay.h`), and it is
the wrong tool for this job: it draws into the swapchain after Unity is done,
so it knows nothing about the game's canvas, its scaling, its fonts, or --
decisively -- where a bot is on screen. What is wanted here is a panel the
GAME renders: real Unity UI, in the real canvas, in the game's own font,
scaling with the game's own resolution.

Post-1.0 that used to be impossible, because IL2CPP reflection on this build
is dead (`il2cpp_object_get_class`, `il2cpp_class_get_name`, `il2cpp_value_box`
and field iteration all FAULT -- the P2-P5 verdict). It stopped being
impossible when `abi/aowlspt_invoke2.h` established that IL2CPP AOT-compiles
every managed method into an ordinary native function which can be CALLED
DIRECTLY at its RVA, with a plain Win64 convention plus a hidden trailing
`const MethodInfo*`. This header is the first real FEATURE built on that.

===========================================================================
THE UI-CREATION PATH: CLONE, NOT NEW
===========================================================================

`il2cpp_object_new` + `GameObject::.ctor` + `AddComponent<T>` is a chain of
three things, two of which are unproven on this build (the generic
`MethodInfo*` for `AddComponent<T>` is read from a LAZY .data cache slot that
is NULL until TMP's own default-control code has run, and the
`AddComponent(Type)` route needs `il2cpp_class_get_type` /
`il2cpp_type_get_object` -- reflection surface).

`UnityEngine.Object::Instantiate(Object)` @ 0x52ADBE0 is ONE static call with
ONE reference argument, needs neither a `System.Type` nor a generic
`MethodInfo*`, and hands back a live clone of whatever it was given. So every
label this overlay draws is a CLONE of a label the game already built, and
the feature has no dependency on object creation at all.

The clone anchor is deliberately the most persistent label in the client:

    EFT.UI.PreloaderUI                     (the root, whole-session UI)
      + 0x020  _alphaVersionLabel  -> EFT.UI.LocalizedText
                 + 0x078  _labels  -> List<TMPro.TextMeshProUGUI>
                            + 0x010 _items -> TMP[]  + 0x020 elems -> [0]

-- i.e. the bottom-left version label. It exists in the menu AND in a raid,
it is a TextMeshProUGUI, and the host has ALREADY proven live that it can
write that component's text by raw field store (the version brand). Cloning
the COMPONENT rather than its GameObject is deliberate: Unity clones the whole
GameObject either way, but cloning the component hands back the CLONED
COMPONENT, which is the pointer the raw `m_text` write needs. Cloning the
GameObject would hand back a GameObject and leave us needing `GetComponent`,
which needs a Type again.

Parenting: `Transform::get_root` on the anchor's transform reaches the Canvas
root, whose RectTransform spans the screen -- so a corner anchor means a
SCREEN corner, which is what a layout config expects. Then
`TMP_DefaultControls::SetParentAndAlign(cloneGO, rootGO)` (static, two
GameObjects, no Type, no generic) puts the clone in the live hierarchy.

===========================================================================
THE TARGETS ADDED HERE, AND HOW THEY WERE RESOLVED
===========================================================================

Every RVA below is for `GameAssembly.dll` imagebase 0x180000000, build
1.1.0.1.46777, taken from the 185k-entry name->RVA map produced by
`tools/il2cpp_resolve.py`, and each one was then DISASSEMBLED to confirm its
argument shape before being written down. The shapes are not guesses:

 * `UnityEngine.Camera::get_main` @ 0x5260400 -- STATIC, 0 args -> Camera.
     5260400: sub rsp,0x28 ; mov rax,[rip+..] ; test rax,rax ; jne ..
     5260428: add rsp,0x28 ; jmp rax          <- lazy icall thunk, RCX unread
   Identical shape to `Screen::get_width`, which the invoke2 ladder already
   calls. RCX carries only the hidden MethodInfo*, and the body never reads it.

 * `UnityEngine.Camera::WorldToScreenPoint(Vector3)` @ 0x525F940 -- INSTANCE,
   one 12-byte struct argument and a 12-byte struct return, so Win64 puts the
   return buffer FIRST and passes the argument BY ADDRESS:
     525f940: movsd xmm0,[r8]        <- R8 = &position   (arg0, by address)
     525f951: mov [rcx],rax          <- RCX = &retbuf    (sret, hidden arg)
     525f954: mov rdi,rdx            <- RDX = this       (the Camera)
     525f99f: mov r8d,2              <- eye = Mono, hardcoded: this IS the
     525f9ad: call rax                  one-argument overload
   so the call is (retbuf, this, &pos, MethodInfo*) and R9 (the MethodInfo) is
   used as scratch by the body -- never read. NOTE the sibling at 0x525F700 is
   the TWO-argument overload (`..., MonoOrStereoscopicEye`), whose R9 is the
   EYE and whose MethodInfo goes on the stack; calling that one by mistake
   would pass a garbage eye, which is exactly why both were disassembled.

 * `UnityEngine.RectTransform::set_anchoredPosition` @ 0x52B5490,
   `set_anchorMin` @ 0x52B5310, `set_anchorMax` @ 0x52B53D0,
   `set_pivot` @ 0x52B5610 -- INSTANCE, one Vector2. A Vector2 is EIGHT bytes,
   so Win64 passes it BY VALUE in an integer register, and all four bodies
   agree:
     52b549d: mov rbx,rcx            <- RCX = this
     52b54a0: mov [rsp+0x20],rdx     <- RDX = the Vector2, packed
     52b54c2: lea rdx,[rsp+0x20]     <- spilled, then passed by address to
     52b54ca: call rax                  the icall
   so the call is (this, <two floats packed into one uint64>, MethodInfo*).
   `aowl_du_call_setvec2` builds that uint64 with memcpy rather than a union
   cast, so it is well-defined and endianness-explicit: x in the LOW half.

 * `UnityEngine.Component::get_transform` @ 0x73B0F0 and
   `UnityEngine.Transform::get_root` @ 0x52B9C50 -- INSTANCE, 0 args ->
   reference. The exact shape of `Component::get_gameObject` @ 0x11F57E0 that
   invoke2 STEP 1 already proved live, so they reuse its thunk.

 * `EFT.UI.PreloaderUI::Update` @ 0x1569F20 -- the per-frame Unity-thread
   anchor this whole feature hangs off. PreloaderUI is the ROOT UI
   MonoBehaviour: it owns the version label, the FPS counter, the console and
   the notifier, it is alive from the preloader through the menu and through a
   raid, and its `Update` is an ordinary MonoBehaviour tick. Its prologue is
   `mov rax,rsp ; mov [rax+0x10],rbx ; mov [rax+0x20],rsi ; mov [rax+8],rcx ;
   push rdi` -- sixteen bytes with no RIP-relative operand, so the detour
   engine's copier relocates it cleanly. RCX = the live PreloaderUI, which is
   simultaneously the frame tick AND the clone anchor.

   It is used in preference to `TarkovApplication::Update` @ 0x977B10
   deliberately: that one has a live crash in its history (see the host
   internals note), and it does not hand us a UI object.

===========================================================================
FIELD OFFSETS
===========================================================================

Resolved OFFLINE from `Il2CppMetadataRegistration.fieldOffsets` in
GameAssembly.dll indexed by type, against the decrypted global-metadata --
the same technique that produced the botdiag and settings-UI offsets, and
self-checked on `System.String` (`_stringLength` @ 0x10, `_firstChar` @ 0x14)
before anything else was believed. NOT from live `il2cpp_field_get_offset`,
which is part of the faulting reflection API.

===========================================================================
SAFETY
===========================================================================

Nothing here calls anything on its own; it is a table, a set of thunks and a
set of guarded stores. `host/Aowlspt.Host.Il2Cpp/debugui.nim` drives it, from
inside the PreloaderUI::Update detour (Unity thread), with the entire body
under the `aowl_p_p_seh` VEH/setjmp guard, every pointer hop
`aowl_is_readable`-guarded, every iteration capped, and both features
flag-gated default-OFF. A fault is caught, logged and skipped; it can never
take the client down.

Constants

  • AOWLSPT_DEBUGUI_H
  • AOWL_DU_ARR_ELEMS
  • AOWL_DU_CAMERA_MAIN
  • AOWL_DU_CANVAS_MODE
  • AOWL_DU_CANVAS_ORDER
  • AOWL_DU_CANVAS_SCALE
  • AOWL_DU_GET_ANCHOREDPOS
  • AOWL_DU_GET_ANCHORMIN
  • AOWL_DU_GET_LOCALPOS
  • AOWL_DU_GET_LOCALSCALE
  • AOWL_DU_GET_PARENT
  • AOWL_DU_GET_PIVOT
  • AOWL_DU_GET_RECT
  • AOWL_DU_GET_ROOT
  • AOWL_DU_GET_SIZEDELTA
  • AOWL_DU_GET_TRANSFORM
  • AOWL_DU_GO_ACTIVEINHIER
  • AOWL_DU_GO_ACTIVESELF
  • AOWL_DU_GO_LAYER
  • AOWL_DU_GW_LOCATIONID
  • AOWL_DU_KEYSLOTS
  • AOWL_DU_LIST_ITEMS
  • AOWL_DU_LIST_SIZE
  • AOWL_DU_LOC_LABELS
  • AOWL_DU_MC_PREVPOS
  • AOWL_DU_MC_ROTATION
  • AOWL_DU_PRELOADER_UPDATE_RVA
  • AOWL_DU_PRE_VERSIONLABEL
  • AOWL_DU_REVERIFY_MS
  • AOWL_DU_SET_ANCHOREDPOS
  • AOWL_DU_SET_ANCHORMAX
  • AOWL_DU_SET_ANCHORMIN
  • AOWL_DU_SET_LOCALPOS
  • AOWL_DU_SET_LOCALSCALE
  • AOWL_DU_SET_PIVOT
  • AOWL_DU_SET_SIZEDELTA
  • AOWL_DU_STR_CHARS
  • AOWL_DU_STR_LEN
  • AOWL_DU_TARGET_COUNT
  • AOWL_DU_TMP_AUTOSIZE
  • AOWL_DU_TMP_DIRTY
  • AOWL_DU_TMP_FIRSTVIS
  • AOWL_DU_TMP_FONTCOLOR
  • AOWL_DU_TMP_FONTSIZE
  • AOWL_DU_TMP_GCANVAS
  • AOWL_DU_TMP_GCOLOR
  • AOWL_DU_TMP_GRECT
  • AOWL_DU_TMP_HALIGN
  • AOWL_DU_TMP_MARGIN
  • AOWL_DU_TMP_MAXVISCHARS
  • AOWL_DU_TMP_MAXVISLINES
  • AOWL_DU_TMP_MAXVISWORDS
  • AOWL_DU_TMP_OVERFLOW
  • AOWL_DU_TMP_PAGE
  • AOWL_DU_TMP_RECT
  • AOWL_DU_TMP_TEXT
  • AOWL_DU_TMP_TEXTALIGN
  • AOWL_DU_TMP_VALIGN
  • AOWL_DU_TMP_WORDWRAP
  • AOWL_DU_WORLD_TO_SCREEN

Types

  • struct AowlDuTarget

Functions

SignatureLine
int32_t aowl_du_off_pre_versionlabel(void)236
int32_t aowl_du_off_loc_labels(void)237
int32_t aowl_du_off_list_items(void)238
int32_t aowl_du_off_list_size(void)239
int32_t aowl_du_off_arr_elems(void)240
int32_t aowl_du_off_tmp_text(void)241
int32_t aowl_du_off_tmp_fontsize(void)242
int32_t aowl_du_off_tmp_fontcolor(void)243
int32_t aowl_du_off_tmp_dirty(void)244
int32_t aowl_du_off_tmp_rect(void)245
int32_t aowl_du_off_mc_prevpos(void)246
int32_t aowl_du_off_mc_rotation(void)247
int32_t aowl_du_off_gw_locationid(void)248
int32_t aowl_du_off_tmp_gcolor(void)249
int32_t aowl_du_off_tmp_gcanvas(void)250
int32_t aowl_du_off_tmp_autosize(void)251
int32_t aowl_du_off_tmp_halign(void)252
int32_t aowl_du_off_tmp_valign(void)253
int32_t aowl_du_off_tmp_textalign(void)254
int32_t aowl_du_off_tmp_wordwrap(void)255
int32_t aowl_du_off_tmp_overflow(void)256
int32_t aowl_du_off_tmp_firstvis(void)257
int32_t aowl_du_off_tmp_maxvischars(void)258
int32_t aowl_du_off_tmp_maxviswords(void)259
int32_t aowl_du_off_tmp_maxvislines(void)260
int32_t aowl_du_off_tmp_page(void)261
int32_t aowl_du_off_tmp_margin(void)262
void aowl_du_fn_full(int32_t i)605
void aowl_du_fn(int32_t i)648
char aowl_du_name(int32_t i)661
uint32_t aowl_du_rva(int32_t i)665
int32_t aowl_du_target_count(void)669
int32_t aowl_du_profull_count(void)670
int32_t aowl_du_ok_count(void)675
int32_t aowl_du_bad_count(void)676
int32_t aowl_du_tried_count(void)680
void aowl_du_preloader_update_target(void)701
uint32_t aowl_du_preloader_update_rva(void)733
void aowl_du_call_v_pb(void* fn, void* self, int32_t b)750
void aowl_du_call_p_v(void* fn)756
void aowl_du_call_p_p(void* fn, void* self)765
void aowl_du_call_setvec2(void* fn, void* self, double x, double y)776
int32_t aowl_du_world_to_screen(void* fn, void* cam, double wx, double wy, double wz)808
uint64_t aowl_du_call_u_p(void* fn, void* self)832
double aowl_du_vec2_x(uint64_t packed)836
double aowl_du_vec2_y(uint64_t packed)839
int32_t aowl_du_call_i_p(void* fn, void* self)845
double aowl_du_call_f_p(void* fn, void* self)850
int32_t aowl_du_call_sret_p(void* fn, void* self, int32_t nfloats)865
int32_t aowl_du_call_sret_p_v3(void* fn, void* self, double ax, double ay, double az, int32_t nfloats)890
double aowl_du_sret_0(void)909
double aowl_du_sret_1(void)910
double aowl_du_sret_2(void)911
double aowl_du_sret_3(void)912
void aowl_du_call_setvec3(void* fn, void* self, double x, double y, double z)919
int32_t aowl_du_string_len(void* s)930
double aowl_du_screen_x(void)942
double aowl_du_screen_y(void)943
double aowl_du_screen_z(void)944
int32_t aowl_du_writable(void* p, int32_t off, size_t n)957
int32_t aowl_du_write_i32(void* p, int32_t off, int32_t v)976
int32_t aowl_du_write_u8(void* p, int32_t off, int32_t v)981
int32_t aowl_du_write_f32(void* p, int32_t off, double v)987
int32_t aowl_du_write_color(void* p, int32_t off, double r, double g, double b, double a)995
int32_t aowl_du_key_edge(int32_t vk)1021
int32_t aowl_du_foreground(void)1047
void aowl_du_fps_sample(void)1076
double aowl_du_fps(void)1101
int64_t aowl_du_frame_no(void)1102

aoughwl — self-hosted platform for things n stuff. Contact / Support on Discord for access to the private backends.