Difference between revisions of "SEN:P-AI/Game Memory Layout/PES2017"
Two Scoops (talk | contribs) m |
Two Scoops (talk | contribs) (Moved Valid Pair description to Common Substructures) |
||
Line 1: | Line 1: | ||
{{TOC limit|3}} | {{TOC limit|3}} | ||
==Common Substructures== | |||
===Valid Pair=== | |||
Size: 4 bytes | |||
{| class="wikitable" | |||
|- | |||
! Offset || Length || Type || Description || | |||
|- | |||
| 0x0 || 2 bytes || int16 || Valid Indicator || 0xFFFD for a valid Home entry, 0xFFFE for a valid Away entry, or 0xFFFF for an invalid entry | |||
|- | |||
| 0x4 || 2 bytes || int16 || Unknown || Some arbitrary value that depends on the team but doesn't seem to have any obvious correlation to IDs or anything like that.<br> | |||
It is the same for all instances of this structure for a given team, even after restarting the game or editing the save file. | |||
|} | |||
This structure appears all over PES memory, in both the Player Stats Table and Team Data Table.<br>It is used to indicate whether the next or current entry is valid such as a filled player slot vs an empty player slot (the 4CC only uses 23 players, but there are 32 slots available). | |||
==Player Stats Table== | ==Player Stats Table== | ||
The Stats Table is an internal memory structure in PES17 containing all player stats that can be seen in the post-match screens but also a considerable number of "hidden stats" not displayed anywhere in the game.<br> | The Stats Table is an internal memory structure in PES17 containing all player stats that can be seen in the post-match screens but also a considerable number of "hidden stats" not displayed anywhere in the game.<br> | ||
Line 376: | Line 390: | ||
|172|| 0x12A8 || 4 Bytes || uint32 || ?UNKNOWN 184 || | |172|| 0x12A8 || 4 Bytes || uint32 || ?UNKNOWN 184 || | ||
|- | |- | ||
|173|| 0x12AC || 4 Bytes ||validPair|| ?Next Player Valid || | |173|| 0x12AC || 4 Bytes || validPair || ?Next Player Valid || There's a validPair both before the first player entry and after the last one so I could have said this was at the beginning as "This Player Valid". I'm not sure why there's one on both ends of the table but I suspect the final one may be used as a [[wikipedia:Sentinel_value |sentinel]]. | ||
There's | |||
|} | |} | ||
'''Unknown stats''' which have unidentified or uncertian purposes/meaning have "?" in front of the name. If you figure out what one of these is please feel free to edit this page. Unknown stats can be displayed in SEN:P-AI by checking the "show hidden stats" box in the columns menu and then checking the corresponding box next to the stat. | '''Unknown stats''' which have unidentified or uncertian purposes/meaning have "?" in front of the name. If you figure out what one of these is please feel free to edit this page. Unknown stats can be displayed in SEN:P-AI by checking the "show hidden stats" box in the columns menu and then checking the corresponding box next to the stat. | ||
Line 488: | Line 500: | ||
===Player Data=== | ===Player Data=== | ||
Size: 232 bytes | Size: 232 bytes | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- |
Revision as of 20:36, 22 February 2018
Common Substructures
Valid Pair
Size: 4 bytes
Offset | Length | Type | Description | |
---|---|---|---|---|
0x0 | 2 bytes | int16 | Valid Indicator | 0xFFFD for a valid Home entry, 0xFFFE for a valid Away entry, or 0xFFFF for an invalid entry |
0x4 | 2 bytes | int16 | Unknown | Some arbitrary value that depends on the team but doesn't seem to have any obvious correlation to IDs or anything like that. It is the same for all instances of this structure for a given team, even after restarting the game or editing the save file. |
This structure appears all over PES memory, in both the Player Stats Table and Team Data Table.
It is used to indicate whether the next or current entry is valid such as a filled player slot vs an empty player slot (the 4CC only uses 23 players, but there are 32 slots available).
Player Stats Table
The Stats Table is an internal memory structure in PES17 containing all player stats that can be seen in the post-match screens but also a considerable number of "hidden stats" not displayed anywhere in the game.
It is dynamically allocated in memory by PES at the very beginning of the match, just before the first touch (not during the anthem cutscenes), updated in real-time for the duration of the match, and de-allocated from memory upon exiting the post-match results screen.
The most common location for the stats table is as specified:
- In a block of memory 0x90000 Bytes (144 4KiB Pages) in size, Committed, marked Private, with ReadWrite protection
- The Home team's stats table begins at offset 0x35010 from the start of the block
- The Away team's stats table begins 0x28E30 bytes after the home offset, or 0x5DE40 from the start of the block
This memory block location was originally thought to be hardcoded, but it was later discovered that it was only the result of a memory allocation pattern that rendered this particular method of finding the tables 95-80% accurate, with the accuracy decreasing the longer the game was running. This search pattern is still used by default, but a brute force search can also be used.
There is additional data before and possibly after both of tables that is part of the same fixed-layout data structure but has yet to be deciphered.
Player Stats Entry
Entry Count: 32 per team, in the same order as the Team-Player Table (Edit File)
Entry Length: 4784 (0x12B0) Bytes
ID | Offset | Length | Type | Description | Behavior |
---|---|---|---|---|---|
0 | 0x0000 | 4 Bytes | uint32 | Player ID | Fixed value, checking it is a good way to see if the table has been overwritten with garbage |
1 | 0x0004 | 36 Bytes | uint32x9 | Goals Scored | |
2 | 0x0028 | 36 Bytes | uint32x9 | Own Goals Scored | These next hundred or so "uint32x9" stats follow the same format:
The 36 bytes are broken into 9 "segments" of 32-bit integers. Each segment corresponds to 15 minutes of a match. Segments 1-3 are the 1st half, segments 4-6 are the 2nd half, segments 7 and 8 are the 1st and 2nd halves of Extra Time, and segment 9 is the Penalty Shootout. Injury time is counted as part of the last segment of the half. Stats are recorded separately for each segment, which means to get the actual value of the stat, you need to calculate the total of all 9 segments. |
3 | 0x004C | 36 Bytes | uint32x9 | Free kicks scored | |
4 | 0x0070 | 36 Bytes | uint32x9 | Penalties scored | |
5 | 0x0094 | 36 Bytes | uint32x9 | Assists | |
6 | 0x00B8 | 36 Bytes | uint32x9 | Shots | |
7 | 0x00DC | 36 Bytes | uint32x9 | Headers | |
8 | 0x0100 | 36 Bytes | uint32x9 | Shots (Strong Foot) | |
9 | 0x0124 | 36 Bytes | uint32x9 | Shots (Weak Foot) | |
10 | 0x0148 | 36 Bytes | uint32x9 | ?UNKNOWN 10 | Strongly correlated with goal scored |
11 | 0x016C | 36 Bytes | uint32x9 | Shots on Target | |
12 | 0x0190 | 36 Bytes | uint32x9 | Free kicks shot | Shots from free kicks in regular and extra time (default key: X. No matter from which half of the field is kicked, it is still considered a shot. Goal kicks are excluded since the game treats them as passes). |
13 | 0x01B4 | 36 Bytes | uint32x9 | Penalty kicks shot | Shots from (mid-match) penalties. |
14 | 0x01D8 | 36 Bytes | uint32x9 | Passes | Low Passes + Through Balls + Lofted/High Passes + Crosses = (total) Passes Ground Passes + Aerial Passes + Crosses == (total) Passes |
15 | 0x01FC | 36 Bytes | uint32x9 | Passes Made | |
16 | 0x0220 | 36 Bytes | uint32x9 | Low Passes | Low passes (default key: A) |
17 | 0x0244 | 36 Bytes | uint32x9 | Low Passes Made | |
18 | 0x0268 | 36 Bytes | uint32x9 | Through Balls | Low Through Ball (default key: Y) + Chipped Through Ball (default key: LB + Y) |
19 | 0x028C | 36 Bytes | uint32x9 | Through Balls Made | |
20 | 0x02B0 | 36 Bytes | uint32x9 | Lofted/High Passes | Lofted Pass (default key: B) + High Pass (default key: RT + B) |
21 | 0x02D4 | 36 Bytes | uint32x9 | Lofted/High Passes Made | |
22 | 0x02F8 | 36 Bytes | uint32x9 | Crosses | |
23 | 0x031C | 36 Bytes | uint32x9 | Crosses Made | Crosses where the sticker get the ball (the same way the game determinates when a pass in made or not). |
24 | 0x0340 | 36 Bytes | uint32x9 | Ground Passes | Low Passes + Low Through Ball (low passes) |
25 | 0x0364 | 36 Bytes | uint32x9 | Ground Passes Made | |
26 | 0x0388 | 36 Bytes | uint32x9 | Aerial Passes | Lofted/High Passes + Chipped Through Balls (lofted passes) |
27 | 0x03AC | 36 Bytes | uint32x9 | Aerial Passes Made | |
28 | 0x03D0 | 36 Bytes | uint32x9 | Low Through Balls | Low Through Ball (default key: Y) |
29 | 0x03F4 | 36 Bytes | uint32x9 | Low Through Balls Made | |
30 | 0x0418 | 36 Bytes | uint32x9 | Chipped Through Balls | Chipped Through Ball (default key: LB + Y) |
31 | 0x043C | 36 Bytes | uint32x9 | Chipped Through Balls Made | |
32 | 0x0460 | 36 Bytes | uint32x9 | ?Forward Passes | (The part where I gave up trying to find correlations but still saw similar patterns to the above) Not sure about these three, but maybe: forward passes |
33 | 0x0484 | 36 Bytes | uint32x9 | ?Forward Passes Made | |
34 | 0x04A8 | 36 Bytes | uint32x9 | ?Lateral Passes | Passes between two players on (almost) the same line |
35 | 0x04CC | 36 Bytes | uint32x9 | ?Lateral Passes Made | |
36 | 0x04F0 | 36 Bytes | uint32x9 | ?Backward Passes | Backward passes |
37 | 0x0514 | 36 Bytes | uint32x9 | ?Backward Passes Made | |
38 | 0x0538 | 36 Bytes | uint32x9 | Tackles | |
39 | 0x055C | 36 Bytes | uint32x9 | Tackles Won | |
40 | 0x0580 | 36 Bytes | uint32x9 | ?UNKNOWN 40 | Tackles Won without sliding??? |
41 | 0x05A4 | 36 Bytes | uint32x9 | ?UNKNOWN 41 | Pretty rare, maybe is a tackle won while the opponent is trying to pass or shoot. |
42 | 0x05C8 | 36 Bytes | uint32x9 | ?UNKNOWN 42 | Tackles where the player hit only the opponent and not the ball??? (Correlated with Tackles and/or Tackles Won). |
43 | 0x05EC | 36 Bytes | uint32x9 | Clearances | |
44 | 0x0610 | 36 Bytes | uint32x9 | Fouls | |
45 | 0x0634 | 36 Bytes | uint32x9 | Fouls Offside | |
46 | 0x0658 | 36 Bytes | uint32x9 | Yellow Cards | For some reason, the exact moment these stats are updated depends on the particular card cutscene used |
47 | 0x067C | 36 Bytes | uint32x9 | Red Cards | |
48 | 0x06A0 | 36 Bytes | uint32x9 | ?UNKNOWN 48 | |
49 | 0x06C4 | 36 Bytes | uint32x9 | ?UNKNOWN 49 | |
50 | 0x06E8 | 36 Bytes | uint32x9 | Free Kicks | |
51 | 0x070C | 36 Bytes | uint32x9 | ?UNKNOWN 51 | |
52 | 0x0730 | 36 Bytes | uint32x9 | Corner Kicks | |
53 | 0x0754 | 36 Bytes | uint32x9 | ?UNKNOWN 53 | |
54 | 0x0778 | 36 Bytes | uint32x9 | ?UNKNOWN 54 | |
55 | 0x079C | 36 Bytes | uint32x9 | ?UNKNOWN 55 | |
56 | 0x07C0 | 36 Bytes | uint32x9 | Touches | (These appeared to have some correlation to the total touches) It looks like that type of Touches is not related to the kind of Passes and it may depends also on how the player stops the ball. Also A_Touches (and maybe B_Touches and C_Touches as well) can be greater than Touches. |
57 | 0x07E4 | 36 Bytes | uint32x9 | ?A_Touches | |
58 | 0x0808 | 36 Bytes | uint32x9 | ?B_Touches | |
59 | 0x082C | 36 Bytes | uint32x9 | ?C_Touches | |
60 | 0x0850 | 36 Bytes | uint32x9 | ?UNKNOWN 60 | |
61 | 0x0874 | 36 Bytes | uint32x9 | ?UNKNOWN 61 | |
62 | 0x0898 | 36 Bytes | uint32x9 | ?UNKNOWN 62 | |
63 | 0x08BC | 36 Bytes | uint32x9 | Interceptions | |
64 | 0x08E0 | 36 Bytes | uint32x9 | ?A_Interceptions | (These appeared to have some correlation to the total interceptions) |
65 | 0x0904 | 36 Bytes | uint32x9 | ?B_Interceptions | |
66 | 0x0928 | 36 Bytes | uint32x9 | ?C_Interceptions | |
67 | 0x094C | 36 Bytes | uint32x9 | ?D_Interceptions | |
68 | 0x0970 | 36 Bytes | uint32x9 | ?UNKNOWN 68 | |
69 | 0x0994 | 36 Bytes | uint32x9 | ?UNKNOWN 69 | |
70 | 0x09B8 | 36 Bytes | uint32x9 | ?UNKNOWN 70 | |
71 | 0x09DC | 36 Bytes | uint32x9 | ?UNKNOWN 71 | |
72 | 0x0A00 | 36 Bytes | uint32x9 | ?UNKNOWN 72 | |
73 | 0x0A24 | 36 Bytes | uint32x9 | ?UNKNOWN 73 | |
74 | 0x0A48 | 36 Bytes | uint32x9 | ?UNKNOWN 74 | |
75 | 0x0A6C | 36 Bytes | uint32x9 | ?UNKNOWN 75 | |
76 | 0x0A90 | 36 Bytes | uint32x9 | ?UNKNOWN 76 | |
77 | 0x0AB4 | 36 Bytes | uint32x9 | ?UNKNOWN 77 | |
78 | 0x0AD8 | 36 Bytes | uint32x9 | ?UNKNOWN 78 | |
79 | 0x0AFC | 36 Bytes | uint32x9 | ?UNKNOWN 79 | |
80 | 0x0B20 | 36 Bytes | uint32x9 | ?UNKNOWN 80 | |
81 | 0x0B44 | 36 Bytes | uint32x9 | ?UNKNOWN 81 | |
82 | 0x0B68 | 36 Bytes | uint32x9 | ?UNKNOWN 82 | |
83 | 0x0B8C | 36 Bytes | uint32x9 | ?UNKNOWN 83 | |
84 | 0x0BB0 | 36 Bytes | uint32x9 | ?UNKNOWN 84 | |
85 | 0x0BD4 | 36 Bytes | uint32x9 | ?UNKNOWN 85 | |
86 | 0x0BF8 | 36 Bytes | uint32x9 | ?UNKNOWN 86 | |
87 | 0x0C1C | 36 Bytes | uint32x9 | ?UNKNOWN 87 | |
88 | 0x0C40 | 36 Bytes | uint32x9 | ?UNKNOWN 88 | |
89 | 0x0C64 | 36 Bytes | uint32x9 | ?UNKNOWN 89 | |
90 | 0x0C88 | 36 Bytes | uint32x9 | ?UNKNOWN 90 | |
91 | 0x0CAC | 36 Bytes | uint32x9 | ?UNKNOWN 91 | |
92 | 0x0CD0 | 36 Bytes | uint32x9 | ?UNKNOWN 92 | |
93 | 0x0CF4 | 36 Bytes | uint32x9 | ?UNKNOWN 93 | |
94 | 0x0D18 | 36 Bytes | uint32x9 | ?UNKNOWN 94 | |
95 | 0x0D3C | 36 Bytes | uint32x9 | ?UNKNOWN 95 | |
96 | 0x0D60 | 36 Bytes | uint32x9 | ?UNKNOWN 96 | |
97 | 0x0D84 | 36 Bytes | uint32x9 | ?UNKNOWN 97 | |
98 | 0x0DA8 | 36 Bytes | uint32x9 | ?UNKNOWN 98 | |
99 | 0x0DCC | 36 Bytes | uint32x9 | ?UNKNOWN 99 | |
100 | 0x0DF0 | 36 Bytes | uint32x9 | ?UNKNOWN 100 | |
101 | 0x0E14 | 36 Bytes | uint32x9 | ?UNKNOWN 101 | |
102 | 0x0E38 | 36 Bytes | uint32x9 | ?UNKNOWN 102 | |
103 | 0x0E5C | 36 Bytes | uint32x9 | ?UNKNOWN 103 | |
104 | 0x0E80 | 36 Bytes | uint32x9 | ?UNKNOWN 104 | |
105 | 0x0EA4 | 36 Bytes | uint32x9 | ?UNKNOWN 105 | |
106 | 0x0EC8 | 36 Bytes | uint32x9 | ?UNKNOWN 106 | |
107 | 0x0EEC | 36 Bytes | uint32x9 | ?UNKNOWN 107 | |
108 | 0x0F10 | 36 Bytes | uint32x9 | ?UNKNOWN 108 | |
109 | 0x0F34 | 36 Bytes | uint32x9 | ?UNKNOWN 109 | |
110 | 0x0F58 | 36 Bytes | uint32x9 | Shots Faced | |
111 | 0x0F7C | 36 Bytes | uint32x9 | Shots Faced On Target | |
112 | 0x0FA0 | 36 Bytes | uint32x9 | Saves | |
113 | 0x0FC4 | 36 Bytes | uint32x9 | ?Saves On Target | (appears to be correlated to Saves in the same way other "(on target)" stats are, but I'm not entirely sure what it means, maybe that the shot saved was on target?) Only shots in the area are count for this stat, even if they are not on target. Shots saved from outside the box do not add value to this stat. It looks like the word "target" means "area" here. Saves in penalty shootout are not counted. |
114 | 0x0FE8 | 1 Byte | sint8 | First Minute on Pitch | when the player was first subbed on, 0 for starting players, -1 for benched players until they're subbed on |
115 | 0x0FE9 | 1 Byte | sint8 | Last Minute on Pitch | when the player was last on the pitch, -1 for benched players, for currently playing players this USUALLY matches the game clock but for recently subbed players, PES rounds it up to the next minute just to fuck with you. Players in undergoing treatment are counted on the pitch. |
116 | 0x0FEA | 1 Byte | uint8 | ?UNKNOWN 116 | |
117 | 0x0FEB | 1 Byte | uint8 | ?UNKNOWN 117 | |
118 | 0x0FEC | 1 Byte | uint8 | ?UNKNOWN 118 | |
119 | 0x0FED | 1 Byte | uint8 | ?UNKNOWN 119 | |
120 | 0x0FEE | 1 Byte | uint8 | ?UNKNOWN 120 | |
121 | 0x0FEF | 1 Byte | uint8 | ?UNKNOWN 121 | |
122 | 0x0FE0 | 4 Bytes | uint32 | ?UNKNOWN 122 | |
123 | 0x0FF4 | 4 Bytes | uint32 | Current Playing Position | [0-12] with the same values as the Edit File |
124 | 0x0FF8 | 52 Bytes | uint32 | Game Ticks Played | An array of 13 32-bit integers, each one corresponding to a playing position. Each element contains the number of "ticks" the player has spent playing in that position. The total sum of the array is the number of ticks the player, which is exact and the same for all unsubbed starting players. 1 real-time seconds is about 48 ticks, with what seems like no relation to framerate. 1 Game Minute is exactly 32*{Match Length Setting} ticks (320 for 10 minute matches). |
125 | 0x102C | 4 Bytes | uint32 | ?UNKNOWN 137 | After further inspection this might actually be 4 single byte values. The 32-bit value is around 0x01010100 for captians and around 0x01000000 for other players and only the low byte changes every so often. |
126 | 0x1030 | 4 Bytes | float32 | Player Rating | A 32-bit floating point number. Matches the rating exactly, in increments of 0.5, no more exact. This leaves no (known) way to determine Man Of The Match if there's a tie for highest rating. |
127 | 0x1034 | 560 Bytes | uint32 | Play Area Grid | This is an array of 140 32-bit integers representing a 10x14 grid of squares. About every real-time second, PES checks where each player is in this grid and increments the corresponding value. This is used to generate the pitch heat-map seen on the individual match records screen, however the highest intensity color it will show there corresponds to 12 seconds while most players will have one or more squares in the ballpark of 90 for a typical match. |
128 | 0x1264 | 4 Bytes | uint32 | Realtime (sec) on Pitch | Roughly the number of real-time seconds a player has been playing. For some reason this drifts by multiple seconds for players who should have been playing the exact same amount of time. |
129 | 0x1268 | 4 Bytes | float32 | ?UNKNOWN 141 | |
130 | 0x126C | 4 Bytes | uint32? | UNKNOWN 142 | Boolean value: 1 if player injured, 0 otherwise. |
131 | 0x1270 | 4 Bytes | float32 | ?UNKNOWN 143 | (0 for most players, nonzero for only a few players) |
132 | 0x1274 | 4 Bytes | uint32 | Stamina | Starts at 100 and periodically decreases throughout the match. During halftime/fulltime/extra-halftime, players will recover stamina in the UI but this value is not updated to match until the next half actually starts. |
133 | 0x1278 | 4 Bytes | float32 | ?UNKNOWN 145 | Zero until the match starts. It constantly grows and it's related with player's movements across the pitch.
Apparently stamina, time on the pitch and many other stats do not affect this value. (may be related to calculating Average Speed) |
134 | 0x127C | 4 Bytes | float32 | Distance Dribbled | 32-bit floating point value tracking the distance dribbled in meters. Truncated to an integer on the match records screen. Zero until the player makes a pass (no matter if completed or not), it grows every time the player passes the ball. Sometimes this rule is not followed and the value stays zero. (perhaps the game chooses to disregard individual distances if they're less than 1m) |
135 | 0x1280 | 4 Bytes | float32 | ?UNKNOWN 147 | Zero until the player completes a pass, it grows after every completed pass. (This may be related to overall possession) |
136 | 0x1284 | 1 Byte | uint8 | ?UNKNOWN 148 FLAG | (Have no idea what these are for, but only the low bit is ever active, leading me to believe they're all Boolean flags) |
137 | 0x1285 | 1 Byte | uint8 | ?UNKNOWN 149 FLAG | |
138 | 0x1286 | 1 Byte | uint8 | ?UNKNOWN 150 FLAG | |
139 | 0x1287 | 1 Byte | uint8 | ?UNKNOWN 151 FLAG | |
140 | 0x1288 | 1 Byte | uint8 | ?UNKNOWN 152 FLAG | |
141 | 0x1289 | 1 Byte | uint8 | ?UNKNOWN 153 FLAG | |
142 | 0x128A | 1 Byte | uint8 | ?UNKNOWN 154 FLAG | |
143 | 0x128B | 1 Byte | uint8 | ?UNKNOWN 155 FLAG | |
144 | 0x128C | 1 Byte | uint8 | ?UNKNOWN 156 FLAG | |
145 | 0x128D | 1 Byte | uint8 | ?UNKNOWN 157 FLAG | |
146 | 0x128E | 1 Byte | uint8 | ?UNKNOWN 158 FLAG | |
147 | 0x128F | 1 Byte | uint8 | ?UNKNOWN 159 FLAG | |
148 | 0x1290 | 1 Byte | uint8 | ?UNKNOWN 160 FLAG | |
149 | 0x1291 | 1 Byte | uint8 | ?UNKNOWN 161 FLAG | |
150 | 0x1292 | 1 Byte | uint8 | ?UNKNOWN 162 FLAG | |
151 | 0x1293 | 1 Byte | uint8 | ?UNKNOWN 163 FLAG | |
152 | 0x1294 | 1 Byte | uint8 | ?UNKNOWN 164 FLAG | |
153 | 0x1295 | 1 Byte | uint8 | ?UNKNOWN 165 FLAG | |
154 | 0x1296 | 1 Byte | uint8 | ?UNKNOWN 166 FLAG | |
155 | 0x1297 | 1 Byte | uint8 | ?UNKNOWN 167 FLAG | |
156 | 0x1298 | 1 Byte | uint8 | ?UNKNOWN 168 FLAG | |
157 | 0x1299 | 1 Byte | uint8 | ?UNKNOWN 169 FLAG | |
158 | 0x129A | 1 Byte | uint8 | ?UNKNOWN 170 FLAG | |
159 | 0x129B | 1 Byte | uint8 | ?UNKNOWN 171 FLAG | |
160 | 0x129C | 1 Byte | uint8 | ?UNKNOWN 172 FLAG | |
161 | 0x129D | 1 Byte | uint8 | ?UNKNOWN 173 FLAG | |
162 | 0x129E | 1 Byte | uint8 | ?UNKNOWN 174 FLAG | |
163 | 0x129F | 1 Byte | uint8 | ?UNKNOWN 175 FLAG | |
164 | 0x12A0 | 1 Byte | uint8 | ?UNKNOWN 176 FLAG | |
165 | 0x12A1 | 1 Byte | uint8 | ?UNKNOWN 177 FLAG | |
166 | 0x12A2 | 1 Byte | uint8 | ?UNKNOWN 178 FLAG | |
167 | 0x12A3 | 1 Byte | uint8 | ?UNKNOWN 179 FLAG | |
168 | 0x12A4 | 1 Byte | uint8 | ?UNKNOWN 180 FLAG | |
169 | 0x12A5 | 1 Byte | uint8 | ?UNKNOWN 181 FLAG | |
170 | 0x12A6 | 1 Byte | uint8 | ?UNKNOWN 182 FLAG | |
171 | 0x12A7 | 1 Byte | uint8 | ?UNKNOWN 183 FLAG | |
172 | 0x12A8 | 4 Bytes | uint32 | ?UNKNOWN 184 | |
173 | 0x12AC | 4 Bytes | validPair | ?Next Player Valid | There's a validPair both before the first player entry and after the last one so I could have said this was at the beginning as "This Player Valid". I'm not sure why there's one on both ends of the table but I suspect the final one may be used as a sentinel. |
Unknown stats which have unidentified or uncertian purposes/meaning have "?" in front of the name. If you figure out what one of these is please feel free to edit this page. Unknown stats can be displayed in SEN:P-AI by checking the "show hidden stats" box in the columns menu and then checking the corresponding box next to the stat.
Team Data Table
The team data table is an internal data structure in PES that holds all kinds of data, including tactical, about the two currently selected teams.
It is allocated (perhaps statically?) by PES as soon as the game launches (but is unpopulated and thus unable to be found until two teams are selected) and only deallocated when the game closes, staying in the same place for the entire duration of a particular PES17.exe instance.
The most common location for the stats table is as specified:
- In a block of memory 0x60000 Bytes (96 4KiB Pages) in size, Committed, marked Private, with ReadWrite protection
- Beginning at offset 0x538B4 from the start of the block
It is unknown whether this pattern is static or just extremely common, since the allocation only ever happens once per PES17.exe instance (and at the very start of the program where memory allocations would follow a very consistent pattern).
Overall Structure
The substructures mentioned in the following table are described further below.
Size: 18736 (0x4930) bytes
Offset | Length | Type | Description |
---|---|---|---|
0x0000 | 1312 bytes | Team Data | Home team data |
0x0520 | 1312 bytes | Team Data | Away team data |
0x0A40 | 632 bytes | Team Tactics | Home Team Tactics |
0x0CB8 | 632 bytes | Team Tactics | Away Team Tactics |
0x0F30 | 7424 bytes | (32x) Player Data | Home Team Players |
0x2C30 | 7424 bytes | (32x) Player Data | Away Team Players |
Note: The values for Unknowns in the following tables were determined with only limited testing. Further testing could potentially yield better results.
Team Data
Size: 1312 (0x520) bytes
Offset | Length | Type | Description | |
---|---|---|---|---|
0x000 | 4 bytes | validPair | Team Valid | |
0x004 | 70 bytes | cstring | Team Name | As written in EDIT0 |
0x04A | 4 bytes | cstring | Scoreboard Name | As written in EDIT0 |
0x04E | 2 bytes | ? | Unknown A | 0xFFFF |
0x050 | 97 bytes | ? | Unknown B | 0x000 x97 |
0x0B1 | 16 bytes | cstring | Banner 1 Text | As written in EDIT0 |
0x0C1 | 16 bytes | cstring | Banner 2 Text | As written in EDIT0 |
0x0D1 | 16 bytes | cstring | Banner 3 Text | As written in EDIT0 |
0x0E1 | 16 bytes | cstring | Banner 4 Text | As written in EDIT0 |
0x0F1 | 4 bytes | int8 x4 | Banner Edited Flags | See Banner Edited Flags |
0x0F5 | 3 bytes | ? | Unknown C | Possibly padding |
0x0F8 | 256 bytes total | Player List | 32 entries | |
0x0 | 4 bytes | validPair | Player Valid | |
0x4 | 4 bytes | uint32 | Player ID | |
0x1F8 | 4 bytes | validPair? | Team Valid? | high bytes set to 0x0000 |
0x1FC | 4 bytes | uint32 | Team ID | |
0x200 | 32 bytes | int8 x32 | Shirt Numbers | |
0x220 | 16 bytes x15 (240 total) | Unknown D | 0xFFFF,0000,0000,0000,0000,0000,0000,0000 x15 | |
0x310 | 528 bytes | Got no fuckin clue |
Home Team Tactics
Size: 632 (0x278) bytes
Offset | Length | Type | Description | |
---|---|---|---|---|
0x00 | 32 bytes | ? | Unknown A | 0x00 x32 |
0x20 | 4 bytes | ? | Unknown B | 0x32 x4 |
0x24 | 8 bytes | ? | Unknown C | 0x02,02,00,02,00,02,00,00 |
0x2C | 4 bytes | validPair? | Team Valid? | high bytes set to 0x0000 |
0x30 | 4 bytes | uint32 | Manager ID | (I'm not actually sure since its the same as the Team ID) |
0x34 | 46 bytes | cstring | Manager Name | As written in EDIT0 |
0x62 | 6 bytes | ? | Unknown D | 0xD7,00,28,14,FF,FF |
0x68 | 528 bytes | Bytes [0x004, 0x213] of the team's Game Plan from EDIT0 |
Note: This structure contains the currently set tactics for the match.
Changes made using the game plan menu are not written back to here until exiting the game plan menu.
Changes made by writing directly to memory are NOT reflected by the UI. The game (reasonably) assumes that only the menu UI can be used to change anything and thus overwrites this memory with the UI's state whenever exiting said menu.
Why do you know this?
I wanted to see if timeout changes could be written directly to memory without pausing the game (and thus almost completely eliminating the stupid amounts of stream time spent on timeouts). Unfortunately the fact that doing so doesn't change the UI prevents the streamer from manually making changes themselves and prevents them and everyone else from seeing the actual state of the game plans (Rigcity, here we come). "The state of the UI" likely has multiple layers of indirection that would be impractical to reverse engineer, so I had to give up on the idea entirely.
It was the only use case for writing to game memory that would have convinced me that it would be worth it to switch SEN:P-AI from ReadOnly to ReadWrite mode, so it will stay that way until everyone can come up with and agree on a better idea.
Player Data
Size: 232 bytes
Offset | Length | Type | Description | |
---|---|---|---|---|
0x00 | 1 byte | uint8 | Height | (cm) |
0x01 | 1 byte | uint8 | Weight | (kg) |
0x02 | 28 bytes | ? | Unknown A | Bytes from the Player Entry in EDIT0, potentially modified or partially out of order |
0x1E:0 | 5 bits | ? | Unknown B | |
0x1E:5 | 3 bits | uint3 | Player Condition | 0 = Worst, 4 = Best, 5-7 appear to default back to neutral in the UI |
0x1F | 13 bytes | ? | Unknown C | |
0x2C | 4 bytes | validPair | Player Valid | |
0x30 | 4 bytes | uint32 | Player ID | |
0x34 | 4 bytes | uint32 | Player Commentary ID | (probably) |
0x38 | 46 bytes | cstring | Player Name | As written in EDIT0 |
0x66 | 18 bytes | cstring | Shirt/Print Name | As written in EDIT0 |
0x78 | 4 bytes x26 (104 total) | Unknown D | either 0x00000000, 0xFFFF0000, or 0xFFFFFFFF | |
0xE0 | 4 bytes | int32? | Unknown E | 0x00000001 |
0xE4 | 4 bytes | int32? | Unknown F | 0x00000015 |
Note: Even though writing directly to the game plan wont change the UI, writing directly to player conditions DOES change the UI. This is because Conditions aren't controlled by the game plan menu, so the game has to check them and update the UI every time the menu opens. This suggests that the entire TDT is actually what the game reads from to make AI decisions rather than just being an extra copy, but I haven't done any more testing to confirm because I'm not interested in rigging the game.