Example #1
0
    def parse_event(self):
        """ Parse custom Fortnite events """
        event_id = self.replay.read_string()
        group = self.replay.read_string()
        metadata = self.replay.read_string()
        start_time = self.replay.read_uint32()
        end_time = self.replay.read_uint32()
        size = self.replay.read_uint32()

        current_pos = self.replay.bytepos
        logger.info(
            f'parse_event(), event id => {event_id}, group id => {group}, current offset => {current_pos}'
        )

        if group == EventTypes.PLAYER_ELIMINATION.value:
            try:
                self.parse_elimination_event(start_time)
            except:
                logger.error("Couldnt parse event PLAYER_ELIMINATION")
                self.replay.bytepos = current_pos + size

        if metadata == EventTypes.MATCH_STATS.value:
            self.parse_matchstats_event()

        if metadata == EventTypes.TEAM_STATS.value:
            self.parse_teamstats_event()
    def parse_replaydata(self):
        """ Parse incremental changes to the last checkpoint """
        logger.info('parse_replaydata()')

        start = self.replay.read_uint32()
        end = self.replay.read_uint32()
        remaining_offset = self.replay.read_uint32()
        _ = self.replay.read_uint32()
        remaining_offset = self.replay.read_uint32()
    def parse_header(self, size):
        """ Parse metadata of the file replay (Fortnite) """
        logger.info('parse_header()')

        logger.debug(self.replay.read(f'bytes:{size}'))
        self.replay.bytepos -= size

        self.replay.skip(4)
        header_version = self.replay.read_uint32()
        server_side_version = self.replay.read_uint32()
        season = self.replay.read_uint32()
        _01 = self.replay.read_uint32()

        if header_version > HeaderTypes.HEADER_GUID.value:
            guid = self.replay.read_guid()
        else:
            guid = ""

        _4 = self.replay.read_uint16()
        some_increasing_number = self.replay.read_uint32()
        fortnite_version = self.replay.read_uint32()
        release = self.replay.read_string()

        if self.replay.read_bool():
            game_map = self.replay.read_string()
        else:
            game_map = ""
        _02 = self.replay.read_uint32()
        _3 = self.replay.read_uint32()

        if self.replay.read_bool():
            game_sub = self.replay.read_string()
        else:
            game_sub = ""

        self.header = Header(header_version=header_version,
                             fortnite_version=fortnite_version,
                             server_side_version=server_side_version,
                             season=season,
                             release=release,
                             game_map=game_map,
                             game_sub=game_sub,
                             guid=guid,
                             unknown0=_01,
                             unknown1=_4,
                             unknown2=_02,
                             unknown3=_3,
                             unknown4=some_increasing_number)
        logger.debug(self.header)
    def parse_meta(self):
        """ Parse metadata of the file replay (Unreal Engine) """
        logger.info('parse_meta()')

        magic = self.replay.read_uint32()
        if (magic != FILE_MAGIC):
            raise InvalidReplayException()
        file_version = self.replay.read_uint32()
        lenght_in_ms = self.replay.read_uint32()
        network_version = self.replay.read_uint32()
        change_list = self.replay.read_uint32()
        friendly_name = self.replay.read_string()
        is_live = self.replay.read_bool()

        if file_version >= HistoryTypes.HISTORY_RECORDED_TIMESTAMP.value:
            time_stamp = self.replay.read_uint64()

        if file_version >= HistoryTypes.HISTORY_COMPRESSION.value:
            is_compressed = self.replay.read_bool()

        is_encrypted = False
        encryption_key = bytearray()
        if file_version >= HistoryTypes.HISTORY_ENCRYPTION.value:
            is_encrypted = self.replay.read_bool()
            encryption_key_size = self.replay.read_uint32()
            encryption_key = self.replay.read_bytes(encryption_key_size)

        if (not is_live and is_encrypted and len(encryption_key) == 0):
            logger.error(
                "Completed replay is marked encrypted but has no key!")
            raise InvalidReplayException()

        if (is_live and is_encrypted):
            logger.error(
                "Replay is marked encrypted but not yet marked as completed!")
            raise InvalidReplayException()

        self.meta = Meta(
            file_version=file_version,
            lenght_in_ms=lenght_in_ms,
            network_version=network_version,
            change_list=change_list,
            friendly_name=friendly_name,
            is_live=is_live,
            time_stamp=time_stamp,
            is_compressed=is_compressed,
            is_encrypted=is_encrypted,
            encryption_key=encryption_key,
        )
Example #5
0
    def __enter__(self):
        logger.info(f'__enter__() replay file {self.src}')

        if isinstance(self.src, str):
            self._file = open(self.src, 'rb')
            self._close_on_exit = True
        elif isinstance(self.src, bytes):
            self._file = self.src
        else:
            raise TypeError()

        self.replay = ConstBitStreamWrapper(self._file)
        self.parse_meta()
        self.parse_chunks()
        return self
Example #6
0
    def parse_meta(self):
        """ Parse metadata of the file replay (Unreal Engine) """
        logger.info('parse_meta()')

        magic = self.replay.read_uint32()
        if (magic != FILE_MAGIC):
            raise InvalidReplayException()
        file_version = self.replay.read_uint32()
        lenght_in_ms = self.replay.read_uint32()
        network_version = self.replay.read_uint32()
        change_list = self.replay.read_uint32()
        friendly_name = self.replay.read_string()
        is_live = self.replay.read_uint32()

        if file_version >= HistoryTypes.HISTORY_RECORDED_TIMESTAMP.value:
            time_stamp = self.replay.read_uint64()
        if file_version >= HistoryTypes.HISTORY_COMPRESSION.value:
            is_compressed = self.replay.read_uint32()
Example #7
0
    def parse_header(self, size):
        """ Parse metadata of the file replay (Fortnite) """
        logger.info('parse_header()')

        magic = self.replay.read_uint32()
        if (magic != NETWORK_MAGIC):
            raise InvalidReplayException()
        network_version = self.replay.read_uint32()
        network_checksum = self.replay.read_uint32()
        engine_network_version = self.replay.read_uint32()
        game_network_protocol = self.replay.read_uint32()

        if network_version > HeaderTypes.HEADER_GUID.value:
            guid = self.replay.read_guid()
        else:
            guid = ""

        major = self.replay.read_uint16()
        minor = self.replay.read_uint16()
        patch = self.replay.read_uint16()
        changelist = self.replay.read_uint32()
        branch = self.replay.read_string()

        levelnames_and_times = self.replay.read_tuple_array(
            self.replay.read_string, self.replay.read_uint32)
        flags = self.replay.read_uint32()
        game_specific_data = self.replay.read_array(self.replay.read_string)

        self.header = Header(
            network_version=network_version,
            network_checksum=network_checksum,
            engine_network_version=engine_network_version,
            game_network_protocol=game_network_protocol,
            guid=guid,
            major=major,
            minor=minor,
            patch=patch,
            changelist=changelist,
            branch=branch,
            levelnames_and_times=levelnames_and_times,
            flags=flags,
            game_specific_data=game_specific_data,
        )
Example #8
0
    def parse_chunks(self):
        """ Parse chunks of the file replay """
        logger.info('parse_chunks()')

        while (self.replay.pos < len(self.replay)):
            chunk_type = self.replay.read_uint32()
            chunk_size = self.replay.read_int32()
            offset = self.replay.bytepos

            if chunk_type == ChunkTypes.CHECKPOINT.value:
                self.parse_checkpoint()

            elif chunk_type == ChunkTypes.EVENT.value:
                self.parse_event()

            elif chunk_type == ChunkTypes.REPLAYDATA.value:
                self.parse_replaydata()

            elif chunk_type == ChunkTypes.HEADER.value:
                self.parse_header(chunk_size)

            self.replay.bytepos = offset + chunk_size
Example #9
0
    def __exit__(self, *args):
        logger.info(f'__exit__() replay file {self.src}')

        if self._close_on_exit:
            self._file.close()
 def parse_checkpoint(self):
     """ Parse snapshot of the game environment """
     logger.info('parse_checkpoint()')
     checkpointId = self.replay.read_string()
     checkpoint = self.replay.read_string()