def addFileToLayout(arc, folderName, name, data): fileAdded = False for folder in arc.contents: if isinstance(folder, SarcLib.Folder) and folder.name == "lyt_root": for lytFolder in folder.contents: if isinstance(lytFolder, SarcLib.Folder) and lytFolder.name == folderName: for file in lytFolder.contents: if isinstance(file, SarcLib.File) and file.name == name: lytFolder.removeFile(file) break file = SarcLib.File() file.name = name file.data = data lytFolder.addFile(file) fileAdded = True if fileAdded: break if fileAdded: break if fileAdded: print("Added: %s" % name) else: print("Something went wrong while adding %s!" % name) return arc
def save(self): """ Save the level back to a file """ # Make a new archive newArchive = SarcLib.SARC_Archive() # Create a folder within the archive courseFolder = SarcLib.Folder('course') newArchive.addFolder(courseFolder) outerArchive = SarcLib.SARC_Archive() # Go through the areas, save them and add them back to the archive for areanum, area in enumerate(self.areas): course, L0, L1, L2 = area.save() if course is not None: courseFolder.addFile(SarcLib.File('course%d.bin' % (areanum + 1), course)) if L0 is not None: courseFolder.addFile(SarcLib.File('course%d_bgdatL0.bin' % (areanum + 1), L0)) if L1 is not None: courseFolder.addFile(SarcLib.File('course%d_bgdatL1.bin' % (areanum + 1), L1)) if L2 is not None: courseFolder.addFile(SarcLib.File('course%d_bgdatL2.bin' % (areanum + 1), L2)) # I need to kick in tileset saving here if area.tileset0 and area.tileset0Obj and not exists(outerArchive, area.tileset0): outerArchive.addFile(SarcLib.File(area.tileset0, SaveTileset(area.tileset0, area.tileset0Obj))) if area.tileset1 and area.tileset1Obj and not exists(outerArchive, area.tileset1): outerArchive.addFile(SarcLib.File(area.tileset1, SaveTileset(area.tileset1, area.tileset1Obj))) if area.tileset2 and area.tileset2Obj and not exists(outerArchive, area.tileset2): outerArchive.addFile(SarcLib.File(area.tileset2, SaveTileset(area.tileset2, area.tileset2Obj))) if area.tileset3 and area.tileset3Obj and not exists(outerArchive, area.tileset3): outerArchive.addFile(SarcLib.File(area.tileset3, SaveTileset(area.tileset3, area.tileset3Obj))) outerArchive.addFile(SarcLib.File(self.name, newArchive.save()[0])) return outerArchive.save()[0]
def save(self): arc = SarcLib.SARC_Archive() self.addSpriteFiles() # Look up every tileset used in each area tilesets_names = [] for area_SARC in self.areas: if area_SARC.tileset0 not in ('', None): tilesets_names.append(area_SARC.tileset0) if area_SARC.tileset1 not in ('', None): tilesets_names.append(area_SARC.tileset1) if area_SARC.tileset2 not in ('', None): tilesets_names.append(area_SARC.tileset2) if area_SARC.tileset3 not in ('', None): tilesets_names.append(area_SARC.tileset3) tilesets_names = tuple(set(tilesets_names)) # Add each tileset to our archive for tileset_name in tilesets_names: if tileset_name not in self.szsData: if os.path.isfile( os.path.join(globals.mod_path, 'Stage/Texture/%s.szs' % tileset_name)): with open( os.path.join(globals.mod_path, 'Stage/Texture/%s.szs' % tileset_name), "rb") as inf: self.szsData[tileset_name] = DecompYaz0(inf.read()) else: print("Tileset %s not found!" % tileset_name) for file in self.szsData: arc.addFile(SarcLib.File(file, self.szsData[file])) return arc.save()[0]
def save(self): """ Save the level back to a file """ # Make a new archive newArchive = SarcLib.SARC_Archive() # Create a folder within the archive courseFolder = SarcLib.Folder('course') newArchive.addFolder(courseFolder) # Go through the areas, save them and add them back to the archive for areanum, area in enumerate(self.areas): course, L0, L1, L2 = area.save() if course is not None: courseFolder.addFile( SarcLib.File('course%d.bin' % (areanum + 1), course)) if L0 is not None: courseFolder.addFile( SarcLib.File('course%d_bgdatL0.bin' % (areanum + 1), L0)) if L1 is not None: courseFolder.addFile( SarcLib.File('course%d_bgdatL1.bin' % (areanum + 1), L1)) if L2 is not None: courseFolder.addFile( SarcLib.File('course%d_bgdatL2.bin' % (areanum + 1), L2)) outerArchive = SarcLib.SARC_Archive() outerArchive.addFile(SarcLib.File('level', newArchive.save()[0])) outerArchive.addFile(SarcLib.File('levelname', b'level')) return outerArchive.save()[0]
def pack(root, endianness, level, outname): """ Pack the files and folders in the root folder. """ if "\\" in root: root = "/".join(root.split("\\")) if root[-1] == "/": root = root[:-1] arc = SarcLib.SARC_Archive(endianness=endianness) lenroot = len(root.split("/")) for path, dirs, files in os.walk(root): if "\\" in path: path = "/".join(path.split("\\")) lenpath = len(path.split("/")) if lenpath == lenroot: path = "" else: path = "/".join(path.split("/")[lenroot - lenpath:]) for file in files: if path: filename = ''.join([path, "/", file]) else: filename = file print(filename) fullname = ''.join([root, "/", filename]) i = 0 for folder in filename.split("/")[:-1]: if not i: exec( "folder%i = SarcLib.Folder(folder + '/'); arc.addFolder(folder%i)" .replace('%i', str(i))) else: exec( "folder%i = SarcLib.Folder(folder + '/'); folder%m.addFolder(folder%i)" .replace('%i', str(i)).replace('%m', str(i - 1))) i += 1 with open(fullname, "rb") as f: inb = f.read() hasFilename = True if file[:5] == "hash_": hasFilename = False if not i: arc.addFile(SarcLib.File(file, inb, hasFilename)) else: exec("folder%m.addFile(SarcLib.File(file, inb, hasFilename))". replace('%m', str(i - 1))) data, maxAlignment = arc.save() if level != -1: outData = libyaz0.compress(data, maxAlignment, level) del data if not outname: outname = ''.join([root, ".szs"]) else: outData = data if not outname: outname = ''.join([root, ".sarc"]) with open(outname, "wb+") as output: output.write(outData)
def saveNewArea(self, innerfilename, course_new, L0_new, L1_new, L2_new): """ Save the level back to a file (when adding a new or deleting an existing Area) """ # Make a new archive newArchive = SarcLib.SARC_Archive() # Create a folder within the archive courseFolder = SarcLib.Folder('course') newArchive.addFolder(courseFolder) # Go through the areas, save them and add them back to the archive for areanum, area in enumerate(self.areas): course, L0, L1, L2 = area.save(True) if course is not None: courseFolder.addFile( SarcLib.File('course%d.bin' % (areanum + 1), course)) if L0 is not None: courseFolder.addFile( SarcLib.File('course%d_bgdatL0.bin' % (areanum + 1), L0)) if L1 is not None: courseFolder.addFile( SarcLib.File('course%d_bgdatL1.bin' % (areanum + 1), L1)) if L2 is not None: courseFolder.addFile( SarcLib.File('course%d_bgdatL2.bin' % (areanum + 1), L2)) if course_new is not None: courseFolder.addFile( SarcLib.File('course%d.bin' % (len(self.areas) + 1), course_new)) if L0_new is not None: courseFolder.addFile( SarcLib.File('course%d_bgdatL0.bin' % (len(self.areas) + 1), L0_new)) if L1_new is not None: courseFolder.addFile( SarcLib.File('course%d_bgdatL1.bin' % (len(self.areas) + 1), L1_new)) if L2_new is not None: courseFolder.addFile( SarcLib.File('course%d_bgdatL2.bin' % (len(self.areas) + 1), L2_new)) # Here we have the new inner-SARC savedata innersarc = newArchive.save()[0] # Now make an outer SARC outerArchive = SarcLib.SARC_Archive() # Add the innersarc to it outerArchive.addFile(SarcLib.File(innerfilename, innersarc)) # Make it easy for future Miyamotos to pick out the innersarc level name outerArchive.addFile( SarcLib.File('levelname', innerfilename.encode('utf-8'))) # Add all the other stuff, too for szsThingName in globals.szsData: if szsThingName in [globals.levelNameCache, 'levelname']: continue outerArchive.addFile( SarcLib.File(szsThingName, globals.szsData[szsThingName])) # Save the outer sarc and return it return outerArchive.save()[0]
def save(self, innerfilename): """ Save the level back to a file """ # Make a new archive newArchive = SarcLib.SARC_Archive() # Create a folder within the archive courseFolder = SarcLib.Folder('course') newArchive.addFolder(courseFolder) # Go through the areas, save them and add them back to the archive for areanum, area in enumerate(self.areas): course, L0, L1, L2 = area.save() if course is not None: courseFolder.addFile( SarcLib.File('course%d.bin' % (areanum + 1), course)) if L0 is not None: courseFolder.addFile( SarcLib.File('course%d_bgdatL0.bin' % (areanum + 1), L0)) if L1 is not None: courseFolder.addFile( SarcLib.File('course%d_bgdatL1.bin' % (areanum + 1), L1)) if L2 is not None: courseFolder.addFile( SarcLib.File('course%d_bgdatL2.bin' % (areanum + 1), L2)) # Here we have the new inner-SARC savedata innersarc = newArchive.save()[0] globals.szsData[innerfilename] = innersarc # Now make an outer SARC outerArchive = SarcLib.SARC_Archive() # Add the innersarc to it outerArchive.addFile(SarcLib.File(innerfilename, innersarc)) # Make it easy for future Miyamotos to pick out the innersarc level name outerArchive.addFile( SarcLib.File('levelname', innerfilename.encode('utf-8'))) globals.szsData['levelname'] = innerfilename.encode('utf-8') # Save all the tilesets if globals.TilesetEdited or globals.OverrideTilesetSaving: if globals.Area.tileset1: tilesetData = SaveTileset(1) if tilesetData: globals.szsData[globals.Area.tileset1] = tilesetData if globals.Area.tileset2: tilesetData = SaveTileset(2) if tilesetData: globals.szsData[globals.Area.tileset2] = tilesetData if globals.Area.tileset3: tilesetData = SaveTileset(3) if tilesetData: globals.szsData[globals.Area.tileset3] = tilesetData # Add all the other stuff, too if os.path.isdir(globals.miyamoto_path + '/data'): szsNewData = {} szsNewData[innerfilename] = innersarc szsNewData['levelname'] = innerfilename.encode('utf-8') paths = [ globals.miyamoto_path + '/miyamotodata/spriteresources.xml' ] for path in globals.gamedef.recursiveFiles('spriteresources'): if path: paths.append( os.path.join( globals.miyamoto_path, path if isinstance(path, str) else path.path)) sprites_xml = {} for path in paths: # Read the sprites resources xml tree = etree.parse(path) root = tree.getroot() # Get all sprites' filenames and add them to a list for sprite in root.iter('sprite'): id = int(sprite.get('id')) name = [] for id2 in sprite: name.append(id2.get('name')) sprites_xml[id] = list(name) # Look up every sprite and tileset used in each area sprites_SARC = [] tilesets_names = [] for area_SARC in globals.Level.areas: for sprite in area_SARC.sprites: sprites_SARC.append(sprite.type) if area_SARC.tileset0 not in ('', None): tilesets_names.append(area_SARC.tileset0) if area_SARC.tileset1 not in ('', None): tilesets_names.append(area_SARC.tileset1) if area_SARC.tileset2 not in ('', None): tilesets_names.append(area_SARC.tileset2) if area_SARC.tileset3 not in ('', None): tilesets_names.append(area_SARC.tileset3) sprites_SARC = list(set(sprites_SARC)) tilesets_names = list(set(tilesets_names)) # Sort the filenames for each "used" sprite sprites_names = [] for sprite in sprites_SARC: if sprite in sprites_xml: for sprite_name in sprites_xml[sprite]: sprites_names.append(sprite_name) sprites_names = list(set(sprites_names)) # Look up each needed file and add it to our archive for sprite_name in sprites_names: # Get it from inside the original archive if not globals.OverwriteSprite and sprite_name in globals.szsData: outerArchive.addFile( SarcLib.File(sprite_name, globals.szsData[sprite_name])) szsNewData[sprite_name] = globals.szsData[sprite_name] # Get it from the "custom" data folder elif os.path.isfile(globals.miyamoto_path + '/data/custom/' + sprite_name): with open( globals.miyamoto_path + '/data/custom/' + sprite_name, 'rb') as f: f1 = f.read() outerArchive.addFile(SarcLib.File(sprite_name, f1)) szsNewData[sprite_name] = f1 # Get it from the data folder elif os.path.isfile(globals.miyamoto_path + '/data/' + sprite_name): with open(globals.miyamoto_path + '/data/' + sprite_name, 'rb') as f: f1 = f.read() outerArchive.addFile(SarcLib.File(sprite_name, f1)) szsNewData[sprite_name] = f1 # Throw a warning because the file was not found... else: print("WARNING: Could not find the file: %s" % sprite_name) print("Expect the level to crash ingame...") # Add each tileset to our archive for tileset_name in tilesets_names: if tileset_name in globals.szsData: outerArchive.addFile( SarcLib.File(tileset_name, globals.szsData[tileset_name])) szsNewData[tileset_name] = globals.szsData[tileset_name] globals.szsData = szsNewData else: # data folder not found, copy the files for szsThingName in globals.szsData: if szsThingName in [ globals.levelNameCache, innerfilename, 'levelname' ]: continue outerArchive.addFile( SarcLib.File(szsThingName, globals.szsData[szsThingName])) # Save the outer sarc and return it return outerArchive.save()[0]
def SaveTileset(name, tilesetObj): """ Saves a tileset from a specific slot """ defs = tilesetObj.defs if defs is None: return False colldata = tilesetObj.colldata deffile = b'' indexfile = b'' for obj in defs: if obj is None: break indexfile += struct.pack('>HBBxB', len(deffile), obj.width, obj.height, obj.randByte) for row in obj.rows: for tile in row: if len(tile) == 3: byte2 = tile[2] << 2 byte2 |= (tile[1] >> 8) & 3 # Slot deffile += bytes([tile[0], tile[1] & 0xFF, byte2]) else: deffile += bytes(tile) deffile += b'\xFE' deffile += b'\xFF' arc = SarcLib.SARC_Archive() tex = SarcLib.Folder('BG_tex') arc.addFolder(tex) tex.addFile(SarcLib.File('%s.gtx' % name, writeGTX(*tilesetObj.img))) tex.addFile(SarcLib.File('%s_nml.gtx' % name, writeGTX(*tilesetObj.nml))) if tilesetObj.hatena_anime: tex.addFile(SarcLib.File('hatena_anime.gtx', writeGTX(*tilesetObj.hatena_anime))) if tilesetObj.block_anime: tex.addFile(SarcLib.File('block_anime.gtx', writeGTX(*tilesetObj.block_anime))) if tilesetObj.hatena_anime_L: tex.addFile(SarcLib.File('hatena_anime_L.gtx', writeGTX(*tilesetObj.hatena_anime_L))) if tilesetObj.block_anime_L: tex.addFile(SarcLib.File('block_anime_L.gtx', writeGTX(*tilesetObj.block_anime_L))) if tilesetObj.tuka_coin_anime: tex.addFile(SarcLib.File('tuka_coin_anime.gtx', writeGTX(*tilesetObj.tuka_coin_anime))) if tilesetObj.belt_conveyor_anime: tex.addFile(SarcLib.File('belt_conveyor_anime.gtx', writeGTX(*tilesetObj.belt_conveyor_anime))) chk = SarcLib.Folder('BG_chk') arc.addFolder(chk) chk.addFile(SarcLib.File('d_bgchk_%s.bin' % name, colldata)) unt = SarcLib.Folder('BG_unt') arc.addFolder(unt) unt.addFile(SarcLib.File('%s.bin' % name, deffile)) unt.addFile(SarcLib.File('%s_hd.bin' % name, indexfile)) return arc.save()[0]
def change_water(path, water_type=0): water_types = [ 'Normal Water', 'Hot Water', 'Poison', 'Lava', 'Ice Water', 'Mud', 'Clear Water', 'Sea Water' ] for parent_dir, dirs, files in os.walk(path): for file in files: current_path = '{0}{1}'.format(parent_dir, file) if 'water.extm.sstera' not in current_path: continue with open(current_path, 'rb') as infile: infile_binary = infile.read() while libyaz0.IsYazCompressed(infile_binary): infile_binary = libyaz0.decompress(infile_binary) path, extension = os.path.splitext(current_path) filename = os.path.basename(current_path) if infile_binary[0x00:0x04] != b'SARC': print('Not a sarc. :(') sarc = SarcLib.SARC_Archive() sarc.load(infile_binary) with tempfile.TemporaryDirectory() as temp_dir: for sarc_file in sarc.contents: if isinstance(sarc_file, SarcLib.File): pos = 0 data = bytearray(sarc_file.data) while pos + 8 <= len(sarc_file.data): height, x_axis_flow_rate, z_axis_flow_rate, mate_check, mate = \ struct.unpack('<3H2B', data[pos:pos + 0x08]) # height = 0x24cc # x_axis_flow_rate = 0x8125 # z_axis_flow_rate = 0x8125 mate = water_type mate_check = mate + 3 data[pos:pos + 0x08] = struct.pack( '<3H2B', height, x_axis_flow_rate, z_axis_flow_rate, mate_check, mate) pos += 0x08 with open( '{0}/{1}'.format(temp_dir, sarc_file.name), 'wb+') as outfile: outfile.write(data) sarc = SarcLib.SARC_Archive(endianness='>') for path, dirs, files in os.walk(temp_dir): for file in files: with open('{0}/{1}'.format(path, file), 'rb') as infile: sarc.addFile( SarcLib.File(file, infile.read(), True)) data, alignment = sarc.save() data = libyaz0.compress(data, alignment, 5) destination = '{0}/output/MainField - {1}'.format( os.path.dirname(__file__), water_types[water_type]) if not os.path.exists('{0}/output/'.format( os.path.dirname(__file__))): os.makedirs('{0}/output/'.format( os.path.dirname(__file__))) if not os.path.exists('{0}/output/MainField - {1}'.format( os.path.dirname(__file__), water_types[water_type])): os.makedirs('{0}/output/MainField - {1}'.format( os.path.dirname(__file__), water_types[water_type])) with open('{0}/{1}'.format(destination, filename), 'wb+') as outfile: print('saving {0}...'.format(filename)) outfile.write(data)