Skip to content

aowlspt_botdiag.h

Source: abi/aowlspt_botdiag.h — 190 lines, 19 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_botdiag.h -- READ-ONLY GameWorld bot/player census for the post-1.0
EFT host. A DIAGNOSTIC instrument, nothing more.

The one question it answers, during an offline raid: are AI bots actually
spawned into the live `EFT.GameWorld` (registered, positioned) or truly
absent? It is a logger. It never writes game state, never renders, never
changes gameplay -- it locates one method, reads a list of players by fixed
IL2CPP field offsets, and prints counts + positions to the host log. Same
reflection-free discipline as the version brand and the Phase 1 settings probe
(static-RVA detour, `cIsReadable`-guarded raw hops, decode strings by raw
layout, log). Reflection (`il2cpp_*` class/name/box/field iteration) is DEAD
on this build; only raw static offsets are used here.

## What it hooks

  `EFT.GameWorld::RegisterPlayer` @ RVA 0x25038C0 (imagebase 0x180000000,
  build 1.1.0.1.46777). Called once per player/bot as it is registered into
  the world -- so a detour here is definitive per-spawn evidence: RCX = the
  live `GameWorld` (`this`), RDX = the `IPlayer` being registered. Each fire
  logs the incoming player, and (throttled) enumerates the whole registered
  list so the running census is visible. GameWorld exists only inside a raid,
  so this fires only in-raid, exactly where the question is asked.

`OnGameStarted` @ 0x2508000 was rejected as a second one-shot target: its
compiled prologue has a conditional branch (`je`) within the first 16 bytes
(`48 8B 89 30 01 00 00  48 85 C9  74 0F ...`), which the detour engine's
length decoder cannot relocate. The whole-list enumerate is therefore driven
from inside the RegisterPlayer detour instead, which is strictly more
informative (a census after every registration, not just once).

The RegisterPlayer prologue relocates cleanly:
  40 56               push rsi
  41 57               push r15
  48 81 EC 88 00 00 00  sub rsp, 0x88
  80 3D 42 F6 BB ..   cmp byte [rip+0xBBF642], 0
The first three instructions (11 bytes, no RIP-relative operand, no branch)
are a clean whole-instruction steal for the trampoline; the `cmp`'s disp32 is
included in the signature only to pin the build, not stolen. On any other
build the bytes differ, the guard fails, and NULL is returned -- a missed
bind, never a corrupted game.

## The offsets (from tools/il2cpp_resolve.py `fields`, build 1.1.0.1.46777,
   Il2CppMetadataRegistration.fieldOffsets @ 0x186B61E70, imagebase 0x180000000)

  EFT.GameWorld
    + 0x1C8  AllAlivePlayersList   List<Player>    (alive players)
    + 0x1D0  RegisteredPlayers     List<IPlayer>   (every registered player)
    + 0x230  MainPlayer            Player          (the local player)

  List<T>  (fixed IL2CPP layout, same as every generic List)
    + 0x10   _items -> T[]        + 0x18   _size (int32);  T[] elems @ +0x20

  EFT.Player
    + 0x60   MovementContext       MovementContext
    + 0x9C0  Profile               Profile
    + 0xA00  AIData                IAIData     (non-null => AI-controlled bot)
    + 0xB89  IsYourPlayer          bool        (the local player)
  EFT.MovementContext
    + 0x370  PreviousPosition      Vector3     (3x float32 -- raw-readable
             world position; BifacialTransform.position is a delegate, not a
             field, so this cached Vector3 is the reflection-free source)
  EFT.Profile          + 0x48   Info -> ProfileInfo
  EFT.ProfileInfo      + 0x10   Nickname (System.String) + 0x48 Side
                                 (EPlayerSide int32) + 0x78 Settings
  EFT.ProfileSettings  + 0x10   Role (WildSpawnType int32) + 0x14 BotDifficulty

All of these are CANDIDATES until the live read-only log shows a sane census
(a known nickname, a plausible position); the log is their validation. No
write is ever performed regardless.

Constants

  • AOWLSPT_BOTDIAG_H
  • AOWL_BD_ARR_ELEMS
  • AOWL_BD_GW_ALIVELIST
  • AOWL_BD_GW_MAINPLAYER
  • AOWL_BD_GW_REGPLAYERS
  • AOWL_BD_INFO_NICKNAME
  • AOWL_BD_INFO_SETTINGS
  • AOWL_BD_INFO_SIDE
  • AOWL_BD_LIST_ITEMS
  • AOWL_BD_LIST_SIZE
  • AOWL_BD_MC_PREVPOS
  • AOWL_BD_PL_AIDATA
  • AOWL_BD_PL_ISYOU
  • AOWL_BD_PL_MOVECTX
  • AOWL_BD_PL_PROFILE
  • AOWL_BD_PROF_INFO
  • AOWL_BD_SET_ROLE
  • AOWL_BOTDIAG_TARGET_COUNT

Types

  • struct AowlBotDiagTarget

Functions

SignatureLine
int32_t aowl_bd_off_gw_alivelist(void)106
int32_t aowl_bd_off_gw_regplayers(void)107
int32_t aowl_bd_off_gw_mainplayer(void)108
int32_t aowl_bd_off_list_items(void)109
int32_t aowl_bd_off_list_size(void)110
int32_t aowl_bd_off_arr_elems(void)111
int32_t aowl_bd_off_pl_movectx(void)112
int32_t aowl_bd_off_pl_profile(void)113
int32_t aowl_bd_off_pl_aidata(void)114
int32_t aowl_bd_off_pl_isyou(void)115
int32_t aowl_bd_off_mc_prevpos(void)116
int32_t aowl_bd_off_prof_info(void)117
int32_t aowl_bd_off_info_nickname(void)118
int32_t aowl_bd_off_info_side(void)119
int32_t aowl_bd_off_info_settings(void)120
int32_t aowl_bd_off_set_role(void)121
void aowl_botdiag_target_at(int32_t i)156
char aowl_botdiag_target_name(int32_t i)182
int32_t aowl_botdiag_target_count(void)187

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