Skip to content

Commit

Permalink
Fix th06.ksy so we no longer edit the generated Python file.
Browse files Browse the repository at this point in the history
See #61. I found this pattern online to better represent stages with
offsets.
  • Loading branch information
n-rook committed Dec 24, 2023
1 parent af35433 commit 5e00879
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 36 deletions.
56 changes: 34 additions & 22 deletions project/thscoreboard/replays/kaitai_parsers/th06.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,43 @@ def _read(self):
self.unknown_5 = self._io.read_u4le()
self.stage_offsets = []
for i in range(7):
self.stage_offsets.append(self._io.read_u4le())
self.stage_offsets.append(Th06.StagePointer(self._io, self, self._root))



class StagePointer(KaitaiStruct):
def __init__(self, _io, _parent=None, _root=None):
self._io = _io
self._parent = _parent
self._root = _root if _root else self
self._read()

def _read(self):
self.raw_offset = self._io.read_u4le()

@property
def offset(self):
"""Offset relative to decrypted file."""
if hasattr(self, '_m_offset'):
return self._m_offset

self._m_offset = (self.raw_offset - 15)
return getattr(self, '_m_offset', None)

@property
def body(self):
if hasattr(self, '_m_body'):
return self._m_body

if self.raw_offset != 0:
_pos = self._io.pos()
self._io.seek(self.offset)
self._m_body = Th06.Stage(self._io, self, self._root)
self._io.seek(_pos)

return getattr(self, '_m_body', None)


class Stage(KaitaiStruct):
def __init__(self, _io, _parent=None, _root=None):
self._io = _io
Expand All @@ -68,25 +101,4 @@ def _read(self):
self.rank = self._io.read_u1()


@property
def stages(self):
if hasattr(self, '_m_stages'):
return self._m_stages

_pos = self._io.pos()
self._m_stages = []
for i in range(7):
_on = self.file_header.stage_offsets[i]
if _on == 0:
self._m_stages.append(Th06.Dummy(self._io, self, self._root))
else:
# the th06 decryptor only returns the decrypted data instead of the full file
# the game stores these stage offsets from the start of the file
# thus we must adjust them to account for this difference when reading the stage data
self._io.seek(self.file_header.stage_offsets[i]-15)
self._m_stages.append(Th06.Stage(self._io, self, self._root))

self._io.seek(_pos)
return getattr(self, '_m_stages', None)


6 changes: 3 additions & 3 deletions project/thscoreboard/replays/replay_parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,9 @@ def _Parse06(rep_raw):
rep_stages = []

enumerated_non_dummy_stages = [
(i, _stage)
for i, _stage in enumerate(replay.stages)
if replay.file_header.stage_offsets[i] != 0
(i, _pointer.body)
for i, _pointer in enumerate(replay.file_header.stage_offsets)
if _pointer.body
]
# TH06 stores stage data values from the start of the stage but score from the end
for (i, current_stage), (j, next_stage) in zip(
Expand Down
28 changes: 17 additions & 11 deletions ref/threp-ksy/th06.ksy
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,6 @@ meta:
seq:
- id: file_header
type: file_header
instances:
stages:
pos: file_header.stage_offsets[_index] - 15
type:
switch-on: file_header.stage_offsets[_index]
cases:
0: dummy
_: stage
repeat: expr
repeat-expr: 7
types:
dummy:
doc: blank type
Expand Down Expand Up @@ -43,9 +33,25 @@ types:
- id: unknown_5
type: u4
- id: stage_offsets
type: u4
type: stage_pointer
repeat: expr
repeat-expr: 7
stage_pointer:
seq:
- id: raw_offset
doc: Raw offset, relative to encrypted file
type: u4
instances:
offset:
doc: Offset relative to decrypted file
value: raw_offset - 15
# See https://github.com/kaitai-io/kaitai_struct/issues/14
# for an explanation of this pattern.
body:
pos: offset
type: stage
if: raw_offset != 0

stage:
seq:
- id: score
Expand Down

0 comments on commit 5e00879

Please sign in to comment.