diff --git a/Makefile b/Makefile index 2cd79d6bfa9..7d874ea2ee0 100644 --- a/Makefile +++ b/Makefile @@ -184,7 +184,15 @@ shift: dirs $(DOL_SHIFT) game: shift $(MAKE) rels @mkdir -p game - @$(PYTHON) tools/package_game_assets.py ./game $(BUILD_DIR) + @$(PYTHON) tools/package_game_assets.py ./game $(BUILD_PATH) copyCode + +game-nocompile: + @mkdir -p game + @$(PYTHON) tools/package_game_assets.py ./game $(BUILD_PATH) noCopyCode + +rungame-nocompile: game-nocompile + @echo If you are playing on a shifted game make sure Hyrule Field Speed hack is disabled in dolphin! + dolphin-emu $(BUILD_DIR)/game/sys/main.dol iso: game @$(PYTHON) tools/packageISO.py $(BUILD_DIR)/game/ $(TARGET_ISO) diff --git a/tools/extract_game_assets.py b/tools/extract_game_assets.py index fc110081355..722e63f339e 100644 --- a/tools/extract_game_assets.py +++ b/tools/extract_game_assets.py @@ -1,5 +1,8 @@ import os import sys +import libarc +from pathlib import Path +from oead import yaz0 """ Extracts the game assets and stores them in the game folder @@ -127,6 +130,36 @@ def writeFolder(parsedFstBin, i): Use the parsed fst.bin contents to write assets to file """ +convertDefinitions = [ + {"extension": ".arc", "function": libarc.extract_to_directory, "exceptions": ["archive/dat/speakerse.arc"]} +] + +def writeFile(name,data): + if (data[0:4]==bytes("Yaz0","ascii")): + splitName = os.path.splitext(name) + name = splitName[0]+".c"+splitName[1] + data = yaz0.decompress(data) + + extractDef = None + splitName = os.path.splitext(name) + ext = splitName[1] + for extractData in convertDefinitions: + if ext == extractData["extension"]: + extractDef = extractData + if extractData["exceptions"] != None: + for exception in extractData["exceptions"]: + if str(name)==exception: + extractDef = None + break + + if extractDef == None: + file = open(name,"wb") + file.write(data) + file.close() + else: + name = extractDef["function"](name,data,writeFile) + return name + def writeAssets(parsedFstBin, handler): # Write the folder structure and files to disc @@ -145,10 +178,11 @@ def writeAssets(parsedFstBin, handler): ) else: handler.seek(i["fileOffset"]) - with open( - (folderStack[-1]["folderName"] + i["fileName"]), "wb" - ) as currentFile: - currentFile.write(bytearray(handler.read(i["fileSize"]))) + writeFile(folderStack[-1]["folderName"] + i["fileName"],bytearray(handler.read(i["fileSize"]))) + #with open( + # (folderStack[-1]["folderName"] + i["fileName"]), "wb" + #) as currentFile: + # currentFile.write(bytearray(handler.read(i["fileSize"]))) while folderStack[-1]["lastEntryNumber"] == j + 1: folderStack.pop() @@ -226,6 +260,5 @@ def extract(path): def main(): extract(sys.argv[1]) - if __name__ == "__main__": main() diff --git a/tools/libarc/arc.py b/tools/libarc/arc.py index 22ed4d3f3c5..c7798643d44 100644 --- a/tools/libarc/arc.py +++ b/tools/libarc/arc.py @@ -5,7 +5,10 @@ Simple library for reading and paring rarc files. """ import struct +import os +import ctypes +from pathlib import Path from dataclasses import dataclass, field from typing import List, Dict @@ -69,6 +72,7 @@ class Node: directory_index: int name: str = None + parent = None rarc: "RARC" = field(default=None, repr=False) def files_and_folders(self, depth): @@ -95,8 +99,8 @@ class RARC: header_length: int file_offset: int file_data_length: int - file_data_length2: int - unknown0: int + file_data_mmem: int + file_data_amem: int unknown1: int # info block @@ -126,9 +130,9 @@ def read_string_table(rarc, data): rarc.string_table = StringTable() offset = 0 - for string in buffer.decode('ascii').split('\0'): + for string in str(buffer,'shift-jis').split('\0'): rarc.string_table.strings[offset] = string - offset += len(string) + 1 + offset += len(bytearray(string,"shift-jis")) + 1 def read_node(rarc, buffer): @@ -184,3 +188,199 @@ def read(buffer) -> RARC: read_directories(rarc, data, file_data) return rarc + +def extract_node(node,arcData,write_function,parentDir,dirNames) -> str: + os.mkdir(Path(parentDir)/node.name) + for i in range(node.directory_index,node.directory_count+node.directory_index): + dir = arcData._directories[i] + dirNames[i] = str(Path(parentDir)/Path(node.name)) + "/" + dir.name + if type(dir) == Folder and dir.name != '.' and dir.name != '..': + for j,node2 in enumerate(arcData._nodes): + if dir.data_offset == j: + dirNames = extract_node(node2,arcData,write_function,Path(parentDir)/node.name,dirNames) + break + elif type(dir) == File: + dirNames[i] = write_function(Path(parentDir)/Path(node.name)/dir.name,dir.data) + + return dirNames + +def extract_to_directory(directory,data,write_function): + print("Extracting "+str(directory)) + os.mkdir(directory) + arcData = read(data) + cwd = os.getcwd() + os.chdir(directory) + dirNames = extract_node(arcData._root,arcData,write_function,"./",[None]*len(arcData._directories)) + + files_data = "" + for i,dir in enumerate(arcData._directories): + directoryIndicator = "" + specialType = "" + indexToUse = str(dir.index).zfill(len(str(len(arcData._directories)))) + if type(dir) == Folder: + directoryIndicator = "/" + indexToUse = "Folder" + if dir.type != 0x200 and dir.type != 0x1100 and dir.type != 0x9500: + specialType = ":"+hex(dir.type) + files_data = files_data + indexToUse + ":" + str(dirNames[i]) + directoryIndicator + specialType + '\n' + + + fileDataLines = files_data.splitlines() + #fileDataLines.sort(key=lambda x : int(x.split(":")[0])) + filesFile = open("_files.txt","w") + for line in fileDataLines: + filesFile.write(line+'\n') + os.chdir(cwd) + return directory + +def computeHash(string): + hash = 0 + for char in string: + hash = hash*3 + hash = hash + ord(char) + + hash = ctypes.c_ushort(hash) + hash = hash.value + return hash + +def getNodeIdent(fullName): + if len(fullName)<4: + fullName = fullName.upper() + for i in range(4-len(fullName)): + fullName = fullName + " " + else: + fullName = fullName.upper()[:4] + return struct.unpack('>I', fullName.encode('ascii'))[0] + +def parseDirForPack(fileDataLines,path,convertFunction,nodes,dirs,currentNode,stringTable,data): + for i in range(currentNode.directory_index,currentNode.directory_count+currentNode.directory_index): + currentLine = fileDataLines[i].split(":") + dirId = currentLine[0] + if dirId == "Folder": + dirId = 0xFFFF + else: + dirId = int(dirId) + currentLineName = currentLine[1] + specialDirType = 0 + if len(currentLine)>2: + specialDirType = int(currentLine[2],16) + if currentLineName[-1] == '/': + currentLineName = currentLineName[0:-1] + dirName = currentLineName.split("/")[-1] + if dirName == '.' or dirName == '..' or (os.path.isdir(path/currentLineName) and len(os.path.splitext(dirName)[1])==0): + stringTableOffset = 0 + nodeIndex = nodes.index(currentNode) + if dirName == '..': + if currentNode.parent == None: + nodeIndex = 0xFFFFFFFF + else: + nodeIndex = nodes.index(currentNode.parent) + stringTableOffset = 2 + if dirName != '.' and dirName != '..': + stringTableOffset = len(bytearray(stringTable,"shift-jis")) + stringTable = stringTable + dirName + "\0" + dirsInCurrentDir = [] + for j,line in enumerate(fileDataLines): + split = line.split(":")[1].split("/") + if split[-1] == '': + split.pop() + if currentLineName == "/".join(split[0:-1]): + dirsInCurrentDir.append(j) + newNode = Node(getNodeIdent(dirName),stringTableOffset,computeHash(dirName),len(dirsInCurrentDir),dirsInCurrentDir[0],dirName) + newNode.parent = currentNode + nodes.append(newNode) + nodeIndex = len(nodes)-1 + stringTable,nodes,dirs,data = parseDirForPack(fileDataLines,path,convertFunction,nodes,dirs,newNode,stringTable,data) + dirs[i] = Folder(dirId,computeHash(dirName),0x200,stringTableOffset,nodeIndex,16,0,dirName) + else: + realFileName, fileData = convertFunction(currentLineName,path,None,True) + realFileName = os.path.basename(realFileName) + stringTableOffset = len(bytearray(stringTable,"shift-jis")) + stringTable = stringTable + realFileName + "\0" + fileType = 0x1100 + if fileData[:4] == bytearray("Yaz0","utf-8"): + fileType = 0x9500 + if specialDirType != 0: + fileType = specialDirType + dirs[i] = File(dirId,computeHash(realFileName),fileType,stringTableOffset,len(data),len(fileData),0,realFileName) + data = data + fileData + fileEndPadding = (0x20-(len(data)%0x20)) + if fileEndPadding == 0x20: + fileEndPadding = 0 + data = data + bytearray(fileEndPadding) + return stringTable,nodes,dirs,data + +def convert_dir_to_arc(sourceDir,convertFunction): + #print("Converting "+str(sourceDir)) + fileData = open(sourceDir/"_files.txt","r").read() + fileDataLinesFull = fileData.splitlines() + #fileDataLinesFull.sort(key=lambda x : int(x.split(":")[0])) + + fileDataLines = [] + for line in fileDataLinesFull: + #fileDataLines.append(":".join(line.split(":")[1:])) #this should map directory ids to their index directly + fileDataLines.append(line) + + rootName = fileDataLines[0].split(":")[1].split("/")[0] + nodes = [] + dirs = [None] * len(fileDataLines) + stringTable = ".\0..\0" + nodes.append(Node(getNodeIdent("ROOT"),len(stringTable),computeHash(rootName),len(os.listdir(sourceDir/rootName))+2,0,rootName)) + stringTable = stringTable+rootName+"\0" + data = bytearray(0) + + stringTable,nodes,dirs,data = parseDirForPack(fileDataLines,sourceDir,convertFunction,nodes,dirs,nodes[0],stringTable,data) + + dirOffset = 32+(len(nodes)*16) + dirOffsetPadding = (0x20-(dirOffset%0x20)) + if dirOffsetPadding == 0x20: + dirOffsetPadding = 0 + dirOffset = dirOffset + dirOffsetPadding + stringTableOffset = dirOffset+(len(dirs)*20) + stringTablePadding = (0x20-(stringTableOffset%0x20)) + stringTableOffset = stringTableOffset + stringTablePadding + stringTableLen = len(bytearray(stringTable,"shift-jis")) + fileOffset = stringTableOffset+stringTableLen + fileOffsetPadding = (0x20-(fileOffset%0x20)) + if fileOffsetPadding == 0x20: + fileOffsetPadding = 0 + fileOffset = fileOffset + fileOffsetPadding + + + fileLength = fileOffset+len(data) + + mMemLength = len(data) + aMemLength = 0 + + fileCount = len(dirs) + folderCount = 0 + for dir in dirs: + if type(dir) == Folder: + folderCount = folderCount + 1 + if aMemLength == 0 and dir.type == 0xA500: + aMemLength = mMemLength + mMemLength = 0 + #hacky way to detect rels.arc + + if folderCount == 2: + fileCount = fileCount - 2 #probably wrong + + arcHeader = RARC(1380012611,fileLength,32,fileOffset,len(data),mMemLength,aMemLength,0,len(nodes),32,len(dirs),dirOffset,stringTableLen+stringTablePadding,stringTableOffset,fileCount,256,0) + headerData = struct.pack(">IIIIIIIIIIIIIIHHI",1380012611,fileLength,32,fileOffset,len(data),mMemLength,aMemLength,0,len(nodes),32,len(dirs),dirOffset,stringTableLen+fileOffsetPadding,stringTableOffset,fileCount,256,0) + nodeData = bytearray() + for node in nodes: + nodeData = nodeData + struct.pack(">IIHHI",node.identifier,node.name_offset,node.name_hash,node.directory_count,node.directory_index) + + dirOffsetPaddingData = bytearray(dirOffsetPadding) + dirData = bytearray() + for dir in dirs: + dirData = dirData + struct.pack(">HHHHIII",dir.index,dir.name_hash,dir.type,dir.name_offset,dir.data_offset,dir.data_length,dir.unknown0) + + stringTablePaddingData = bytearray(stringTablePadding) + stringTableData = bytearray(stringTable,"shift-jis") + fileOffsetPaddingData = bytearray(fileOffsetPadding) + + fullData = bytearray() + fullData = headerData + nodeData + dirOffsetPaddingData + dirData + stringTablePaddingData + stringTableData + fileOffsetPaddingData + data + + return fullData diff --git a/tools/package_game_assets.py b/tools/package_game_assets.py index ae1053e833c..8a2d5fd9e93 100644 --- a/tools/package_game_assets.py +++ b/tools/package_game_assets.py @@ -7,25 +7,88 @@ import hashlib import struct import ctypes import oead +import libarc +def getMaxDateFromDir(path): + maxTime = 0 + for root,dirs,files in os.walk(str(path)): + for file in files: + time = os.path.getmtime(Path(root+"/"+file)) + if time > maxTime: + maxTime = time + return maxTime + +convertDefinitions = [ + {"sourceExtension" : ".arc", "destExtension" : ".arc", "convertFunction" : libarc.convert_dir_to_arc, "exceptions": ["game/files/res/Object/HomeBtn.c.arc/archive/dat/speakerse.arc"]} +] + +def convertEntry(file,path,destPath,returnData): + split = os.path.splitext(file) + mustBeCompressed = False + destFileName = file + if split[0].split(".")[-1] == "c": + destFileName = split[0][0:-2]+split[-1] + mustBeCompressed = True + sourceExtension = split[-1] + data = None + + extractDef = None + for extractData in convertDefinitions: + if sourceExtension == extractData["sourceExtension"]: + extractDef = extractData + if extractData["exceptions"] != None: + for exception in extractData["exceptions"]: + if str(path/file)==exception: + extractDef = None + break + + if extractDef != None: + destFileName = os.path.splitext(destFileName)[0]+extractDef["destExtension"] + + targetTime = 0 + if destPath != None and os.path.exists(destPath/destFileName): + targetTime = os.path.getmtime(destPath/destFileName) + sourceTime = 0 + if targetTime != 0: + if os.path.isdir(path/file): + sourceTime = getMaxDateFromDir(path/file) + else: + sourceTime = os.path.getmtime(path/file) + if returnData == False and sourceTime < targetTime: + return destFileName + + if extractDef != None: + data = extractDef["convertFunction"](path/file,convertEntry) + + if mustBeCompressed == True: + if data == None: + data = open(path/file,"rb").read() + data = oead.yaz0.compress(data) + if returnData == True: + if data == None and returnData == True: + data = open(path/file,"rb").read() + return destFileName,data + else: + print(str(path/file)+" -> "+str(destPath/destFileName)) + if data != None: + open(destPath/destFileName,"wb").write(data) + else: + shutil.copy(path/file,destPath/destFileName) + return destFileName def copy(path, destPath): - for root, dirs, files in os.walk(str(path)): - for file in files: - outputDir = destPath / Path(str(root)) - # print(str(outputDir.absolute())+file) - if not outputDir.absolute().exists(): - os.makedirs(outputDir.absolute()) - outputFile = Path(str(outputDir.absolute()) + "/" + str(file)) - inFile = Path(str(Path(root).absolute()) + "/" + str(file)) - if not outputFile.exists(): - print(str(inFile) + " -> " + str(outputFile)) - shutil.copyfile(inFile, outputFile) - else: - if os.path.getmtime(inFile) > os.path.getmtime(outputFile): - print(str(inFile) + " -> " + str(outputFile)) - shutil.copyfile(inFile, outputFile) + for file in os.listdir(path): + split = os.path.splitext(file) + if len(split[1])==0 and os.path.isdir(path/file): + #is a standard directory + if not Path(destPath/file).exists(): + os.mkdir(destPath/file) + copy(path/file,destPath/file) + else: + #either a file or directory that needs to be converted + convertEntry(file,path,destPath,False) +#copy(Path("srcArc"),Path("arcDest")) aMemRels = """d_a_alldie.rel d_a_andsw2.rel @@ -163,89 +226,10 @@ d_a_vrbox.rel d_a_vrbox2.rel f_pc_profile_lst.rel""" -# Because libarc is only geared toward reading from arcs I'm writing my own arc writer in this file - -class HEADER: - RARC: int - length: int - headerLength: int - fileDataOffset: int - fileDataLen: int - fileDataLen2: int - unk1: int - unk2: int - - -class INFO: - numNodes: int - firstNodeOffset: int - totalDirNum: int - firstDirOffset: int - stringTableLen: int - stringTableOffset: int - numDirsThatAreFiles: int - unk1: int - unk2: int - - -class NODE: - NAME: int - stringTableOffset: int - hash: int - numDirs: int - firstDirIndex: int - - -class DIRECTORY: - dirIndex: int - stringHash: int - type: int - stringOffset: int - fileOffset: int - fileLength: int - unk1: int - - -def computeHash(string): - hash = 0 - for char in string: - hash = hash * 3 - hash = hash + ord(char) - - hash = ctypes.c_ushort(hash) - hash = hash.value - return hash - - -def addFile(index, sizeIndex, dirs, name, stringTable, paths, data): - file = DIRECTORY() - file.dirIndex = index - file.stringHash = computeHash(name) - file.type = 0xA500 - file.stringOffset = stringTable.find(name) - path = None - for relPath in paths: - if str(relPath).find(name) != -1: - path = relPath - file.unk1 = 0 - fileData = open(path, "rb") - compressedData = oead.yaz0.compress(fileData.read()) - padding = 0x20 - (len(compressedData) % 0x20) - file.fileLength = len(compressedData) - file.fileOffset = sizeIndex - sizeIndex = sizeIndex + file.fileLength + padding - data += compressedData - data += bytearray(padding) - fileData.close() - dirs.append(file) - - return dirs, data, sizeIndex - - -def copyRelFiles(buildPath, aMemList, mMemList): +def copyRelFiles(gamePath, buildPath, aMemList, mMemList): relArcPaths = [] - for root, dirs, files in os.walk(str(buildPath / "rel")): + for root, dirs, files in os.walk(str(buildPath / "dolzel2/rel")): for file in files: if file.find(".rel") != -1: relArcFound = False @@ -260,240 +244,55 @@ def copyRelFiles(buildPath, aMemList, mMemList): print( str(fullPath) + " -> " - + str(buildPath / "game/files/rel/Final/Release" / file) + + str(buildPath / "dolzel2/game/files/rel/Final/Release" / file) ) relSource = open(fullPath, "rb") data = relSource.read() relSource.close() data = oead.yaz0.compress(data) relNew = open( - buildPath / "game/files/rel/Final/Release" / file, "wb" + buildPath / "dolzel2/game/files/rel/Final/Release" / file, "wb" ) relNew.write(data) relNew.truncate() relNew.close() else: relArcPaths.append(fullPath) + + if os.path.exists(buildPath/"RELS.arc") == False: + os.mkdir(buildPath/"RELS.arc") + os.mkdir(buildPath/"RELS.arc/rels") + os.mkdir(buildPath/"RELS.arc/rels/mmem") + os.mkdir(buildPath/"RELS.arc/rels/amem") - arcHeader = HEADER() - arcHeader.RARC = 0x52415243 - arcHeader.headerLength = 0x20 - arcHeader.unk1 = 0 - arcHeader.unk2 = 0 - infoBlock = INFO() - infoBlock.numNodes = 3 - infoBlock.numDirsThatAreFiles = 142 - rootNode = NODE() - rootNode.NAME = 0x524F4F54 - rootNode.numDirs = 4 - rootNode.firstDirIndex = 0 - rootNode.hash = computeHash("rels") - aMemNode = NODE() - aMemNode.NAME = 0x414D454D - aMemNode.hash = computeHash("amem") - aMemNode.numDirs = 79 - aMemNode.firstDirIndex = 4 - mMemNode = NODE() - mMemNode.hash = computeHash("mmem") - mMemNode.NAME = 0x4D4D454D - mMemNode.numDirs = 59 - mMemNode.firstDirIndex = 83 + filesTxtData = "Folder:rels/amem/\nFolder:rels/mmem/\nFolder:rels/./\nFolder:rels/../\n" + for i,rel in enumerate(aMemRels.splitlines()): + filesTxtData = filesTxtData + str(i+4) + ":rels/amem/" + rel + ":0xa500\n" + filesTxtData = filesTxtData + "Folder:rels/amem/./\nFolder:rels/amem/../\n" + for i,rel in enumerate(mMemRels.splitlines()): + filesTxtData = filesTxtData + str(i+83) + ":rels/mmem/" + rel + ":0xa500\n" + filesTxtData = filesTxtData + "Folder:rels/mmem/./\nFolder:rels/mmem/../\n" + open(buildPath/"RELS.arc/_files.txt","w").write(filesTxtData) + for rel in relArcPaths: + for rel2 in aMemRels.splitlines(): + if str(rel).find(rel2) != -1: + sourceRel = open(rel,"rb").read() + open(buildPath/"RELS.arc/rels/amem/"/rel2,"wb").write(oead.yaz0.compress(sourceRel)) + break + for rel2 in mMemRels.splitlines(): + if str(rel).find(rel2) != -1: + sourceRel = open(rel,"rb").read() + open(buildPath/"RELS.arc/rels/mmem/"/rel2,"wb").write(oead.yaz0.compress(sourceRel)) + break - stringTable = ".\0..\0rels\0amem\0" - for rel in aMemList: - stringTable = stringTable + rel + "\0" - stringTable = stringTable + "mmem\0" - for rel in mMemList: - stringTable = stringTable + rel + "\0" - stringTable = stringTable + "\0\0\0\0\0\0" - - rootNode.stringTableOffset = stringTable.find("rels") - aMemNode.stringTableOffset = stringTable.find("amem") - mMemNode.stringTableOffset = stringTable.find("mmem") - - aMemDir = DIRECTORY() - aMemDir.dirIndex = 0xFFFF - aMemDir.type = 0x200 - aMemDir.stringOffset = stringTable.find("amem") - aMemDir.stringHash = computeHash("amem") - aMemDir.fileOffset = 1 - aMemDir.fileLength = 0x10 - aMemDir.unk1 = 0 - - mMemDir = DIRECTORY() - mMemDir.dirIndex = 0xFFFF - mMemDir.type = 0x200 - mMemDir.stringOffset = stringTable.find("mmem") - mMemDir.stringHash = computeHash("mmem") - mMemDir.fileOffset = 2 - mMemDir.fileLength = 0x10 - mMemDir.unk1 = 0 - - unkDir = DIRECTORY() - unkDir.dirIndex = 0xFFFF - unkDir.stringHash = 0x2E - unkDir.type = 0x200 - unkDir.stringOffset = 0 - unkDir.fileOffset = 0 - unkDir.fileLength = 0x10 - unkDir.unk1 = 0 - - unkDir2 = DIRECTORY() - unkDir2.dirIndex = 0xFFFF - unkDir2.stringHash = 0xB8 - unkDir2.type = 0x200 - unkDir2.stringOffset = 2 - unkDir2.fileOffset = 0xFFFFFFFF - unkDir2.fileLength = 0x10 - unkDir2.unk1 = 0 - - dirs = [aMemDir, mMemDir, unkDir, unkDir2] - - data = bytearray() - - dirIndex = 4 - sizeIndex = 0 - for rel in aMemList: - retdirs, retdata, retSize = addFile( - dirIndex, sizeIndex, dirs, rel, stringTable, relArcPaths, data - ) - dirIndex = dirIndex + 1 - sizeIndex = retSize - dirs = retdirs - data = retdata - dirs.append(unkDir) - dirs.append(unkDir2) - dirIndex = dirIndex + 2 - for rel in mMemList: - retdirs, retdata, retSize = addFile( - dirIndex, sizeIndex, dirs, rel, stringTable, relArcPaths, data - ) - dirIndex = dirIndex + 1 - sizeIndex = retSize - # print(hex(dirIndex)) - dirs = retdirs - data = retdata - unkDir3 = DIRECTORY() - unkDir3.dirIndex = 0xFFFF - unkDir3.stringHash = 0x2E - unkDir3.type = 0x200 - unkDir3.stringOffset = 0 - unkDir3.fileOffset = 2 - unkDir3.fileLength = 0x10 - unkDir3.unk1 = 0 - - unkDir4 = DIRECTORY() - unkDir4.dirIndex = 0xFFFF - unkDir4.stringHash = 0xB8 - unkDir4.type = 0x200 - unkDir4.stringOffset = 2 - unkDir4.fileOffset = 0 - unkDir4.fileLength = 0x10 - unkDir4.unk1 = 0 - dirs.append(unkDir3) - dirs.append(unkDir4) - dirIndex = dirIndex + 2 - - arcHeader.length = ( - len(stringTable) + 0x20 + 0x20 + 0x30 + (len(dirs) * 0x14) + len(data) - ) - arcHeader.fileDataOffset = 0x14E0 - arcHeader.fileDataLen = len(data) - arcHeader.fileDataLen2 = arcHeader.fileDataLen - - infoBlock.firstNodeOffset = 0x20 - infoBlock.firstDirOffset = 0x60 - infoBlock.stringTableLen = len(stringTable) - infoBlock.stringTableOffset = 0xB80 - infoBlock.unk1 = 0x100 - infoBlock.unk2 = 0 - infoBlock.totalDirNum = 0x8E - - outputArcFile = open(buildPath / "game/files/RELS.arc", "wb") - outputArcFile.seek(0) - - outputArcFile.write( - struct.pack( - ">IIIIIIII", - arcHeader.RARC, - arcHeader.length, - arcHeader.headerLength, - arcHeader.fileDataOffset, - arcHeader.fileDataLen, - arcHeader.unk1, - arcHeader.fileDataLen2, - arcHeader.unk2, - ) - ) - outputArcFile.write( - struct.pack( - ">IIIIIIHHI", - infoBlock.numNodes, - infoBlock.firstNodeOffset, - infoBlock.totalDirNum, - infoBlock.firstDirOffset, - infoBlock.stringTableLen, - infoBlock.stringTableOffset, - infoBlock.numDirsThatAreFiles, - infoBlock.unk1, - infoBlock.unk2, - ) - ) - outputArcFile.write( - struct.pack( - ">IIHHI", - rootNode.NAME, - rootNode.stringTableOffset, - rootNode.hash, - rootNode.numDirs, - rootNode.firstDirIndex, - ) - ) - outputArcFile.write( - struct.pack( - ">IIHHI", - aMemNode.NAME, - aMemNode.stringTableOffset, - aMemNode.hash, - aMemNode.numDirs, - aMemNode.firstDirIndex, - ) - ) - outputArcFile.write( - struct.pack( - ">IIHHI", - mMemNode.NAME, - mMemNode.stringTableOffset, - mMemNode.hash, - mMemNode.numDirs, - mMemNode.firstDirIndex, - ) - ) - outputArcFile.write(bytearray(16)) - for dir in dirs: - outputArcFile.write( - struct.pack( - ">HHHHIII", - dir.dirIndex, - dir.stringHash, - dir.type, - dir.stringOffset, - dir.fileOffset, - dir.fileLength, - dir.unk1, - ) - ) - outputArcFile.write(bytearray(8)) - strBytearray = bytearray() - strBytearray.extend(map(ord, stringTable)) - outputArcFile.write(strBytearray) - outputArcFile.write(data) - - outputArcFile.truncate() - outputArcFile.close() + print("Creating RELS.arc") + open(buildPath/"dolzel2/game/files/RELS.arc","wb").write(libarc.convert_dir_to_arc(buildPath/"RELS.arc",convertEntry)) + -def main(gamePath, buildPath): + + +def main(gamePath, buildPath,copyCode): if not gamePath.exists(): gamePath.mkdir(parents=True, exist_ok=True) @@ -510,17 +309,23 @@ def main(gamePath, buildPath): os.chdir(previousDir) print("Copying game files...") - copy(gamePath, buildPath.absolute()) + if os.path.exists(buildPath/"dolzel2") == False: + os.mkdir(buildPath/"dolzel2") + if os.path.exists(buildPath/"dolzel2"/"game") == False: + os.mkdir(buildPath/"dolzel2/game") + copy(gamePath, Path(buildPath/"dolzel2/game").absolute()) - print( - str(buildPath / "main_shift.dol") - + " -> " - + str(buildPath / "game/sys/main.dol") - ) - shutil.copyfile(buildPath / "main_shift.dol", buildPath / "game/sys/main.dol") + if copyCode != "noCopyCode": + print( + str(buildPath / "dolzel2/main_shift.dol") + + " -> " + + str(buildPath / "dolzel2/game/sys/main.dol") + ) + shutil.copyfile(buildPath / "dolzel2/main_shift.dol", buildPath / "dolzel2/game/sys/main.dol") - copyRelFiles(buildPath, aMemRels.splitlines(), mMemRels.splitlines()) + copyRelFiles(gamePath,buildPath, aMemRels.splitlines(), mMemRels.splitlines()) if __name__ == "__main__": - main(Path(sys.argv[1]), Path(sys.argv[2])) + pass + main(Path(sys.argv[1]), Path(sys.argv[2]), sys.argv[3])