Appearance
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_HAOWL_BD_ARR_ELEMSAOWL_BD_GW_ALIVELISTAOWL_BD_GW_MAINPLAYERAOWL_BD_GW_REGPLAYERSAOWL_BD_INFO_NICKNAMEAOWL_BD_INFO_SETTINGSAOWL_BD_INFO_SIDEAOWL_BD_LIST_ITEMSAOWL_BD_LIST_SIZEAOWL_BD_MC_PREVPOSAOWL_BD_PL_AIDATAAOWL_BD_PL_ISYOUAOWL_BD_PL_MOVECTXAOWL_BD_PL_PROFILEAOWL_BD_PROF_INFOAOWL_BD_SET_ROLEAOWL_BOTDIAG_TARGET_COUNT
Types
struct AowlBotDiagTarget
Functions
| Signature | Line |
|---|---|
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 |

