Skip to content

aowlspt_settingswrite.h

Source: abi/aowlspt_settingswrite.h — 407 lines, 24 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_settingswrite.h -- Phase 2/3 layout for WRITING into Tarkov's real
SettingsScreen.

`aowlspt_settingsui.h` is the READ side and stays read-only; this header is
its write-side sibling and carries exactly two things:

  1. the value-field offsets of the four concrete setting WIDGETS, so a
     control's current value can be read and a new one written by raw field
     access -- no reflection, which is dead on this build;
  2. one guarded byte reader, the missing sibling of the guarded writers that
     `aowlspt_debugui.h` already provides (`aowl_du_write_u8` /
     `aowl_du_write_f32`) and `aowlspt_uxpatch.h` provides for references
     (`aowl_uxpatch_write_ptr`).

## Where these numbers came from

All of them were re-derived offline from `Il2CppMetadataRegistration.
fieldOffsets` with `tools/il2cpp_resolve.py fields <Type>` against
GameAssembly.dll + the DECRYPTED global-metadata, build 1.1.0.1.46777,
imagebase 0x180000000 -- the same tool and the same run that reproduces the
`System.String` self-check (`_stringLength`@0x10, `_firstChar`@0x14) and every
offset already in `aowlspt_settingsui.h`.

The decisive structural fact the resolver confirmed for all four widget types
at once: EVERY concrete `SettingControl` subclass carries its widget at the
SAME offset, +0xA8, because they all inherit the identical base field run and
each declares exactly one field of its own:

  EFT.UI.Settings.SettingToggle       +0xA8  Toggle    -> EFT.UI.UpdatableToggle
  EFT.UI.Settings.SettingFloatSlider  +0xA8  Slider    -> EFT.UI.NumberSlider
  EFT.UI.Settings.SettingSelectSlider +0xA8  Slider    -> EFT.UI.SelectSlider
  EFT.UI.Settings.SettingDropDown     +0xA8  DropDown  -> EFT.UI.DropDownBox

That is why `AOWL_SUI_CTRL_VALUE` (0xA8) in the read header is correct for
every control the live probe walked, and why the widget object at +0xA8 needs
no per-type dispatch to FETCH -- only to INTERPRET.

## Telling the four apart without reflection

`il2cpp_object_get_class` and `il2cpp_class_get_name` both fault on this
build, so the type of a control cannot be asked for. It can, however, be
OBSERVED: the klass pointer in the object header (obj+0x00) is stable within
one process, and the live Phase-1.8 census found exactly FOUR distinct values
across all 78 controls on the real screen (dropdown 38, toggle 19, float
slider 13, select slider 8). The absolute values differ per launch, so the
host learns them per session by matching a control whose stock label is known
-- see `AOWL_SW_ANCHOR_*` below -- and then groups every other control by
klass identity. That is the whole discriminator: pointer equality, no names.

## The value fields

UpdatableToggle derives from UnityEngine.UI.Toggle, whose backing field is
`m_IsOn`@0x120 (bool). NumberSlider wraps a UnityEngine.UI.Slider it holds at
`_slider`@0x80, and the value lives on that Slider as `m_Value`@0x120 (float),
bounded by `m_MinValue`@0x114 / `m_MaxValue`@0x118 and quantised by
`m_WholeNumbers`@0x11C. NumberSlider ALSO keeps its own display bounds at
`_minValue`@0x9C / `_maxValue`@0x98, which are what the game clamps typed
input against.

## What a raw write does and does not do

Writing `m_IsOn` or `m_Value` changes the MODEL, not the pixels: Unity
repaints a Toggle from `Toggle::Set` and a Slider from
`Slider::UpdateVisuals`, neither of which a field store calls. So a raw value
write is correct for READING the user's choice and for seeding a control, and
it is NOT sufficient to move a checkmark on screen. The text path is the
exception and the reason Phase 2a leads with it: TMP repaints from a plain
dirty flag (`m_havePropertiesChanged`@0x378), so a String store plus that one
byte IS a complete, visible edit -- which is exactly why the version brand
works today, and why relabelling is the honest first proof that we can write
into the real settings screen.

CORRECTION, from the live run. That last paragraph is true of the version
label and of the debug overlay's own clones, and it was NOT true of a settings
row. The log proved `m_text` held our String (Phase 2b read the value back
THROUGH the new label) and the row on screen still said 'FOV:'. A settings
label is not a bare TMP: it sits behind an `EFT.UI.LocalizedText`, which
re-applies its own localised string, and the raw store is behind that class's
back. So the relabel now CALLS `EFT.UI.LocalizedText::SetLabelText` and
`TMPro.TMP_Text::set_text` (both added to the target table below) and keeps
the raw store only as the last resort on a build where neither verifies.
The lesson generalises: prefer calling the managed setter to poking a field.

Fail-safe, like every other write in this codebase: nothing here dereferences
anything. The reader below VirtualQueries first and returns a miss rather than
faulting, and every caller on the Nim side is additionally inside the
`aowl_p_p_seh` VEH/setjmp guard that already wraps the settings postfix body.

Constants

  • AOWLSPT_SETTINGSWRITE_H
  • AOWL_SW_ANCHOR_DROPDOWN
  • AOWL_SW_ANCHOR_FLOAT
  • AOWL_SW_ANCHOR_SELECT
  • AOWL_SW_ANCHOR_TOGGLE
  • AOWL_SW_LOC_SETLABELTEXT
  • AOWL_SW_NUMSLIDER_MAX
  • AOWL_SW_NUMSLIDER_MIN
  • AOWL_SW_NUMSLIDER_SLIDER
  • AOWL_SW_SLIDER_MAXVALUE
  • AOWL_SW_SLIDER_MINVALUE
  • AOWL_SW_SLIDER_SET_MAX
  • AOWL_SW_SLIDER_SET_MIN
  • AOWL_SW_SLIDER_SET_NONOTIFY
  • AOWL_SW_SLIDER_UPDATEVISUALS
  • AOWL_SW_SLIDER_VALUE
  • AOWL_SW_SLIDER_WHOLENUM
  • AOWL_SW_TARGET_COUNT
  • AOWL_SW_TMP_DIRTY
  • AOWL_SW_TMP_SET_DIRTY
  • AOWL_SW_TMP_SET_TEXT
  • AOWL_SW_TOGGLE_ISON
  • AOWL_SW_TOGGLE_SET_ISON
  • AOWL_SW_TOGGLE_SET_NONOTIFY

Types

  • struct AowlSwTarget

Functions

SignatureLine
char aowl_sw_anchor_float(void)134
char aowl_sw_anchor_toggle(void)135
char aowl_sw_anchor_dropdown(void)136
char aowl_sw_anchor_select(void)137
int32_t aowl_sw_read_u8(void* p, int32_t off)150
int32_t aowl_sw_off_toggle_ison(void)172
int32_t aowl_sw_off_ns_slider(void)173
int32_t aowl_sw_off_ns_min(void)174
int32_t aowl_sw_off_ns_max(void)175
int32_t aowl_sw_off_slider_value(void)176
int32_t aowl_sw_off_slider_min(void)177
int32_t aowl_sw_off_slider_max(void)178
int32_t aowl_sw_off_slider_whole(void)179
int32_t aowl_sw_off_tmp_dirty(void)180
void aowl_sw_fn(int32_t i)329
char aowl_sw_name(int32_t i)352
uint32_t aowl_sw_rva(int32_t i)356
int32_t aowl_sw_target_count(void)360
int32_t aowl_sw_ok_count(void)361
int32_t aowl_sw_bad_count(void)362
void aowl_sw_call_v_pf(void* fn, void* self, double v)373
void aowl_sw_call_v_pb(void* fn, void* self, int32_t b)383
void aowl_sw_call_v_pp(void* fn, void* self, void* arg)392
void aowl_sw_call_v_p(void* fn, void* self)400

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