sourcehold / sourcehold-maps

Reverse engineering the map file format of Stronghold
GNU General Public License v3.0
20 stars 3 forks source link

Assess which memory/map sections are informative #22

Open gynt opened 3 years ago

gynt commented 3 years ago

Because there are many sections and there is a lot of data in a file, it will be useful to distinguish more relevant and less relevant memory/map file sections.

The map/sav/msv file format seems to be a memory dump. That means that there is a distinction between authoritative information (e.g., building info) and non-informative information, such as section 1001 which is just a cache for what is drawn to the screen.

The hypothesis is that section 1001 has no unique information, and is rather recalculated based on other sections (unit and building info for example). There must be more sections that display this behavior.

To achieve this, we could wipe memory sections (of which we know the location) by setting the values to 0, and then see whether the game updates these sections with the same information.

Then, we could flag each section with the label "fully/partially/not restored" and "game continues/breaks".

The code to do this would be something along the lines of:

from sourcehold.debugtools.memory.common.access import AccessContext()
# Run Stronghold Crusader first. Load any game. Pause the game.
# Then:
process = AccessContext()

# Then make a memory dump of the section
v1 = process.read_section('1001')
# Then wipe the memory:
process.write_section('1001', b'\x00', recycle=True)

# Then rotate the map view in game. (This forces a redraw/recache as far as we know)
v2 = process.read_section('1001')

# If v2 is all null bytes, maybe consider pressing spacebar once or twice (this allows 1 game tick to pass) and then check again
if len(set(v2)) and set(v2) == {b'\x00'}:
  print("the section is empty")

v3 = process.read_section('1001')

# Then inspect what data has changed
same_values = [i for i in range(len(v1)) if v1[i]==v2[i]] # or compare with v3 instead of v2 if that is relevant
print(len(same_values)/len(v1))

If the percentage of values that are the same is 100%, it is fully restored, if < 100% "partially restored".