mirror of https://github.com/zeldaret/tp.git
Arc Extraction and Re-Packing
This commit is contained in:
parent
02195070b6
commit
25d3c16ca7
10
Makefile
10
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)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
|
|
|
|||
Loading…
Reference in New Issue