Appearance
aowlspt_unitypp.h
Source: abi/aowlspt_unitypp.h — 504 lines, 11 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_unitypp.h -- Unity Post Processing Stack v2, READ-ONLY DISCOVERY.
===========================================================================
WHY THIS FILE EXISTS
===========================================================================
`mods/graphics` renders nothing itself. The renderer is native D3D11 in
`abi/aowlspt_graphics.h`, hooked off the overlay's Present: it copies the
FINISHED back buffer and grades it. That is post-hoc -- it fights the game's
own rendering, it is ordered after everything including the UI, and it has
no honest access to depth or motion vectors. The standing instruction is to
stop doing that and drive the game's OWN post-processing instead.
So the first question is not "how do we write the grade", it is "what post
processing does THIS build actually have". That was answered OFFLINE, before
a line of this file was written, with `tools/il2cpp_resolve.py` and
`tools/fldoff.py` against D:/Aowlspt/GameAssembly.dll and the decrypted
global-metadata. The answer:
Unity.Postprocessing.Runtime.dll IS PRESENT AND UNSTRIPPED.
118 types in namespace `UnityEngine.Rendering.PostProcessing`, including
every one that matters here:
PostProcessLayer PostProcessVolume PostProcessProfile PostProcessManager
PostProcessEffectSettings PostProcessBundle PostProcessRenderContext
ColorGrading Bloom Vignette Grain ChromaticAberration AmbientOcclusion
DepthOfField MotionBlur LensDistortion AutoExposure ScreenSpaceReflections
TemporalAntialiasing SubpixelMorphologicalAntialiasing Fog Dithering
plus the whole ParameterOverride family (FloatParameter, BoolParameter,
ColorParameter, Vector2/3/4Parameter, IntParameter, SplineParameter,
TextureParameter, and the enum-typed TonemapperParameter / GradingModeParameter
/ VignetteModeParameter / KernelSizeParameter).
That is the real answer to "does the stack exist", and it means the D3D11
path can eventually be retired rather than merely wrapped.
===========================================================================
THE OFFSETS -- AND THE ONE THAT IS NOT KNOWABLE OFFLINE
===========================================================================
All of these come from `Il2CppMetadataRegistration.fieldOffsets` via
`tools/fldoff.py fields <Type>`, whose mandatory self-check
(System.String._stringLength@0x10, _firstChar@0x14) passed. None is guessed.
PostProcessVolume sharedProfile @0x20 PostProcessProfile
isGlobal @0x28 bool
blendDistance @0x2C float
weight @0x30 float
priority @0x34 float
m_InternalProfile @0x48 PostProcessProfile
PostProcessProfile settings @0x18 List<PostProcessEffectSettings>
isDirty @0x20 bool
PostProcessEffectSettings active @0x18 bool
enabled @0x20 BoolParameter
parameters @0x28 ReadOnlyCollection<ParameterOverride>
ColorGrading (: EffectSettings)
gradingMode @0x30 temperature @0x88
tonemapper @0x40 tint @0x90
toneCurveToeStrength @0x48 colorFilter @0x98
ldrLutContribution @0x80 hueShift @0xA0
saturation @0xA8 brightness @0xB0
postExposure @0xB8 contrast @0xC0
lift @0x110 gamma @0x118 gain @0x120
Vignette (: EffectSettings) mode @0x30 color @0x38 center @0x40
intensity @0x48 smoothness@0x50 roundness@0x58
rounded @0x60 mask @0x68 opacity @0x70
ParameterOverride (NON-generic base)
overrideState @0x10 bool <-- REAL
---- THE HOLE, STATED PLAINLY -------------------------------------------
`FloatParameter` declares NO fields of its own. Its value lives in
`ParameterOverride<T>.value`, and `fldoff.py` reports that field as
GENERIC -- NO LAYOUT: uninstantiated generic type definition
which is CLAUDE.md 5's three-state offset rule biting exactly where it says
it will. IL2CPP writes an all-zero fieldOffsets array for `ParameterOverride`1`;
the concrete layout of `ParameterOverride<float>` is built at runtime and
every `Il2CppGenericClass.cached_class` in GameAssembly.dll is null. It is
NOT reachable offline, and no amount of reading the file will change that.
The obvious inference is `value @ 0x14` (bool at 0x10, float padded to its
natural 4-byte alignment). It is PROBABLY right. It is still an INFERENCE,
and a wrong offset here does not fault -- it reads a plausible float and then
a WRITE at that offset corrupts a live managed object every frame. That is
precisely the failure this project keeps paying for, so:
THIS FILE DOES NOT WRITE. NOT ONE BYTE.
It PROBES: it walks to the live profile, names every effect it finds by
reading the object's own klass, and for ColorGrading it dumps the raw bytes
of `saturation` and `postExposure` at 0x10..0x20 into the host log. Two
FloatParameters with different, known-different authored values settle the
`value` offset from the log in ONE run, empirically, with no guess surviving.
Only after that run may a write path be built -- in a follow-up.
===========================================================================
BORROWED LAYOUTS (said out loud, as required)
===========================================================================
List<T> _items @0x10 -> T[], _size @0x18 (int32)
T[] element 0 @0x20
BORROWED from `abi/aowlspt_botdiag.h` and `abi/aowlspt_debugui.h`, which have
both used this shape against live objects in this client. It is an
instantiated generic layout and therefore, per the rule, not offline-derivable
either. Every element read below is bounds-checked against `_size` AND capped,
and every element pointer is klass-named before anything is read through it,
so a wrong borrow produces a refusal in the log rather than a fabricated tree.
===========================================================================
TYPE CONFUSION IS THE REAL ENEMY, NOT UNREADABILITY
===========================================================================
`aowl_admin_readable()` proves a page is mapped. It does not prove the object
is what you think, and Unity's FAKE NULL means a live-looking managed pointer
can wrap a destroyed native object. So every hop here is checked TWICE:
readable, and then IDENTIFIED by `aowl_comp_klass_fullname()` -- the same
klass->name/namespace reader the inspector's `component` verb uses. A pointer
whose klass does not name a PostProcessing type is refused by name in the log.
That is the check that can actually fail, which is the only kind worth having.
===========================================================================
THE EIGHT RULES
===========================================================================
1. Prologue byte-verify -- inherited. The only game code called is
`Component::GetComponent(String)` @0x52A48E0, bound and 16-byte verified
by `abi/aowlspt_navui.h`, and the camera acquisition in
`abi/aowlspt_admin.h` (AOWL_ADM_SIG_CAM_MAIN / _CAM_MGR). No new RVA is
introduced and nothing new is bound.
2. VirtualQuery on EVERY hop -- `aowl_admin_readable` before each read.
3. ONE `aowl_p_p_seh`, opened by `aowl_upp_tick` around the whole body.
`aowl_upp_scan_body` opens NONE. Nesting would disarm the outer guard.
4. Capped -- AOWL_UPP_MAX_EFFECTS effects, AOWL_UPP_NAME_MAX name bytes.
5. Flag-gated, default OFF -- `unityPostProbe`.
6. Self-disable after AOWL_UPP_MAXFAULT faults.
7. No managed allocation. Ever. No `il2cpp_string_new` in the tick either:
the GetComponent argument string is created ONCE, on the first tick, and
cached in a static.
8. Never blind-write -- vacuously, since it never writes.
The probe runs ONCE and latches. It is a survey, not a per-frame feature.
===========================================================================
PREREQUISITES
===========================================================================
Same translation unit as `aowlspt_admin.h` (for `aowl_admin_cam_object`,
`aowl_admin_readable`) and `aowlspt_components.h` (for the klass namer), and
after `aowlspt_region.h` for `aowl_region_sayf`. That is region.nim, and only
region.nim.Constants
AOWLSPT_UNITYPP_HAOWL_UPP_ARR_ELEM0AOWL_UPP_CG_CONTRASTAOWL_UPP_CG_POSTEXPOSUREAOWL_UPP_CG_SATURATIONAOWL_UPP_LIST_ITEMSAOWL_UPP_LIST_SIZEAOWL_UPP_MAXFAULTAOWL_UPP_MAX_EFFECTSAOWL_UPP_PARAM_OVERRIDESTATEAOWL_UPP_PROF_SETTINGSAOWL_UPP_RVA_GETCOMPONENTAOWL_UPP_SET_ACTIVEAOWL_UPP_SET_ENABLEDAOWL_UPP_VOL_INTERNALPROFILEAOWL_UPP_VOL_ISGLOBALAOWL_UPP_VOL_PRIORITYAOWL_UPP_VOL_SHAREDPROFILEAOWL_UPP_VOL_WEIGHT
Functions
| Signature | Line |
|---|---|
void aowl_upp_bind(void) | 232 |
int32_t aowl_upp_is_done(void) | 266 |
int32_t aowl_upp_is_disabled(void) | 267 |
int32_t aowl_upp_effect_count(void) | 268 |
int32_t aowl_upp_has_grading(void) | 269 |
int32_t aowl_upp_fault_count(void) | 270 |
int32_t aowl_upp_identify(const void *obj) | 275 |
void aowl_upp_dump_param(const char *what, const void *p) | 289 |
int32_t aowl_upp_walk_profile(const void *profile, const char *origin) | 322 |
void aowl_upp_scan_body(void *unused) | 400 |
void aowl_upp_tick(void) | 485 |

