class ReadW3E(): def __init__(self, filename): self.read = DataReader(filename) self.mapInfo = self.ReadMap() def ReadMap(self): mapInfo = self.ReadHeader() mapInfo["info"] = [] for i in xrange((mapInfo["width"])*(mapInfo["height"])): mapInfo["info"].append(self.ReadTile()) return mapInfo def ReadHeader(self): data = {} data["fileID"] = self.read.charArray(4) data["formatVersion"] = self.read.int() data["mainTileSet"] = self.read.char() data["customTileSet"] = self.read.int() #actually is a boolean data["groundTileSets"] = self.ReadTileset() data["cliffTileSets"] = self.ReadTileset() data["width"] = self.read.int() data["height"] = self.read.int() data["offsetX"] = self.read.float() data["offsetY"] = self.read.float() return data def ReadTileset(self): length = self.read.int() info = [] for i in range(0,length): info.append(self.read.charArray(4)) return info def ReadTile(self): tmpData = {} tmpData["groundHeight"] = self.read.short() tmpData["waterLevel"] = self.read.short() #bit 15 is used for boundary flag 1 tmpData["nibble1"] = self.read.byte() tmpData["textureDetails"] = self.read.byte() tmpData["nibble2"] = self.read.byte() return tmpData
class ObjectReader(): from DataReader import DataReader #These are the file extentions that have more reading #This is to OptionalInts = [ "w3d", "w3a", "w3q" ] variableTypes = [] def __init__(self, filename): self.read = DataReader(filename) self.variableTypes = [ self.read.int, self.read.float, self.read.float, self.read.string ] self.fileVersion = self.read.int() self.originalInfo = self.readTable() self.customInfo = self.readTable() def readMod(self): modInfo = {} modInfo["ID"] = self.read.charArray(4) varType = self.read.int() if filename.split(".")[1] in self.OptionalInts: modInfo["level"] = self.read.int() modInfo["pointer"] = self.read.int() print(varType) modInfo["value"] = self.variableTypes[varType]() self.read.int() #verify / end thing return modInfo def readObject(self): objectData = {} objectData["oldID"] = self.read.charArray(4) objectData["newID"] = self.read.charArray(4) modCount = self.read.int() objectData["mods"] = [] for i in xrange(modCount): objectData["mods"].append(self.readMod()) return objectData def readTable(self): tmpLen = self.read.int() tmpInfo = [] if tmpLen > 0: for i in xrange(tmpLen): tmpInfo.append(self.readObject()) return tmpInfo
def read_header(self): """Read the header of a MPQ archive.""" def read_mpq_header(offset=None): if offset: self.file.seek(offset) data = self.file.read(32) header = MPQFileHeader._make( struct.unpack(MPQFileHeader.struct_format, data)) header = header._asdict() if header['format_version'] == 1: data = self.file.read(12) extended_header = MPQFileHeaderExt._make( struct.unpack(MPQFileHeaderExt.struct_format, data)) header.update(extended_header._asdict()) return header def read_mpq_user_data_header(): data = self.file.read(16) header = MPQUserDataHeader._make( struct.unpack(MPQUserDataHeader.struct_format, data)) header = header._asdict() header['content'] = self.file.read(header['user_data_header_size']) return header magic = self.file.read(4) self.file.seek(0) print(magic) if magic == "HM3W": datReader = DataReader(self.file) header = {} ## should be HM3W header["wc3map_magic"] = datReader.charArray(4) ## unknown datReader.int() header["wc3map_mapName"] = datReader.string() """ 0x0001: 1=hide minimap in preview screens 0x0002: 1=modify ally priorities 0x0004: 1=melee map 0x0008: 1=playable map size was large and has never been reduced to medium 0x0010: 1=masked area are partially visible 0x0020: 1=fixed player setting for custom forces 0x0040: 1=use custom forces 0x0080: 1=use custom techtree 0x0100: 1=use custom abilities 0x0200: 1=use custom upgrades 0x0400: 1=map properties menu opened at least once since map creation 0x0800: 1=show water waves on cliff shores 0x1000: 1=show water waves on rolling shores """ header["wc3map_mapFlags"] = datReader.flags() header["wc3map_maxPlayers"] = datReader.int() self.file.read(512 - datReader.index) print ("Now position:", self.file.tell()) else: ## If the magic isn't HM3W, we will skip the first 512 bytes of the ## file anyway self.file.seek(512) print(self.file.tell()) magic = self.file.read(4) self.file.seek(512) print( len(magic)) print(magic, hex(ord(magic[3])) ) if magic == b'MPQ\x1a': header.update(read_mpq_header()) header['offset'] = 512 elif magic == b'MPQ\x1b': user_data_header = read_mpq_user_data_header() header.update(read_mpq_header(user_data_header['mpq_header_offset'])) header['offset'] = user_data_header['mpq_header_offset'] header['user_data_header'] = user_data_header else: raise ValueError("Invalid file header.") return header