@@ -132,7 +132,7 @@ def __init__(self, obj):
132132 cdata = self .root_parser .read (compressed_data_size )
133133 self .data = bytearray (lzo .decompress (cdata , False , data_size ))
134134
135- bp = ByteReader (self .data [:] )
135+ bp = ByteReader (self .data )
136136 self ._read_node (self .class_id , - 1 , bp )
137137
138138 def __read_sub_folder (self ):
@@ -141,19 +141,19 @@ def __read_sub_folder(self):
141141 self .root_parser .read_string ()
142142 self .__read_sub_folder ()
143143
144- def find_raw_chunk_id (self , chunk_id ):
145- """Finds a raw chunk ID in the file, skipping through any data that does not match the chunk ID provided.
144+ """Finds a raw chunk ID in the file, skipping through any data that does not match the chunk ID provided.
146145
147- It is not guaranteed that the chunk found is indeed the desired data, as it could be other unrelated
148- chunk that bytes happened to form the chunk ID provided.
146+ It is not guaranteed that the chunk found is indeed the desired data, as it could be other unrelated
147+ chunk that bytes happened to form the chunk ID provided.
149148
150- Args:
151- chunk_id (int): the chunk ID to search for
149+ Args:
150+ chunk_id (int): the chunk ID to search for
152151
153- Returns:
154- ByteParser with the current position set right after the chunk ID, or None
155- if no specified chunk ID was found
156- """
152+ Returns:
153+ ByteParser with the current position set right after the chunk ID, or None
154+ if no specified chunk ID was found
155+ """
156+ def find_raw_chunk_id (self , chunk_id ):
157157 bp = ByteReader (self .data [:])
158158 for i in range (len (self .data ) - 4 ):
159159 bp .pos = i
@@ -209,6 +209,10 @@ def _read_user_data(self):
209209 user_data_pos = self .root_parser .pos
210210 num_chunks = self .root_parser .read_uint32 ()
211211 for _ in range (num_chunks ):
212+ if self .root_parser .pos >= self .root_parser .size - 1 :
213+ self .root_parser .pos = user_data_pos + self .user_data_size
214+ return
215+
212216 cid = self .root_parser .read_uint32 ()
213217 self .root_parser .push_info ()
214218 size = self .root_parser .read_uint32 ()
@@ -671,15 +675,21 @@ def _read_node(self, class_id, depth, bp, add=True):
671675 # For TM2
672676 if ('version' in self .__replay_header_info
673677 and self .__replay_header_info ['version' ] >= 8 ):
674- game_class .login = bp .read_string ()
678+ pos = bp .pos
679+ try :
680+ game_class .login = bp .read_string ()
681+ except :
682+ bp .pos = pos
683+
675684 elif cid == 0x309200F or cid == 0x2401B00F :
676685 game_class .login = bp .read_string ()
677686 elif cid == 0x3092010 or cid == 0x2401B010 :
678687 bp .read_string_lookback ()
679688 elif cid == 0x3092012 or cid == 0x2401B012 :
680689 bp .skip (4 + 16 )
681690 # import binascii
682- # bp.read(4)
691+ # # bp.read(4)
692+ # print(bp.read_uint32())
683693 # print(f'{binascii.hexlify(bp.read(16))}')
684694 # print()
685695 elif cid == 0x3092013 or cid == 0x2401B013 :
@@ -692,35 +702,8 @@ def _read_node(self, class_id, depth, bp, add=True):
692702 bp .read_string_lookback ()
693703 bp .read_string_lookback ()
694704 bp .read_string_lookback ()
695- elif cid == 0x3092019 or cid == 0x03092025 or cid == 0x2401B019 :
696- if cid == 0x03092025 :
697- bp .skip (4 )
698-
699- game_class .events_duration = bp .read_uint32 ()
700- bp .skip (4 )
701-
702- num_control_names = bp .read_uint32 ()
703- game_class .control_names = []
704- for _ in range (num_control_names ):
705- name = bp .read_string_lookback ()
706- if name != '' :
707- game_class .control_names .append (name )
708-
709- if len (game_class .control_names ) == 0 :
710- continue
711-
712- num_control_entries = bp .read_uint32 ()
713- bp .skip (4 )
714- for _ in range (num_control_entries ):
715- time = bp .read_uint32 () - 100000
716- name = game_class .control_names [bp .read_byte ()]
717- entry = headers .ControlEntry (time , name , bp .read_uint16 (), bp .read_uint16 ())
718- game_class .control_entries .append (entry )
719-
720- game_class .game_version = bp .read_string ()
721- bp .skip (3 * 4 )
722- bp .read_string ()
723- bp .skip (4 )
705+ elif cid == 0x3092019 or cid == 0x03092025 or cid == 0x2401B019 or cid == 0x2401B011 :
706+ Gbx .read_ghost_events (game_class , bp , cid )
724707 elif cid == 0x309201c :
725708 bp .skip (32 )
726709 elif cid == 0x03093004 or cid == 0x2403f004 :
@@ -731,6 +714,39 @@ def _read_node(self, class_id, depth, bp, add=True):
731714 else :
732715 return
733716
717+ @staticmethod
718+ def read_ghost_events (game_class , bp , cid ):
719+ if cid == 0x03092025 :
720+ game_class .is_maniaplanet = True
721+ bp .skip (4 )
722+
723+ game_class .events_duration = bp .read_uint32 ()
724+ if game_class .events_duration != 0 :
725+ bp .skip (4 )
726+
727+ num_control_names = bp .read_uint32 ()
728+ game_class .control_names = []
729+ for _ in range (num_control_names ):
730+ name = bp .read_string_lookback ()
731+ if name != '' :
732+ game_class .control_names .append (name )
733+
734+ if len (game_class .control_names ) == 0 :
735+ return
736+
737+ num_control_entries = bp .read_uint32 ()
738+ bp .skip (4 )
739+ for _ in range (num_control_entries ):
740+ time = bp .read_uint32 () - 100000
741+ name = game_class .control_names [bp .read_byte ()]
742+ entry = headers .ControlEntry (time , name , bp .read_uint16 (), bp .read_uint16 ())
743+ game_class .control_entries .append (entry )
744+
745+ game_class .game_version = bp .read_string ()
746+ bp .skip (3 * 4 )
747+ bp .read_string ()
748+ bp .skip (4 )
749+
734750 @staticmethod
735751 def read_ghost (game_class , bp ):
736752 uncomp_sz = bp .read_uint32 ()
@@ -771,8 +787,12 @@ def read_ghost(game_class, bp):
771787 gr .read_int16 (), gr .read_int16 (),
772788 gr .read_int8 (), gr .read_int8 ())
773789
774- if len (sample_sizes ) == 1 :
775- sample_sz = sample_sizes [0 ]
790+ len_sizes = len (sample_sizes )
791+ if i >= len_sizes :
792+ if len_sizes >= 1 :
793+ sample_sz = sample_sizes [0 ]
794+ else :
795+ sample_sz = 0
776796 else :
777797 sample_sz = sample_sizes [i ]
778798
0 commit comments