Ajout de la fonction permettant de patcher le jeu
Configuration de la barre de progression
Les fichiers à sélectionner doivent à présent être du bon format
This commit is contained in:
raphael60650 2021-01-28 22:08:57 +01:00
parent bb6e60b9b4
commit 90bc6e7ae6
2 changed files with 224 additions and 19 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

243
main.pyw
View file

@ -28,8 +28,10 @@ class main():
self.label_GameInformation.grid(row=1, column=1)
self.button_ExtractROM = Button(self.frame_ActionGameFile, text="Extraire le jeu", relief=RIDGE, command=self.extract_game)
self.button_InstallLECODE = Button(self.frame_ActionGameFile, text="Installer LE-CODE", relief=RIDGE, command=self.install_lecode)
self.button_EditROM = Button(self.frame_ActionGameFile, text="Modifier la ROM", relief=RIDGE, command=self.edit_game)
self.button_EditROM = Button(self.frame_ActionGameFile, text="Modifier la configuration", relief=RIDGE, command=self.edit_game)
self.button_PatchROM = Button(self.frame_ActionGameFile, text="Patcher le jeu", relief=RIDGE, command=self.patch_game)
self.progressbar_Action = ttk.Progressbar(self.frame_ActionGameFile)
self.label_Action = Label(self.frame_ActionGameFile)
self.frame_CupManager = LabelFrame(self.root, text="Coupe")
@ -75,7 +77,7 @@ class main():
def ask_game_file(self):
path = filedialog.askopenfilename()
path = filedialog.askopenfilename(filetypes = (("Jeu Wii", r"*.iso *.wbfs main.dol"),))
if path:
self.entry_SelectGameFile.delete(0, END)
self.entry_SelectGameFile.insert(END, path)
@ -104,22 +106,25 @@ class main():
def refresh_action_frame(self):
self.label_GameInformation.config(text = f"chemin du jeu : {self.path}\ntype : {self.file_type}")
self.frame_ActionGameFile.grid(row=2, column=1)
self.frame_ActionGameFile.grid(row=2, column=1, sticky = "NEWS")
if self.file_type in ["wbfs", "iso"]:
self.button_ExtractROM.grid(row=2, column=1)
self.button_ExtractROM.grid(row=2, column=1, sticky = "NEWS")
self.button_InstallLECODE.grid_forget()
self.button_EditROM.grid_forget()
self.button_PatchROM.grid_forget()
else:
self.button_ExtractROM.grid_forget()
if os.path.exists(f"{self.path}/files/rel/lecode-PAL.bin"):
if os.path.exists(f"{self.path}/files/.MKCreator/"):
self.button_InstallLECODE.grid_forget()
self.button_EditROM.grid(row = 4, column = 1, sticky = "NEWS")
self.button_PatchROM.grid_forget()
else:
self.button_InstallLECODE.grid(row = 3, column = 1, sticky = "NEWS")
self.button_EditROM.grid_forget()
self.button_PatchROM.grid_forget()
def extract_game(self):
@ -127,6 +132,8 @@ class main():
dir = filedialog.askdirectory()
if dir:
self.progressbar_Action.grid(row = 100, column = 1, sticky = "NEWS")
self.label_Action.grid(row = 101, column = 1, sticky = "NEWS")
self.label_Action.config(text = "Extraction du jeu en cours...")
self.button_ExtractROM.grid_forget()
self.progressbar_Action.config(mode="indeterminate")
@ -136,6 +143,7 @@ class main():
p.wait()
self.progressbar_Action.grid_forget()
self.label_Action.grid_forget()
self.path = dir
self.file_type = "dol"
self.refresh_action_frame()
@ -148,16 +156,22 @@ class main():
# visuel
self.progressbar_Action.grid(row = 100, column = 1, sticky = "NEWS")
self.progressbar_Action.config(mode = "determinate")
self.progressbar_Action['maximum'] = 100
self.label_Action.grid(row = 101, column = 1, sticky = "NEWS")
self.progressbar_Action.stop()
self.progressbar_Action['maximum'] = 56
self.progressbar_Action["value"] = 0
self.button_InstallLECODE.grid_forget()
# commande de patch
self.label_Action.config(text="Modification de main.dol...")
self.progressbar_Action.step(1)
p = subprocess.Popen(f"wstrt patch \"{self.path}/sys/main.dol\" --clean-dol --add-lecode", shell=True)
p.wait()
# patch des menus
for file in ["Award", "Channel", "Event", "Globe", "MenuMulti", "MenuOther", "MenuSingle", "Present", "Race", "Title"]:
self.label_Action.config(text=f"Extraction du fichier {file}.szs...")
self.progressbar_Action.step(1)
p = subprocess.Popen(f"wszst EXTRACT \"{self.path}/files/Scene/UI/{file}.szs\" --DEST \"./.tmp/{file}\"")
p.wait()
@ -172,14 +186,19 @@ class main():
}
for subfile in replace_path:
self.label_Action.config(text=f"Remplacement des fichiers de {file}.szs ({subfile})...")
if os.path.exists(subfile): shutil.copy(f"./assets/{replace_path[subfile]}", subfile)
if file in ["Channel", "MenuMulti", "MenuSingle"]:
self.label_Action.config(text=f"Remplacement des icones de {file}.szs...")
self.progressbar_Action.step(1)
shutil.copy(f"./assets/ct_icons-default.tpl", f"./.tmp/{file}/button/timg/ct_icons.tpl")
shutil.copy(f"./assets/ct_icons-default.tpl", f"./.tmp/{file}/control/timg/ct_icons.tpl")
# patch des fichiers de langage des menus
for language in "EFGIS":
self.label_Action.config(text=f"Remplacement des fichiers langues de {file}_{language}.szs...")
self.progressbar_Action.step(1)
szs_path = f"{self.path}/files/Scene/UI/{file}_{language}.szs"
tmp_path = f"./.tmp/{file}_{language}"
if os.path.exists(szs_path):
@ -193,21 +212,25 @@ class main():
p.wait()
os.remove(f"{tmp_path}/message/Common.txt")
self.label_Action.config(text=f"Finalisation de {file}_{language}.szs...")
self.progressbar_Action.step(1)
p = subprocess.Popen(f"wszst CREATE \"{tmp_path}\" --DEST \"{szs_path}\" --overwrite")
p.wait()
shutil.rmtree(tmp_path)
self.label_Action.config(text=f"Finalisation de {file}.szs...")
self.progressbar_Action.step(1)
p = subprocess.Popen(f"wszst CREATE \"./.tmp/{file}\" --DEST \"{self.path}/files/Scene/UI/{file}.szs\" --overwrite")
p.wait()
shutil.rmtree(f"./.tmp/{file}")
# patch des vidéos de présentation
for file in ["banana", "cup_select", "flower", "kinoko", "konoha", "koura", "special", "star", "thunder"]:
self.label_Action.config(text=f"Patch du fichier vidéo {file}...")
shutil.copy("./assets/video.thp", f"{self.path}/files/thp/course/{file}.thp")
# correction des courses
@ -218,9 +241,11 @@ class main():
if os.path.isfile(f"{self.path}/files/Race/Course/{file}"):
_, extension = os.path.splitext(file)
if extension == ".szs":
self.label_Action.config(text=f"Correction de la course {file}...")
shutil.move(f"{self.path}/files/Race/Course/{file}", f"{self.path}/files/.MKCreator/Track/{file}")
# application du patch
self.label_Action.config(text=f"Patch de LE-CODE.bin")
p = subprocess.Popen(f"wlect patch ./assets/lecode-PAL.bin -od \"{self.path}/files/rel/lecode-PAL.bin\" --track-dir "+\
f"\"{self.path}/files/Race/Course\" --copy-tracks \"{self.path}/files/.MKCreator/Track/\" --le-define "+\
f"./assets/CTFILE-default.txt --lpar ./assets/lpar-default.txt --overwrite")
@ -233,6 +258,7 @@ class main():
self.progressbar_Action.grid_forget()
self.label_Action.grid_forget()
self.refresh_action_frame()
Thread(target=main).start()
@ -246,6 +272,8 @@ class main():
def refresh_cup_menu(self):
self.button_PatchROM.grid(row = 5, column = 1, sticky = "NEWS")
for x in range(4):
for y in range(2):
pos_index = (x * 2) + y
@ -316,11 +344,12 @@ class main():
def select_icon():
nonlocal new_icon, new_icon_tk
path = filedialog.askopenfilename()
path = filedialog.askopenfilename(filetypes = (("Icone coupe", r"*.png"),))
tl.focus_force()
if path:
if os.path.exists(path):
new_icon = Image.open(path)
new_icon_tk = ImageTk.PhotoImage(new_icon)
new_icon = Image.open(path).resize((128,128))
new_icon_tk = ImageTk.PhotoImage(new_icon.resize((64,64)))
button_NewCupIcon.config(image=new_icon_tk)
Label(tl, text="Choississez un nom pour votre coupe :").grid(row=1, column=1)
@ -351,6 +380,7 @@ class main():
self.save_config()
self.refresh_cup_menu()
tl.destroy()
self.root.focus_force()
else:
messagebox.showerror("Erreur", "Veuillez choisir un nom pour votre coupe.")
@ -359,11 +389,12 @@ class main():
def select_new_cup_icon(self, index):
path = filedialog.askopenfilename()
path = filedialog.askopenfilename(filetypes = (("Icone coupe", r"*.png"),))
if path:
if os.path.exists(path):
shutil.copy(path, f"{self.path}/files/.MKCreator/cup_icon/{index}.png")
self._selected_cup_img = ImageTk.PhotoImage(Image.open(path))
_cup_img = Image.open(path).resize((128,128))
_cup_img.save(f"{self.path}/files/.MKCreator/cup_icon/{index}.png")
self._selected_cup_img = ImageTk.PhotoImage(_cup_img)
self.button_CupIconManager.config(image=self._selected_cup_img)
self.refresh_cup_menu()
else:
@ -453,7 +484,8 @@ class main():
}
def select_file():
path = filedialog.askopenfilename()
path = filedialog.askopenfilename(filetypes = (("Fichier course", r"*.szs"),))
tl.focus_force()
if path:
if os.path.exists(path):
name = path.split("/")[-1].replace("_", " ").replace(".szs", "")
@ -483,17 +515,190 @@ class main():
listbox_TrackType.current(0)
listbox_TrackType.grid(row=8, column=1, sticky="NEWS", columnspan=2)
Checkbutton(tl, text="marqué comme étant nouveau").grid(row=9, column=1, columnspan=2)
Bool_isTrackNew = BooleanVar(value=False)
checkbutton_TrackNew = Checkbutton(tl, text="Marqué comme étant nouveau", variable=Bool_isTrackNew)
checkbutton_TrackNew.grid(row=9, column=1, columnspan=2)
def confirm():
if os.path.exists(entry_CoursePath.get()):
_formated_name = entry_CourseName.get().replace(" ", "")
if (_formated_name != "") and (_formated_name != "/"):
if listbox_MusicType.get() in track2ID:
if listbox_TrackType.get() in track2ID:
if not(os.path.exists(f"{self.path}/files/.MKCreator/Track/")):
os.makedirs(f"{self.path}/files/.MKCreator/Track/")
shutil.copy(entry_CoursePath.get(), f"{self.path}/files/.MKCreator/Track/{entry_CourseName.get()}.szs")
self.config["cup"][str(cup_index)]["courses"][str(course_index)] = {
"name": entry_CourseName.get(),
"music": track2ID[listbox_MusicType.get()][0],
"special": track2ID[listbox_TrackType.get()][1],
"new": Bool_isTrackNew.get(),
}
self.save_config()
self.select_cup(cup_index)
tl.destroy()
self.root.focus_force()
else: messagebox.showerror("Erreur", "Le type spécial de la map est invalide.")
else: messagebox.showerror("Erreur", "La musique de la map est invalide.")
else: messagebox.showerror("Erreur", "Le nom de la course doit être défini.")
else: messagebox.showerror("Erreur", "Vous devez sélectionner le fichier .szs de la course.")
Button(tl, text="Confirmer", command=confirm, relief=RIDGE).grid(row=10,column=1, columnspan=2, sticky="E")
def patch_game(self):
def main():
self.progressbar_Action.grid(row = 100, column = 1, sticky = "NEWS")
self.label_Action.grid(row = 101, column = 1)
self.label_Action.config(text=f"Préparation...")
self.button_EditROM.grid_forget()
self.button_PatchROM.grid_forget()
self.progressbar_Action.config(mode = "determinate")
self.progressbar_Action.stop()
self.progressbar_Action['maximum'] = 31
self.progressbar_Action["value"] = 0
LE_CODE = ""
TEXT_DATA = [
{"slot": "703e", "name": "Aléatoire: Toutes les pistes"},
{"slot": "703f", "name": "Aléatoire: Pistes Originales"},
{"slot": "7040", "name": "Aléatoire: Custom Tracks"},
{"slot": "7041", "name": "Aléatoire: Pistes Nouvelles"},
]
text_index = 0
total_cup = len(self.config["cup"])
ct_icon = Image.new("RGBA", (128, 128*(total_cup+2)))
base = Image.open("./assets/ct_icons-base.png")
ct_icon.paste(base, (0, 0))
for cup in self.config["cup"]:
self.label_Action.config(text=f"Configuration de la coupe {cup}...")
self.progressbar_Action.step(1)
cup_icon = Image.open(f"{self.path}/files/.MKCreator/cup_icon/{cup}.png")
ct_icon.paste(cup_icon, (0, (int(cup)+2)*128))
if not(cup in ["0","1","2","3","4","5","6","7","8"]):
_cup_config = self.config["cup"][cup]
LE_CODE += f"\n\nC \"{_cup_config['name']}\""
for course in _cup_config["courses"]:
_course_config = _cup_config["courses"][course]
self.label_Action.config(text=f"Configuration de la course {_course_config['name']} (coupe {cup})...")
self.progressbar_Action.step(1)
flag = "0x00"
if _course_config["new"]: flag = "0x01"
LE_CODE += f"\nT {_course_config['music']};"+\
f" {hex(_course_config['special'])};"+\
f" {flag};"+\
f" \"{_course_config['name']}\";"+\
f" \"{_course_config['name']}\";"+\
f" \"\""
TEXT_DATA.append({"slot": format(0x7044 + text_index, '02x'), "name": _course_config['name']})
text_index += 1
if _course_config["name"] == "/":
messagebox.showerror("Erreur", f"Une course semble ne pas avoir été configuré "+\
f"dans la coupe {_cup_config['name']} (slot {course})")
self.progressbar_Action.grid_forget()
self.label_Action.grid_forget()
return
self.label_Action.config(text=f"Création du fichier CTFILE.txt...")
self.progressbar_Action.step(1)
shutil.copy("./assets/CTFILE-default.txt", f"{self.path}/files/.MKCreator/CTFILE.txt")
with open(f"{self.path}/files/.MKCreator/CTFILE.txt", "a") as CTFile:
CTFile.write(LE_CODE)
self.label_Action.config(text=f"Configuration des icones...")
self.progressbar_Action.step(1)
ct_icon.save(f"{self.path}/files/.MKCreator/ct_icons.png")
p = subprocess.Popen(f"wimgt encode \"{self.path}/files/.MKCreator/ct_icons.png\" "+\
f"--DEST \"{self.path}/files/.MKCreator/ct_icons.tpl\" -x tpl.CMPR --overwrite")
p.wait()
for file in ["Channel", "MenuMulti", "MenuSingle"]:
self.label_Action.config(text=f"Configuration des icones {file}.szs...")
self.progressbar_Action.step(1)
p = subprocess.Popen(f"wszst EXTRACT \"{self.path}/files/Scene/UI/{file}.szs\" --DEST \"./.tmp/{file}\"")
p.wait()
shutil.copy(f"{self.path}/files/.MKCreator/ct_icons.tpl", f"./.tmp/{file}/button/timg/ct_icons.tpl")
shutil.copy(f"{self.path}/files/.MKCreator/ct_icons.tpl", f"./.tmp/{file}/control/timg/ct_icons.tpl")
p = subprocess.Popen(f"wszst CREATE \"./.tmp/{file}\" --DEST \"{self.path}/files/Scene/UI/{file}.szs\" --overwrite")
p.wait()
shutil.rmtree(f"./.tmp/{file}")
for language in "EFGIS":
self.label_Action.config(text=f"Configuration des icones {file}_{language}.szs...")
self.progressbar_Action.step(1)
szs_path = f"{self.path}/files/Scene/UI/{file}_{language}.szs"
tmp_path = f"./.tmp/{file}_{language}"
if os.path.exists(szs_path):
p = subprocess.Popen(f"wszst EXTRACT \"{szs_path}\" --DEST \"{tmp_path}\"")
p.wait()
if os.path.exists(f"{tmp_path}/message/Common.bmg"):
p = subprocess.Popen(f"wbmgt decode \"{tmp_path}/message/Common.bmg\" --overwrite")
p.wait()
with open(f"{tmp_path}/message/Common.txt", "a+") as CommonFile:
for line in CommonFile.readlines():
for TEXT in TEXT_DATA:
print(line[len(f" {TEXT['slot']}"):])
if line[len(f" {TEXT['slot']}"):] == f" {TEXT['slot']}":
if line != f"\n {TEXT['slot']}\t= {TEXT['name']}":
pointer = CommonFile.tell()
CommonFile.write(f"\n {TEXT['slot']}\t= {TEXT['name']}")
CommonFile.seek(pointer)
TEXT_DATA.pop(TEXT)
for TEXT in TEXT_DATA:
CommonFile.write(f"\n {TEXT['slot']}\t= {TEXT['name']}")
p = subprocess.Popen(f"wbmgt encode \"{tmp_path}/message/Common.txt\" --overwrite --le-code")
p.wait()
os.remove(f"{tmp_path}/message/Common.txt")
p = subprocess.Popen(f"wszst CREATE \"{tmp_path}\" --DEST \"{szs_path}\" --overwrite")
p.wait()
shutil.rmtree(tmp_path)
self.label_Action.config(text=f"Patch de LE-CODE.bin...")
self.progressbar_Action.step(1)
p = subprocess.Popen(
f"wlect patch ./assets/lecode-PAL.bin -od \"{self.path}/files/rel/lecode-PAL.bin\" --track-dir " + \
f"\"{self.path}/files/Race/Course\" --copy-tracks \"{self.path}/files/.MKCreator/Track/\" --le-define " + \
f"\"{self.path}/files/.MKCreator/CTFILE.txt\" --lpar ./assets/lpar-default.txt --overwrite")
p.wait()
self.progressbar_Action.grid_forget()
self.label_Action.grid_forget()
self.button_EditROM.grid(row = 4, column = 1, sticky = "NEWS")
self.button_PatchROM.grid(row = 5, column = 1, sticky = "NEWS")
Thread(target=main).start()
def save_config(self):
with open(f"{self.path}/files/.MKCreator/config.json", "w") as file:
json.dump(self.config, file)
#TODO: wimgt encode "src" --DEST "dst" -x tpl.CMPR - pour convertir un .png en .tpl
#TODO: sélectionné un fichier force à choisir un type valide
#TODO: chargement de la partie d'injection améliorer (barre de chargement, ...)
#TODO: Icone CTx pour les icones par défaut de course
#TODO: Importer des groupes entier de course et de coupe
#TODO: Vérifier les overwrites pour éviter les bugs
Main = main()
mainloop()