class Map(Resource): url_template = 'http://{0}.depot.battle.net:1119/{1}.s2ma' 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(StringIO(self.file)) self.minimap = self.archive.read_file('Minimap.tga') @classmethod def get_url(gateway, map_hash): if gateway and map_hash: return Map.url_template.format(gateway, map_hash) else: return None def load(self): self.read_game_strings() def read_game_strings(self): 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]
class Map(Resource): url_template = 'http://{0}.depot.battle.net:1119/{1}.s2ma' #: The unique hash used to identify this map on bnet's depots. hash = str() #: The gateway this map was posted to. #: Maps must be posted individually to each gateway. gateway = str() #: A URL reference to the location of this map on bnet's depots. url = str() #: The localized (only enUS supported right now) map name name = str() #: The map's author author = str() #: The map description as written by author description = str() #: A byte string representing the minimap in tga format. minimap = str() 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] @classmethod def get_url(cls, gateway, map_hash): """Builds a download URL for the map from its components.""" if gateway and map_hash: # it seems like sea maps are stored on us depots. gateway = 'us' if gateway=='sea' else gateway return cls.url_template.format(gateway, map_hash) else: return None
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 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
class Map(object): url_template = 'http://{0}.depot.battle.net:1119/{1}.s2ma' def __init__(self, gateway, map_hash, map_name=''): self.hash = map_hash.encode('hex') self.gateway = gateway self.url = Map.url_template.format(self.gateway, self.hash) self.name = map_name 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 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 read_game_events(protocol, archive: MPQArchive) -> dict: game_event_file = archive.read_file('replay.game.events') return protocol.decode_replay_game_events(game_event_file)
def read_details(protocol, archive: MPQArchive) -> dict: detail_file = archive.read_file('replay.details') return protocol.decode_replay_details(detail_file)
def read_initdata(protocol, archive: MPQArchive) -> dict: init_file = archive.read_file('replay.initData') return protocol.decode_replay_initdata(init_file)
def read_metadata(protocol, archive: MPQArchive) -> dict: return archive.read_file('replay.gamemetadata.json')
def read_tracker_events(protocol, archive: MPQArchive) -> dict: tracker_event_file = archive.read_file('replay.tracker.events') return protocol.decode_replay_tracker_events(tracker_event_file)
def read_attribute_events(protocol, archive: MPQArchive) -> dict: attrib_event_file = archive.read_file('replay.attributes.events') return protocol.decode_replay_attributes_events(attrib_event_file)
def __init__(self, replay, partial_parse=True, full_parse=True): self.filename = replay self.speed = "" self.release_string = "" self.build = "" self.type = "" self.category = "" self.is_ladder = False self.is_private = False self.map = "" self.realm = "" self.events = list() self.results = dict() self.teams = defaultdict(list) self.players = list() #Unordered list of Player self.player = PlayerDict() #Maps pid to Player self.events_by_type = dict() self.attributes = list() self.length = None # (minutes, seconds) tuple self.messages = list() self.seconds = None # Length of the game in seconds self.versions = None # (number,number,number,number) tuple self.recorder = None # Player object self.frames = None # Integer representing FPS self.winner_known = False # Set in parsers.DetailParser.load, should we hide this? self.file_time = None # Probably number milliseconds since EPOCH # Marked as private in case people want raw file access self._files = dict() # Files extracted from mpyq #Used internally to ensure parse ordering self.__parsed = dict(details=False, attributes=False, messages=False, events=False, initdata=False) # TODO: Change to something better # http://en.wikipedia.org/wiki/Epoch_(reference_date) # Notice that Windows and Mac have different EPOCHs, I wonder whether # this is different depending on the OS on which the replay was played. self.date = "" # Date when the game was played #Make sure the file exists and is readable, first and foremost if not os.access(self.filename, os.F_OK): raise ValueError("File at '%s' cannot be found" % self.filename) elif not os.access(self.filename, os.R_OK): raise ValueError("File at '%s' cannot be read" % self.filename) #Always parse the header first, the extract the files self._parse_header() #Manually extract the contents of SC2Replay file (bypass the listfile) archive = MPQArchive(replay, listfile=False) self._files['replay.initData'] = archive.read_file('replay.initData') self._files['replay.details'] = archive.read_file('replay.details') self._files['replay.attributes.events'] = archive.read_file('replay.attributes.events') self._files['replay.message.events'] = archive.read_file('replay.message.events') self._files['replay.game.events'] = archive.read_file('replay.game.events') #These are quickly parsed files that contain most of the game information #The order is important, I need some way to reinforce it in the future if partial_parse or full_parse: self._parse_initdata() self._parse_details() self._parse_attributes() self._parse_messages() #Parsing events takes forever, so only do this on request if full_parse: self._parse_events()