Properties2
TypePractice
Note createdApr 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.

ComponentLocation
Game executableFL_2026.exe (438 MB, renamed PES2021.exe)
SiderSiderAddons/ (sider.dll, LuaJIT enabled)
Lua modulesSiderAddons/modules/ (~40 modules)
RE workspaceC:\RE\pes21\ (scripts, scan data, analysis outputs)

Key DLLs at Runtime

DLLAddressRole
FL_2026.exe0x140000000Main game (image base)
xinput1_3.dll0x560000Controller input (XInput)
dinput8.dll0x7FFB33D40000Sider’s proxy DLL
sider.dll0x7FFB2C0D0000Mod framework
PES21_Hook.dll0x7FFB2D310000Accessory/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):

PatternRVAStatus
Stamina (F7 7D 18 48 83 C4 30)0xA587FBPatched (stamina mod active)
Camera fanview0x8A1AA2Match
BroadCast zoom/pitch0x8A5815Match
DynWide angle0x8A1FC2Match

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)

OffsetValueMeaning
+0x00floatX position on pitch (~38-50 range)
+0x04floatY position (height, ~-5 when on ground, higher during jumps)
+0x08floatZ position on pitch (~48-53 range)
+0x0C1.0Scale or flag
+0x1025.0Unknown 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):

AddressLikely entityNotes
0xA6F0A8Teammate/ballRepeating X,Y,Z pattern at 8-byte stride
0xA6F408Teammate7-adjacent group, 3 sets of (X,0,Z) triplets
0xA6F468Teammate or GKDifferent movement pattern
0xA6F4C8TeammateSimilar range to others

Found via static analysis of the original exe:

StringFile OffsetSignificance
CheckShootInFrame0x025D11B5Frame-by-frame shot validation
SHOOT_SIDE0x025D4FC0Shot side selection
ShootMiss FORCAST0x025A0804Miss prediction
ActingShootFailedLevel0x025D2266Accuracy calculation
SHOOT_SUCCESS / INFRAME_SHOOT0x025D54B0Outcome tracking
constant_shootAging.bin0x0259281Fdt18 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:

NameVAPatternAssessment
switch6_A0x14478AE45cmp eax,6; je; add eax,-7; cmp eax,3Most promising — action type dispatcher, 6 could be “shoot”
switch6_B0x15B5D8355cmp eax,6; ja; lea rcx,[rip+table]Jump table, but targets seem wrong
switch6_C0x1445C1E86cmp eax,6; jne; read [rsi+0x178946C]Game state check, not shot zones
switch6_D0x14477613Bcmp eax,6; setnz al; mov [rdi+0xc],alBoolean “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

SectionVA RangeSizePurpose
.trace0x14000100037 MBPrimary code
.rdata0x14252F00014 MBRead-only data, strings
.impdata0x143D14000398 MBMain game logic (Fox Engine)

Most gameplay code lives in .impdata, not .trace.

What Remains To Do

  1. Find the shot direction processing code — trace from XInputGetState through the shooting pipeline using Frida function hooks or hardware breakpoints
  2. 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
  3. Confirm player position stability — the heap address 0xE5B3F0 will shift between sessions; need to find an AOB pattern or pointer chain to locate it reliably
  4. 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:

FileContents
static_analysis.txtPE imports, sections, AOB matches, string searches
shoot_analysis.txtShooting string cross-references
shoot3_analysis.txtXInput, deadzone, normalization, atan2, PI constants, CMP 6 analysis
deep_switch.txtDetailed disassembly of switch6_A/C/D and PI/4 code
runtime_recon.txtLive process modules, AOB verification, camera values
snapshot1.bin / snapshot2.binFull float memory snapshots (~37M entries each, ~420 MB each)
pos_diff.txtDiff results showing position candidates
pi4_search.txtHeap search for angle boundary structs
Various .py scriptsAll 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)
end