def parse_version(value): try: return dbc.WowVersion(value) except ValueError as e: # User may have given just a build number, try a workaround and warn if value.isdigit(): logging.warn('Presuming -b input "{}" as a build number for World of Warcraft 8.0.1, this will become an error in 8.1.0'.format( value)) return dbc.WowVersion('8.0.1.{}'.format(value)) raise argparse.ArgumentTypeError(e)
def __find_newest_file(self, path): valid_files = [] for f in path.iterdir(): try: ver = dbc.WowVersion(f.stem) except: continue valid_files.append((ver, f)) # Format file patch level should match the build patch level given patch_files = list( filter( lambda x: x[0].patch_level() == self.options.build.patch_level( ), valid_files)) # Nothing usable found for the patch level, just grab all we can and # use the highest version format file we can find (in relation to build option) if len(patch_files) == 0: patch_files = valid_files patch_files.sort() idx = 0 while idx < len( patch_files) and patch_files[idx][0] <= self.options.build: idx += 1 logging.debug('Opened format file %s', patch_files[idx - 1][1]) return patch_files[idx - 1][1]
sys.exit(1) g.generate() args = { 'file': 'CombatRatings.txt', 'comment': '// Combat rating values for level 1 - %d, wow build %s\n' % ( options.level, options.build), 'values': [ 'Dodge', 'Parry', 'Block', 'Hit - Melee', 'Hit - Ranged', 'Hit - Spell', 'Crit - Melee', 'Crit - Ranged', 'Crit - Spell', 'Resilience - Player Damage', 'Lifesteal', 'Haste - Melee', 'Haste - Ranged', 'Haste - Spell', 'Expertise', 'Mastery', 'PvP Power', 'Versatility - Damage Done', 'Versatility - Healing Done', 'Versatility - Damage Taken', 'Speed', 'Avoidance' ] } if options.build >= dbc.WowVersion(8, 3, 0, 0): args['values'] += ['Corruption', 'Corruption Resistance'] else: args['values'] += ['Multi-Strike', 'Readiness'] g = CSVDataGenerator(options, args) if not g.initialize(): sys.exit(1) g.generate() combat_rating_values = [ 'Rating Multiplier' ] # CombatRatingsMultByILvl.txt gets more complicated starting 7.1.5, # earliest build published to the public is 23038 on PTR if options.build >= 23038: combat_rating_values = [ 'Armor Multiplier', 'Weapon Multiplier', 'Trinket Multiplier', 'Jewelry Multiplier' ]
def parse_blocks(self): if self.options.build < dbc.WowVersion(8, 1, 5, 0): entry_unpacker = struct.Struct('<4sIiIIIB3s') else: entry_unpacker = struct.Struct('<4sIIIIB3s') n_entries = 0 all_entries = [] while self.parse_offset < len(self.data): if self.options.build < dbc.WowVersion(8, 1, 5, 0): magic, game_type, unk_2, length, sig, record_id, enabled, pad = \ entry_unpacker.unpack_from(self.data, self.parse_offset) else: magic, unk_2, sig, record_id, length, enabled, pad = \ entry_unpacker.unpack_from(self.data, self.parse_offset) if magic != b'XFTH': logging.error('Invalid hotfix magic %s', magic.decode('utf-8')) return False self.parse_offset += entry_unpacker.size entry = { 'record_id': record_id, 'unk_2': unk_2, 'enabled': enabled, 'length': length, 'offset': self.parse_offset, 'sig': sig, 'pad': codecs.encode(pad, 'hex').decode('utf-8') } if self.options.build < dbc.WowVersion(8, 1, 5, 0): entry['game_type'] = game_type if sig not in self.entries: self.entries[sig] = [] if enabled: self.entries[sig].append(entry) all_entries.append(entry) # Skip data self.parse_offset += length n_entries += 1 if self.options.debug: if self.options.build < dbc.WowVersion(8, 1, 5, 0): for entry in sorted(all_entries, key = lambda e: (e['unk_2'], e['sig'], e['record_id'])): logging.debug('entry: { %s }', ('record_id=%(record_id)-6u game_type=%(game_type)u table_hash=%(sig)#.8x ' + 'unk_2=%(unk_2)-5u enabled=%(enabled)u, unk_4=%(unk_4)-3u unk_5=%(unk_5)-3u ' + 'unk_6=%(unk_6)-3u length=%(length)-3u offset=%(offset)-7u') % entry) else: for entry in sorted(all_entries, key = lambda e: (e['sig'], e['record_id'])): logging.debug('entry: { %s }', ('record_id=%(record_id)-6u table_hash=%(sig)#.8x ' + 'unk_2=%(unk_2)#.8x enabled=%(enabled)u ' + 'length=%(length)-3u pad=%(pad)-6s offset=%(offset)-7u') % entry) logging.debug('Parsed %d hotfix entries', n_entries) return True
def parse_blocks(self): # For some reason, 9.1.0 builds do not use the version 8 format. if self.version < 8 or self.options.build.patch_level( ) == dbc.WowVersion(9, 1, 0, 0).patch_level(): entry_unpacker = struct.Struct('<4sIIIIB3s') else: entry_unpacker = struct.Struct('<4sIIIIIB3s') n_entries = 0 all_entries = [] while self.parse_offset < len(self.data): # For some reason, 9.1.0 builds do not use the version 8 format. if self.version < 8 or self.options.build.patch_level( ) == dbc.WowVersion(9, 1, 0, 0).patch_level(): magic, unk_2, sig, record_id, length, state, pad = \ entry_unpacker.unpack_from(self.data, self.parse_offset) unk_3 = None else: magic, unk_2, unk_3, sig, record_id, length, state, pad = \ entry_unpacker.unpack_from(self.data, self.parse_offset) if magic != b'XFTH': logging.error('Invalid hotfix magic %s', magic.decode('utf-8')) return False self.parse_offset += entry_unpacker.size entry = { 'record_id': record_id, 'unk_2': unk_2, 'unk_3': unk_3, 'state': state, 'length': length, 'offset': self.parse_offset, 'sig': sig, 'pad': codecs.encode(pad, 'hex').decode('utf-8') } if sig not in self.entries: self.entries[sig] = [] if state in [HotfixType.ENABLED, HotfixType.REMOVED]: self.entries[sig].append(entry) all_entries.append(entry) # Skip data self.parse_offset += length n_entries += 1 if self.options.debug: for entry in sorted(all_entries, key=lambda e: (e['sig'], e['record_id'])): logging.debug( 'entry: { %s }', ('record_id=%(record_id)-6u table_hash=%(sig)#.8x ' + 'unk_2=%(unk_2)#.8x state=%(state)u ' + 'length=%(length)-3u pad=%(pad)-6s offset=%(offset)-7u') % entry) logging.debug('Parsed %d hotfix entries', n_entries) return True