def __init__(self, map_file, filename=None, gateway=None, map_hash=None, **options): super(Map, self).__init__(map_file, filename, **options) self.hash = map_hash self.gateway = gateway self.url = Map.get_url(gateway, map_hash) self.archive = MPQArchive(map_file) self.minimap = self.archive.read_file('Minimap.tga') # This will only populate the fields for maps with enUS localizations. # Clearly this isn't a great solution but we can't be throwing exceptions # just because US English wasn't a concern of the map author. # TODO: Make this work regardless of the localizations available. game_strings = self.archive.read_file( 'enUS.SC2Data\LocalizedData\GameStrings.txt') if game_strings: for line in game_strings.split('\r\n'): parts = line.split('=') if parts[0] == 'DocInfo/Name': self.name = parts[1] elif parts[0] == 'DocInfo/Author': self.author = parts[1] elif parts[0] == 'DocInfo/DescLong': self.description = parts[1]
def read_file(filename, config=DefaultConfig()): if (os.path.splitext(filename)[1].lower() != '.sc2replay'): raise TypeError("Target file must of the SC2Replay file extension") with open(filename) as replay_file: release, frames = read_header(replay_file) replay = config.ReplayClass(filename, release, frames) archive = MPQArchive(filename, listfile=False) #Extract and Parse the relevant files for file, readers in config.readers.iteritems(): for reader in readers: if reader.reads(replay.build): reader.read(archive.read_file(file), replay) break else: raise NotYetImplementedError( "No parser was found that accepted the replay file;check configuration" ) #Do cleanup and post processing for processor in config.processors: replay = processor.process(replay) return replay
def extract_mmr_apm(path, your_id, opponent_id): try: archive = MPQArchive(path) players = json.loads( archive.extract()[b'replay.gamemetadata.json'])['Players'] if "MMR" not in players[opponent_id]: players[opponent_id]["MMR"] = "Unknown" if "MMR" not in players[your_id]: players[your_id]["MMR"] = "Unkown" return { "yourMMR": str(players[your_id]['MMR']), "opponentMMR": str(players[opponent_id]['MMR']), "yourAPM": str(players[your_id]['APM']), "opponentAPM": str(players[opponent_id]['APM']) } except Exception: traceback.print_exc() print("failed to parse mmr/apm for path {}".format(path)) return { "yourMMR": "Unknown", "opponentMMR": "Unknown", "yourAPM": "Unknown", "opponentAPM": "Unknown" }
def winners(filepath): archive = MPQArchive(str(filepath)) files = archive.extract() data = json.loads(files[b"replay.gamemetadata.json"]) result_by_playerid = {p["PlayerID"]: p["Result"] for p in data["Players"]} return { playerid: result == "Win" for playerid, result in result_by_playerid.items() }
def __init__(self, replay: str): self.archive = MPQArchive(replay) self.protocol = self.read_protocol(self.archive) self._initdata = None self._details = None self._events = None self._attributeevents = None self._trackerevents = None self._metadata = None
def __init__(self, base_path: Text, *archives: Text): """Create a new multi-archive. Args: base_path: The path to the WoW client. *archives: A list of MPQ archive names to load from the client. """ self.archives = [ MPQArchive(os.path.join(base_path, 'Data', a)) for a in archives ]
def parse_replay(self, filename): """ Given a Heroes of the Storm replay file (mpq archive), parses the file and returns a Replay object. """ try: logging.info("Attempting to parse replay: {}".format(filename)) mpq = MPQArchive(filename) replay = Replay() return self._parse_replay(replay, mpq) except Exception, e: logging.error( "Something went wrong with replay {}".format(filename)) logging.error("{0}\n{1}".format(str(e), repr(e))) return None
def load(self): print "Fetching map: {0}".format(self.url); self.file = urllib2.urlopen(self.url).read() print "Map Received" self.archive = MPQArchive(StringIO(self.file)) self.minimap = self.archive.read_file('Minimap.tga') self.game_strings = self.archive.read_file('enUS.SC2Data\LocalizedData\GameStrings.txt') for line in self.game_strings.split('\r\n'): parts = line.split('=') if parts[0] == 'DocInfo/Name': self.name = parts[1] elif parts[0] == 'DocInfo/Author': self.author = parts[1] elif parts[0] == 'DocInfo/DescLong': self.description = parts[1]
def extractResult(filepath): archive = MPQArchive(str(filepath)) files = archive.extract() data = json.loads(files[b"replay.gamemetadata.json"]) # print(data) result_by_playerid = {p["PlayerID"]: p["Result"] for p in data["Players"]} # print(data["Players"]) # print(result_by_playerid) return { playerid: result == "Win" for playerid, result in result_by_playerid.items() } # winners("./replays/MyBot_vs_DefaultRandomHard_DreamcatcherLE_11_05_063.SC2Replay")
def get_commands(filename): archive = MPQArchive(filename, listfile=False) script = archive.read_file('war3map.j') if not script: script = archive.read_file(r'Scripts\war3map.j') script = script.decode('utf-8', errors='replace') re_str = r'call TriggerRegisterPlayerChatEvent\([^,]*,([^,]*),[ ]*"([^"]*)"[ ]*,[^,]*\)' cmds = dict() for player, cmd in re.findall(re_str, script): if cmd not in cmds: cmds[cmd] = [] cmds[cmd].append(player.strip()) return cmds
def filter(self, replay): """Apply filter to a particular SC2Replay Args: replay (str): Absolute file path to a SC2Replay Returns: Replay metadata if matching filter else None """ # Extract JSON archive data from replay SC2_archive = MPQArchive(replay).extract() # Load JSON archive data metadata = json.loads(SC2_archive[b"replay.gamemetadata.json"].decode("utf-8")) # If game_version provided and non-matching then return None replay_game_version = int(metadata['DataBuild']) if self.game_version: if not self.game_version == replay_game_version: return None # If map_title provided and non-matching then return None replay_map_title = metadata['Title'] if self.map_title: if not self.map_title == replay_map_title: return None # Evaluate players and against APM, MMR, races, and winning_races threshholds players = metadata["Players"] raceFound = False for player in players: try: if player['APM'] < self.apm_threshold or player['MMR'] < self.mmr_threshold: return None player_race = player['AssignedRace'] if player_race in self.races: raceFound = True if player['Result'] == 'Win': if not player_race in self.winning_races: return None except KeyError: return None if not raceFound: return None # Replay has met all criteria so return it's metadata return metadata
def main(): """ Get command line arguments and invoke the command line functionality. """ filters = [] parser = argparse.ArgumentParser() parser.add_argument('replay_file', help='.SC2Replay file to load', nargs='?') parser.add_argument("--gameevents", help="print game events", action="store_true") parser.add_argument("--messageevents", help="print message events", action="store_true") parser.add_argument("--trackerevents", help="print tracker events", action="store_true") parser.add_argument("--attributeevents", help="print attributes events", action="store_true") parser.add_argument("--attributeparse", help="parse attributes events", action="store_true") parser.add_argument("--header", help="print protocol header", action="store_true") parser.add_argument("--metadata", help="print game metadata", action="store_true") parser.add_argument("--details", help="print protocol details", action="store_true") parser.add_argument("--details_backup", help="print protocol anoynmized details", action="store_true") parser.add_argument("--initdata", help="print protocol initdata", action="store_true") parser.add_argument("--all", help="print all data", action="store_true") parser.add_argument("--quiet", help="disable printing", action="store_true") parser.add_argument("--stats", help="print stats", action="store_true") parser.add_argument("--diff", help="diff two protocols", default=None, action="store") parser.add_argument("--versions", help="show all protocol versions", action="store_true") parser.add_argument("--types", help="show type information in event output", action="store_true") parser.add_argument("--json", help="print output as json", action="store_true") parser.add_argument("--ndjson", help="print output as ndjson (newline delimited)", action="store_true") parser.add_argument("--profile", help="Whether to profile or not", action="store_true") args = parser.parse_args() if args.profile: pr = cProfile.Profile() pr.enable() # TODO: clean up the command line arguments to allow cleaner sub-command # style commands # List all protocol versions if args.versions: files = list_all() pattern = re.compile('^protocol([0-9]+).py$') captured = [] for f in files: captured.append(pattern.match(f).group(1)) if len(captured) == 8: print(captured[0:8]) captured = [] print(captured) return # Diff two protocols if args.diff and args.diff is not None: version_list = args.diff.split(',') if len(version_list) < 2: print( "--diff requires two versions separated by comma e.g. --diff=1,2", file=sys.stderr) sys.exit(1) diff(version_list[0], version_list[1]) return # Check/test the replay file if args.replay_file is None: print(".S2Replay file not specified", file=sys.stderr) sys.exit(1) archive = MPQArchive(args.replay_file) filters = [] if args.json: filters.insert(0, JSONOutputFilter(sys.stdout)) elif args.ndjson: filters.insert(0, NDJSONOutputFilter(sys.stdout)) elif not args.quiet: filters.insert(0, PrettyPrintFilter(sys.stdout)) if args.types: filters.insert(0, TypeDumpFilter()) if args.stats: filters.insert(0, StatCollectionFilter()) def process_event(event): for f in filters: event = f.process(event) # Read the protocol header, this can be read with any protocol contents = archive.header['user_data_header']['content'] header = latest().decode_replay_header(contents) if args.header: process_event(header) # The header's baseBuild determines which protocol to use baseBuild = header['m_version']['m_baseBuild'] try: protocol = build(baseBuild) except Exception as e: print('Unsupported base build: {0} ({1!s})'.format(baseBuild, e), file=sys.stderr) sys.exit(1) # Process game metadata if args.all or args.metadata: contents = read_contents(archive, 'replay.gamemetadata.json') process_event(json.loads(contents)) # Print protocol details if args.all or args.details: contents = read_contents(archive, 'replay.details') details = protocol.decode_replay_details(contents) details = process_details_data(details) process_event(details) # Print protocol details if args.all or args.details_backup: contents = read_contents(archive, 'replay.details.backup') details_backup = protocol.decode_replay_details(contents) details_backup = process_details_data(details_backup) process_event(details_backup) # Print protocol init data if args.all or args.initdata: contents = read_contents(archive, 'replay.initData') initdata = protocol.decode_replay_initdata(contents) initdata = process_init_data(initdata) process_event(initdata) # Print game events and/or game events stats if args.all or args.gameevents: contents = read_contents(archive, 'replay.game.events') map(process_event, protocol.decode_replay_game_events(contents)) # Print message events if args.all or args.messageevents: contents = read_contents(archive, 'replay.message.events') map(process_event, protocol.decode_replay_message_events(contents)) # Print tracker events if args.all or args.trackerevents: if hasattr(protocol, 'decode_replay_tracker_events'): contents = read_contents(archive, 'replay.tracker.events') map(process_event, protocol.decode_replay_tracker_events(contents)) # Print attributes events if args.all or args.attributeevents or args.attributeparse: contents = read_contents(archive, 'replay.attributes.events') attributes = protocol.decode_replay_attributes_events(contents) # Process raw attribute events structure if args.attributeevents: process_event(attributes) # Convert attributes to higher level requested data, will # call prcess_event for each new event that it creates if args.attributeparse: process_scope_attributes(attributes['scopes'], process_event) for f in filters: f.finish() if args.profile: pr.disable() print("Profiler Results") print("----------------") s = get_stream() sortby = 'cumulative' ps = pstats.Stats(pr, stream=s).sort_stats(sortby) ps.print_stats() print(s.getvalue())
local_regex = re.compile(r'^[a-z][a-z][A-Z][A-Z]\.SC2Data\\LocalizedData\\GameStrings\.txt$') for filename in mpq.files: if filename == thumbnail_name: data = mpq.read_file(filename) f = open(filename, 'wb') f.write(data) f.close() elif local_regex.match(filename): data = mpq.read_file(filename) f = open(filename, 'wb') if data != None: f.write(data) f.close() if len(sys.argv) < 2: print 'syntax: extract_map.py <map> [thumbnail-name] [/output/dir/]' sys.exit(1) mapdir = os.path.dirname(sys.argv[1]) if mapdir == "": mapdir = "." os.chdir(mapdir) archive = MPQArchive(sys.argv[1]) outdir = None thumbnail_name = None if len(sys.argv) >= 3: outdir = sys.argv[2] if len(sys.argv) >= 4: outdir = sys.argv[3] extract_map(archive, outdir)
def test_init_with_file(self): self.archive = MPQArchive(open(TEST_DIR + 'test.SC2Replay', 'rb'))
def setUp(self): self.archive = MPQArchive(TEST_DIR + 'test.SC2Replay')