mirror of https://github.com/zeldaret/tp.git
Shiftable
This commit is contained in:
parent
c72012c5d8
commit
e1246d9b0a
11
Makefile
11
Makefile
|
@ -125,6 +125,7 @@ clean_rels:
|
|||
tools: $(ELF2DOL)
|
||||
|
||||
assets:
|
||||
@mkdir -p game
|
||||
@cd game; $(PYTHON) ../tools/extract_game_assets.py ../$(IMAGENAME)
|
||||
|
||||
docs:
|
||||
|
@ -149,6 +150,14 @@ $(DOL_SHIFT): $(ELF_SHIFT) | tools
|
|||
|
||||
shift: dirs $(DOL_SHIFT)
|
||||
|
||||
game: | shift rels
|
||||
@mkdir -p game
|
||||
@$(PYTHON) tools/package_game_assets.py game $(BUILD_DIR)
|
||||
|
||||
rungame: game
|
||||
@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
|
||||
|
||||
#
|
||||
$(BUILD_DIR)/%.o: %.cpp
|
||||
@mkdir -p $(@D)
|
||||
|
@ -170,4 +179,4 @@ include tools/elf2dol/Makefile
|
|||
### Debug Print ###
|
||||
print-% : ; $(info $* is a $(flavor $*) variable set to [$($*)]) @true
|
||||
|
||||
.PHONY: default all dirs clean tools docs shift print-%
|
||||
.PHONY: default all dirs clean tools docs shift game rungame print-%
|
||||
|
|
|
@ -277,7 +277,7 @@ extern "C" static void cMtx_XrotM__FPA4_fs();
|
|||
extern "C" static void JMAFastSqrt__Ff();
|
||||
extern "C" static void dComIfGp_particle_set__FUlUsPC4cXyzPC5csXyzPC4cXyz();
|
||||
extern "C" void cancelOriginalDemo__9daHorse_cFv();
|
||||
extern "C" void __ct__10JAISoundIDFUl();
|
||||
extern "C" void __ct__10JAISoundIDFUl(u32* this_replacement,u32 param_0);
|
||||
extern "C" static void dComIfGp_getVibration__Fv();
|
||||
extern "C" void __ct__4cXyzFfff();
|
||||
extern "C" void onDemoJumpDistance__9daHorse_cFff();
|
||||
|
@ -4970,8 +4970,8 @@ asm void daHorse_c::cancelOriginalDemo() {
|
|||
#pragma pop
|
||||
|
||||
/* 807E27D0-807E27D8 -00001 0008+00 0/0 0/0 0/0 .text __ct__10JAISoundIDFUl */
|
||||
JAISoundID::JAISoundID(u32 param_0) {
|
||||
*(u32*)this = (u32)(param_0);
|
||||
extern "C" void __ct__10JAISoundIDFUl(u32* this_replacement,u32 param_0) {
|
||||
*(u32*)this_replacement = (u32)(param_0);
|
||||
}
|
||||
|
||||
/* 807E27D8-807E27E8 010438 0010+00 1/1 0/0 0/0 .text dComIfGp_getVibration__Fv */
|
||||
|
|
|
@ -372,7 +372,7 @@ bool DynamicModuleControl::do_load() {
|
|||
}
|
||||
}
|
||||
if(mModule==NULL&&sFileCache!=NULL) {
|
||||
mModule = (OSModuleInfo*)sFileCache->getResource(0x72656C73,buffer);
|
||||
mModule = (OSModuleInfo*)sFileCache->getResource(0x72656C73/*rels*/,buffer);
|
||||
if(mModule!=NULL) {
|
||||
mSize = 0;
|
||||
mResourceType = 11;
|
||||
|
|
|
@ -7,6 +7,13 @@ Usage: `python tools/extract_game_assets.py`
|
|||
"""
|
||||
|
||||
fstInfoPosition = 0x424
|
||||
bootPosition = 0x0
|
||||
bootSize = 0x440
|
||||
bi2Position = 0x440
|
||||
bi2Size = 0x2000
|
||||
apploaderPosition = 0x2440
|
||||
dolInfoPosition = 0x420
|
||||
|
||||
numFileEntries = 0
|
||||
|
||||
"""
|
||||
|
@ -94,7 +101,7 @@ Write the current folder to disk and return it's name/last entry number
|
|||
|
||||
|
||||
def writeFolder(parsedFstBin, i):
|
||||
folderPath = i["folderName"] + "/"
|
||||
folderPath = i["folderName"] + "/"
|
||||
lastEntryNumber = i["lastEntryNumber"]
|
||||
|
||||
if i["parentFolderEntryNumber"] == 0:
|
||||
|
@ -125,6 +132,9 @@ def writeAssets(parsedFstBin, handler):
|
|||
# Write the folder structure and files to disc
|
||||
j = 0
|
||||
folderStack = []
|
||||
if not os.path.exists("./files/"):
|
||||
os.makedirs("./files/")
|
||||
os.chdir('./files/')
|
||||
folderStack.append({"folderName": "./", "lastEntryNumber": numFileEntries})
|
||||
for i in parsedFstBin:
|
||||
j += 1
|
||||
|
@ -143,6 +153,38 @@ def writeAssets(parsedFstBin, handler):
|
|||
while folderStack[-1]["lastEntryNumber"] == j + 1:
|
||||
folderStack.pop()
|
||||
|
||||
def writeSys(boot,bi2,apploader,dol,fst):
|
||||
if not os.path.exists("./sys/"):
|
||||
os.makedirs("./sys/")
|
||||
open("./sys/boot.bin","wb").write(boot)
|
||||
open("./sys/bi2.bin","wb").write(bi2)
|
||||
open("./sys/apploader.img","wb").write(apploader)
|
||||
open("./sys/main.dol","wb").write(dol)
|
||||
open("./sys/fst.bin","wb").write(fst)
|
||||
|
||||
def getDolInfo(disc):
|
||||
disc.seek(dolInfoPosition)
|
||||
dolOffset = int.from_bytes(bytearray(disc.read(4)), byteorder="big")
|
||||
dolSize = 0
|
||||
for i in range(7):
|
||||
disc.seek(dolOffset+(i*4))
|
||||
segmentOffset = int.from_bytes(bytearray(disc.read(4)), byteorder="big")
|
||||
disc.seek(dolOffset+0x90+(i*4))
|
||||
segmentSize = int.from_bytes(bytearray(disc.read(4)), byteorder="big")
|
||||
if (segmentOffset+segmentSize)>dolSize:
|
||||
dolSize = segmentOffset + segmentSize
|
||||
|
||||
for i in range(11):
|
||||
disc.seek(dolOffset+0x1c+(i*4))
|
||||
dataOffset = int.from_bytes(bytearray(disc.read(4)), byteorder="big")
|
||||
disc.seek(dolOffset+0xac+(i*4))
|
||||
dataSize = int.from_bytes(bytearray(disc.read(4)), byteorder="big")
|
||||
if (dataOffset+dataSize)>dolSize:
|
||||
dolSize = dataOffset + dataSize
|
||||
|
||||
return dolOffset, dolSize
|
||||
|
||||
|
||||
|
||||
def extract(path):
|
||||
with open(path, "rb") as f:
|
||||
|
@ -150,10 +192,30 @@ def extract(path):
|
|||
f.seek(fstInfoPosition)
|
||||
fstOffset, fstSize = getFstInfo(f, fstInfoPosition)
|
||||
|
||||
f.seek(bootPosition)
|
||||
bootBytes = bytearray(f.read(bootSize))
|
||||
|
||||
f.seek(bi2Position)
|
||||
bi2Bytes = bytearray(f.read(bi2Size))
|
||||
|
||||
f.seek(apploaderPosition+0x14)
|
||||
apploaderSize = int.from_bytes(bytearray(f.read(4)), byteorder="big")
|
||||
f.seek(apploaderPosition+0x18)
|
||||
trailerSize = int.from_bytes(bytearray(f.read(4)), byteorder="big")
|
||||
apploaderMainSize = 0x20 + apploaderSize + trailerSize
|
||||
f.seek(apploaderPosition)
|
||||
apploaderBytes = bytearray(f.read(apploaderMainSize))
|
||||
dolOffset, dolSize = getDolInfo(f)
|
||||
f.seek(dolOffset)
|
||||
dolBytes = bytearray(f.read(dolSize))
|
||||
|
||||
|
||||
# Seek to fst.bin and retrieve it
|
||||
f.seek(fstOffset)
|
||||
fstBinBytes = bytearray(f.read(fstSize))
|
||||
|
||||
writeSys(bootBytes,bi2Bytes,apploaderBytes,dolBytes,fstBinBytes)
|
||||
|
||||
# Parse fst.bin
|
||||
parsedFstBin = parseFstBin(fstBinBytes)
|
||||
|
||||
|
@ -162,7 +224,7 @@ def extract(path):
|
|||
|
||||
|
||||
def main():
|
||||
extract(sys.argv[1], "rb")
|
||||
extract(sys.argv[1])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -0,0 +1,433 @@
|
|||
import os
|
||||
import sys
|
||||
import shutil
|
||||
import extract_game_assets
|
||||
from pathlib import Path
|
||||
import hashlib
|
||||
import struct
|
||||
|
||||
|
||||
def sha1_from_data(data):
|
||||
sha1 = hashlib.sha1()
|
||||
sha1.update(data)
|
||||
|
||||
return sha1.hexdigest().upper()
|
||||
|
||||
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:
|
||||
inf = open(inFile,"rb")
|
||||
inSum = sha1_from_data(bytearray(inf.read()))
|
||||
outf = open(outputFile,"rb")
|
||||
outSum = sha1_from_data(bytearray(outf.read()))
|
||||
if inSum!=outSum:
|
||||
print(str(inFile)+" -> "+str(outputFile))
|
||||
shutil.copyfile(inFile,outputFile)
|
||||
|
||||
|
||||
aMemRels = """d_a_alldie.rel
|
||||
d_a_andsw2.rel
|
||||
d_a_bd.rel
|
||||
d_a_canoe.rel
|
||||
d_a_cstaf.rel
|
||||
d_a_demo_item.rel
|
||||
d_a_door_bossl1.rel
|
||||
d_a_econt.rel
|
||||
d_a_e_dn.rel
|
||||
d_a_e_fm.rel
|
||||
d_a_e_ga.rel
|
||||
d_a_e_hb.rel
|
||||
d_a_e_nest.rel
|
||||
d_a_e_rd.rel
|
||||
d_a_fr.rel
|
||||
d_a_grass.rel
|
||||
d_a_kytag05.rel
|
||||
d_a_kytag10.rel
|
||||
d_a_kytag11.rel
|
||||
d_a_kytag14.rel
|
||||
d_a_mg_fish.rel
|
||||
d_a_npc_besu.rel
|
||||
d_a_npc_fairy_seirei.rel
|
||||
d_a_npc_fish.rel
|
||||
d_a_npc_henna.rel
|
||||
d_a_npc_kakashi.rel
|
||||
d_a_npc_kkri.rel
|
||||
d_a_npc_kolin.rel
|
||||
d_a_npc_maro.rel
|
||||
d_a_npc_taro.rel
|
||||
d_a_npc_tkj.rel
|
||||
d_a_obj_bhashi.rel
|
||||
d_a_obj_bkdoor.rel
|
||||
d_a_obj_bosswarp.rel
|
||||
d_a_obj_cboard.rel
|
||||
d_a_obj_digplace.rel
|
||||
d_a_obj_eff.rel
|
||||
d_a_obj_fmobj.rel
|
||||
d_a_obj_gptaru.rel
|
||||
d_a_obj_hhashi.rel
|
||||
d_a_obj_kanban2.rel
|
||||
d_a_obj_kbacket.rel
|
||||
d_a_obj_kgate.rel
|
||||
d_a_obj_klift00.rel
|
||||
d_a_obj_ktonfire.rel
|
||||
d_a_obj_ladder.rel
|
||||
d_a_obj_lv2candle.rel
|
||||
d_a_obj_magne_arm.rel
|
||||
d_a_obj_metalbox.rel
|
||||
d_a_obj_mgate.rel
|
||||
d_a_obj_nameplate.rel
|
||||
d_a_obj_ornament_cloth.rel
|
||||
d_a_obj_rope_bridge.rel
|
||||
d_a_obj_stick.rel
|
||||
d_a_obj_stonemark.rel
|
||||
d_a_obj_swallshutter.rel
|
||||
d_a_obj_swpropeller.rel
|
||||
d_a_obj_swpush5.rel
|
||||
d_a_obj_yobikusa.rel
|
||||
d_a_scene_exit2.rel
|
||||
d_a_shop_item.rel
|
||||
d_a_sq.rel
|
||||
d_a_swc00.rel
|
||||
d_a_tag_ajnot.rel
|
||||
d_a_tag_attack_item.rel
|
||||
d_a_tag_cstasw.rel
|
||||
d_a_tag_gstart.rel
|
||||
d_a_tag_hinit.rel
|
||||
d_a_tag_hjump.rel
|
||||
d_a_tag_hstop.rel
|
||||
d_a_tag_lv2prchk.rel
|
||||
d_a_tag_magne.rel
|
||||
d_a_tag_mhint.rel
|
||||
d_a_tag_mstop.rel
|
||||
d_a_tag_spring.rel
|
||||
d_a_tag_statue_evt.rel
|
||||
d_a_ykgr.rel"""
|
||||
|
||||
mMemRels = """d_a_andsw.rel
|
||||
d_a_arrow.rel
|
||||
d_a_bg.rel
|
||||
d_a_bg_obj.rel
|
||||
d_a_boomerang.rel
|
||||
d_a_crod.rel
|
||||
d_a_demo00.rel
|
||||
d_a_disappear.rel
|
||||
d_a_dmidna.rel
|
||||
d_a_door_dbdoor00.rel
|
||||
d_a_door_knob00.rel
|
||||
d_a_door_shutter.rel
|
||||
d_a_door_spiral.rel
|
||||
d_a_dshutter.rel
|
||||
d_a_ep.rel
|
||||
d_a_hitobj.rel
|
||||
d_a_kytag00.rel
|
||||
d_a_kytag04.rel
|
||||
d_a_kytag17.rel
|
||||
d_a_mg_rod.rel
|
||||
d_a_midna.rel
|
||||
d_a_nbomb.rel
|
||||
d_a_obj_brakeeff.rel
|
||||
d_a_obj_burnbox.rel
|
||||
d_a_obj_carry.rel
|
||||
d_a_obj_ito.rel
|
||||
d_a_obj_life_container.rel
|
||||
d_a_obj_movebox.rel
|
||||
d_a_obj_swpush.rel
|
||||
d_a_obj_timer.rel
|
||||
d_a_obj_yousei.rel
|
||||
d_a_path_line.rel
|
||||
d_a_scene_exit.rel
|
||||
d_a_set_bgobj.rel
|
||||
d_a_spinner.rel
|
||||
d_a_suspend.rel
|
||||
d_a_swhit0.rel
|
||||
d_a_tag_allmato.rel
|
||||
d_a_tag_attention.rel
|
||||
d_a_tag_camera.rel
|
||||
d_a_tag_chkpoint.rel
|
||||
d_a_tag_event.rel
|
||||
d_a_tag_evt.rel
|
||||
d_a_tag_evtarea.rel
|
||||
d_a_tag_evtmsg.rel
|
||||
d_a_tag_howl.rel
|
||||
d_a_tag_kmsg.rel
|
||||
d_a_tag_lantern.rel
|
||||
d_a_tag_mist.rel
|
||||
d_a_tag_msg.rel
|
||||
d_a_tag_push.rel
|
||||
d_a_tag_telop.rel
|
||||
d_a_tbox.rel
|
||||
d_a_tbox2.rel
|
||||
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)
|
||||
|
||||
if hash>65535:
|
||||
hash=hash%65535
|
||||
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.fileLength = os.path.getsize(path)
|
||||
file.fileOffset = sizeIndex
|
||||
sizeIndex = sizeIndex + file.fileLength + 1
|
||||
file.unk1 = 0
|
||||
fileData = open(path,"rb")
|
||||
data += fileData.read(file.fileLength)
|
||||
fileData.close()
|
||||
dirs.append(file)
|
||||
|
||||
return dirs,data,sizeIndex
|
||||
|
||||
|
||||
def copyRelFiles(buildPath,aMemList,mMemList):
|
||||
relArcPaths = []
|
||||
for root,dirs,files in os.walk(str(buildPath/"rel")):
|
||||
for file in files:
|
||||
if file.find(".rel")!=-1:
|
||||
relArcFound = False
|
||||
for rel in aMemList:
|
||||
if rel==file:
|
||||
relArcFound = True
|
||||
for rel in mMemList:
|
||||
if rel==file:
|
||||
relArcFound = True
|
||||
fullPath = Path(root+"/"+file)
|
||||
print(str(fullPath)+" -> "+str(buildPath/"game/files/rel/Final/Release"/file))
|
||||
shutil.copy(fullPath,buildPath/"game/files/rel/Final/Release/") #We're copying uncompressed rels here, we should compress in the future!
|
||||
if relArcFound==True:
|
||||
relArcPaths.append(fullPath)
|
||||
#print(relArcPaths)
|
||||
|
||||
#After writing this all I found out we don't actually need RELS.arc to load rels lol, keeping it here for the future in case we want to match RELS.arc
|
||||
|
||||
arcHeader = HEADER()
|
||||
arcHeader.RARC = 0x52415243
|
||||
arcHeader.headerLength = 0x20
|
||||
arcHeader.unk1 = 0
|
||||
arcHeader.unk2 = 0
|
||||
infoBlock = INFO()
|
||||
infoBlock.numNodes = 5
|
||||
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
|
||||
|
||||
stringTable = "\x2E\0\x2E\x2E\0rels\0amem\0"
|
||||
for rel in aMemList:
|
||||
stringTable = stringTable+rel+'\0'
|
||||
stringTable = stringTable+"mmem\0"
|
||||
for rel in mMemList:
|
||||
stringTable = stringTable+rel+'\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
|
||||
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
|
||||
|
||||
arcHeader.length = sizeIndex+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 = len(dirs)
|
||||
|
||||
|
||||
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.fileDataLen2,arcHeader.unk1,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))
|
||||
unkData = [0x8A ,0xCF ,0x7F ,0xA5 ,0x00 ,0x09 ,0x36 ,0x00 ,0x0D ,0x08 ,0xA0 ,0x00 ,0x00 ,0x0C ,0xD8 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x8B ,0x9B ,0xF7 ,0xA5 ,0x00 ,0x09 ,0x45 ,0x00 ,0x0D ,0x15 ,0x80 ,0x00 ,0x00 ,0x21 ,0xED ,0x00 ,0x00 ,0x00 ,0x00 ,0xFF ,0xFF ,0x00 ,0x2E ,0x02 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x02 ,0x00 ,0x00 ,0x00 ,0x10 ,0x00 ,0x00 ,0x00 ,0x00 ,0xFF ,0xFF ,0x00 ,0xB8 ,0x02 ,0x00 ,0x00 ,0x02 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x10 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, 0x00]
|
||||
outputArcFile.write(bytearray(unkData))
|
||||
strBytearray = bytearray()
|
||||
strBytearray.extend(map(ord,stringTable))
|
||||
outputArcFile.write(strBytearray)
|
||||
outputArcFile.write(bytearray(6))
|
||||
outputArcFile.write(data)
|
||||
|
||||
outputArcFile.truncate()
|
||||
outputArcFile.close()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def main(gamePath,buildPath):
|
||||
if not gamePath.exists():
|
||||
gamePath.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
iso = Path("gz2e01.iso")
|
||||
if not iso.exists() or not iso.is_file():
|
||||
print("gz2e01.iso doesn't exist in project directory!")
|
||||
sys.exit(1)
|
||||
|
||||
if not (gamePath/"files").exists() or not (gamePath/"sys").exists():
|
||||
print("ISO is not extracted; extracting...")
|
||||
previousDir = os.getcwd()
|
||||
os.chdir(str(gamePath.absolute()))
|
||||
extract_game_assets.extract("../" + str(iso))
|
||||
os.chdir(previousDir)
|
||||
|
||||
print("Copying game files...")
|
||||
copy(gamePath,buildPath.absolute())
|
||||
|
||||
print(str(buildPath/"main_shift.dol")+" -> "+str(buildPath/"game/sys/main.dol"))
|
||||
shutil.copyfile(buildPath/"main_shift.dol",buildPath/"game/sys/main.dol")
|
||||
|
||||
copyRelFiles(buildPath,aMemRels.splitlines(),mMemRels.splitlines())
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(Path(sys.argv[1]),Path(sys.argv[2]))
|
|
@ -351,7 +351,7 @@ def check(debug, rels, game_path, build_path):
|
|||
CONSOLE.print(text)
|
||||
|
||||
try:
|
||||
check_sha1(game_path, build_path, rels)
|
||||
check_sha1(game_path/"files", build_path, rels)
|
||||
text = Text(" OK")
|
||||
text.stylize("bold green")
|
||||
CONSOLE.print(text)
|
||||
|
|
Loading…
Reference in New Issue