Properties2
| Type | Practice |
| Note created | Apr 13, 2026 |
Documentation of reverse engineering work on PES 2021’s Advanced Shooting system in SP Football Life 2026, with the goal of making shot direction relative to the player’s position and camera angle rather than fixed to the broadcast view.
Goal
Advanced Shooting maps 6 goal zones to fixed stick directions that never change regardless of camera angle or player position on the pitch. The mod would apply a 2D rotation to the stick input based on the angle between the player→goal vector and the camera orientation, making aiming intuitive from any approach angle.
Installation Layout
The working installation is on the Windows PC (korolev) at D:\SP Football Life 2026\. An unmodified copy sits at D:\SP Football Life 2026 - original\ for safe binary analysis.
| Component | Location |
|---|---|
| Game executable | FL_2026.exe (438 MB, renamed PES2021.exe) |
| Sider | SiderAddons/ (sider.dll, LuaJIT enabled) |
| Lua modules | SiderAddons/modules/ (~40 modules) |
| RE workspace | C:\RE\pes21\ (scripts, scan data, analysis outputs) |
Key DLLs at Runtime
| DLL | Address | Role |
|---|---|---|
FL_2026.exe | 0x140000000 | Main game (image base) |
xinput1_3.dll | 0x560000 | Controller input (XInput) |
dinput8.dll | 0x7FFB33D40000 | Sider’s proxy DLL |
sider.dll | 0x7FFB2C0D0000 | Mod framework |
PES21_Hook.dll | 0x7FFB2D310000 | Accessory/model mods |
Tools Installed on the PC
- Python 3.12 at
C:\Users\dvicente\AppData\Local\Programs\Python\Python312\ - pymem — process memory read/write/scan
- pefile — PE static analysis
- Frida 17.9.1 — dynamic instrumentation (not yet tested against the running game)
A base64 decoder helper lives at C:\RE\pes21\dec.py for transferring scripts via SSH.
Confirmed Findings
AOB Patterns Verified at Runtime
All existing Sider module patterns match the live process. The stamina pattern is already patched by the stamina mod (proving code caves work):
| Pattern | RVA | Status |
|---|---|---|
Stamina (F7 7D 18 48 83 C4 30) | 0xA587FB | Patched (stamina mod active) |
| Camera fanview | 0x8A1AA2 | Match |
| BroadCast zoom/pitch | 0x8A5815 | Match |
| DynWide angle | 0x8A1FC2 | Match |
Broadcast Camera — Live Values
Read from memory using the BroadCast zoom AOB + relative offset:
Camera base: 0x1434A00C0
zoom = 13.75 (offset +0x04, default 14.41)
pitch = 0.12 (offset +0x0C, default 0.5)
height = 0.24 (offset +0x03 from height/angle base)
angle = 64.00 (offset +0x0A from height/angle base)
The height/angle base is at bc_pattern_addr + 0x44.
Player Position — Confirmed
Address: 0xE5B3F0 (heap, not module-relative — may change between sessions)
| Offset | Value | Meaning |
|---|---|---|
+0x00 | float | X position on pitch (~38-50 range) |
+0x04 | float | Y position (height, ~-5 when on ground, higher during jumps) |
+0x08 | float | Z position on pitch (~48-53 range) |
+0x0C | 1.0 | Scale or flag |
+0x10 | 25.0 | Unknown constant |
Verified by monitoring live values while moving the player — updates smoothly at 60fps, Y component rises during jumps/animations.
Other Player Positions Identified
From the same scan session (3v1 practice mode):
| Address | Likely entity | Notes |
|---|---|---|
0xA6F0A8 | Teammate/ball | Repeating X,Y,Z pattern at 8-byte stride |
0xA6F408 | Teammate | 7-adjacent group, 3 sets of (X,0,Z) triplets |
0xA6F468 | Teammate or GK | Different movement pattern |
0xA6F4C8 | Teammate | Similar range to others |
Shooting-Related Strings in Binary
Found via static analysis of the original exe:
| String | File Offset | Significance |
|---|---|---|
CheckShootInFrame | 0x025D11B5 | Frame-by-frame shot validation |
SHOOT_SIDE | 0x025D4FC0 | Shot side selection |
ShootMiss FORCAST | 0x025A0804 | Miss prediction |
ActingShootFailedLevel | 0x025D2266 | Accuracy calculation |
SHOOT_SUCCESS / INFRAME_SHOOT | 0x025D54B0 | Outcome tracking |
constant_shootAging.bin | 0x0259281F | dt18 shooting parameter file |
These strings are in Fox Engine’s event/scripting table — referenced by hash, not by direct LEA instructions.
Switch-6 Candidates (Shot Zone Dispatch?)
Four cmp eax, 6 locations confirmed in live memory:
| Name | VA | Pattern | Assessment |
|---|---|---|---|
| switch6_A | 0x14478AE45 | cmp eax,6; je; add eax,-7; cmp eax,3 | Most promising — action type dispatcher, 6 could be “shoot” |
| switch6_B | 0x15B5D8355 | cmp eax,6; ja; lea rcx,[rip+table] | Jump table, but targets seem wrong |
| switch6_C | 0x1445C1E86 | cmp eax,6; jne; read [rsi+0x178946C] | Game state check, not shot zones |
| switch6_D | 0x14477613B | cmp eax,6; setnz al; mov [rdi+0xc],al | Boolean “is mode 6” flag |
Angle Initialization Code
At 0x14189949A (in .trace section), a series of MOV instructions writes angle constants to a structure:
[rbx+0x110] = 3.14159 (PI)
[rbx+0x114] = 3.0
[rbx+0x118] = 0.9
[rbx+0x11C] = +0.7854 (PI/4, +45°)
[rbx+0x120] = -0.7854 (-PI/4, -45°)
[rbx+0x124] = +0.7854 (PI/4)
[rbx+0x128] = -1.5708 (-PI/2, -90°)
[rbx+0x12C] = +1.5708 (PI/2, +90°)
These could be the angle boundaries dividing stick input into 6 shooting zones. The pattern was not found in heap memory during a practice session — the initialization may only run during regular matches with Advanced Shooting enabled, or the struct may be transient.
Input System
PES uses both XInput (statically imported, ordinals 2/3/4) and DirectInput (dynamically loaded via LoadLibrary). XInputGetState is called through an obfuscated wrapper — no direct IAT call was found. The DirectInput8Create string confirms dynamic DI8 loading with full device enumeration.
PE Section Layout
| Section | VA Range | Size | Purpose |
|---|---|---|---|
.trace | 0x140001000 | 37 MB | Primary code |
.rdata | 0x14252F000 | 14 MB | Read-only data, strings |
.impdata | 0x143D14000 | 398 MB | Main game logic (Fox Engine) |
Most gameplay code lives in .impdata, not .trace.
What Remains To Do
- Find the shot direction processing code — trace from XInputGetState through the shooting pipeline using Frida function hooks or hardware breakpoints
- Locate the angle→zone conversion — the PI/4 initialization code needs to be traced to find what struct it writes to and what reads those values
- Confirm player position stability — the heap address
0xE5B3F0will shift between sessions; need to find an AOB pattern or pointer chain to locate it reliably - Build the Sider Lua module — once the shot direction memory location is known, write a module that reads player position + camera angle and applies a rotation transform to the stick input before the game processes it
Scan Data on Disk
All preserved in C:\RE\pes21\ on korolev:
| File | Contents |
|---|---|
static_analysis.txt | PE imports, sections, AOB matches, string searches |
shoot_analysis.txt | Shooting string cross-references |
shoot3_analysis.txt | XInput, deadzone, normalization, atan2, PI constants, CMP 6 analysis |
deep_switch.txt | Detailed disassembly of switch6_A/C/D and PI/4 code |
runtime_recon.txt | Live process modules, AOB verification, camera values |
snapshot1.bin / snapshot2.bin | Full float memory snapshots (~37M entries each, ~420 MB each) |
pos_diff.txt | Diff results showing position candidates |
pi4_search.txt | Heap search for angle boundary structs |
Various .py scripts | All analysis tools, ready to rerun |
Sider Module Architecture (for the final mod)
The mod will be a Sider Lua module using the memory API and nesalib framework:
-- Pseudocode
function m.init(ctx)
-- AOB scan for player position pointer chain
-- AOB scan for camera angle (reuse BroadCastCam patterns)
-- AOB scan or code cave for shot direction intercept
ctx.register("set_teams", m.on_match_start)
end
function m.on_match_start(ctx)
-- Per-frame: read player pos, camera angle, goal pos
-- When shot is charging: rotate stick input by calculated angle
-- rotation = atan2(goal_z - player_z, goal_x - player_x) - camera_yaw
-- rotated_x = stick_x * cos(rotation) - stick_y * sin(rotation)
-- rotated_y = stick_x * sin(rotation) + stick_y * cos(rotation)
endRelated
- Advanced Shooting in PES 2021 — the shooting system being modified