mirror of
https://github.com/Faraphel/Atlas-Install.git
synced 2025-07-03 03:08:29 +02:00
created a Option class, merged get_github_file with Track and install_mod with Game
This commit is contained in:
parent
2f171311bc
commit
2990b1a652
14 changed files with 432 additions and 446 deletions
7
main.pyw
7
main.pyw
|
@ -22,14 +22,13 @@ class ClassApp():
|
|||
from source.StateButton import StateButton
|
||||
from source.patch_file import patch_file
|
||||
from source.patch_bmg import patch_bmg
|
||||
from source.install_mod import install_mod
|
||||
from source.restart import restart
|
||||
from source.patch_img_desc import patch_img_desc
|
||||
from source.log_error import log_error
|
||||
from source.get_github_file import get_github_file
|
||||
from source.patch_track import patch_track, patch_autoadd
|
||||
from source.patch_track import patch_track
|
||||
from source.patch_image import patch_image
|
||||
from source.option import load_option, change_option
|
||||
|
||||
from source.Option import Option
|
||||
from source.CT_Config import CT_Config
|
||||
from source.Game import Game, InvalidGamePath, InvalidFormat
|
||||
|
||||
|
|
140
source/Game.py
140
source/Game.py
|
@ -1,5 +1,9 @@
|
|||
from . import wszst
|
||||
from .definition import *
|
||||
from threading import Thread
|
||||
import subprocess
|
||||
import shutil
|
||||
import json
|
||||
import glob
|
||||
import os
|
||||
|
||||
|
@ -10,6 +14,7 @@ region_id_to_name = {
|
|||
"E": "USA"
|
||||
}
|
||||
|
||||
|
||||
class InvalidGamePath(Exception):
|
||||
def __init__(self):
|
||||
super().__init__("This path is not valid !")
|
||||
|
@ -60,8 +65,139 @@ class Game:
|
|||
self.region_ID = self.game_ID[3]
|
||||
self.region = region_id_to_name[self.region_ID] if self.region_ID in region_id_to_name else self.region
|
||||
|
||||
def install_mod(self):
|
||||
pass
|
||||
def patch_autoadd(self, auto_add_dir: str = "./file/auto-add"):
|
||||
if os.path.exists(auto_add_dir): shutil.rmtree(auto_add_dir)
|
||||
if not os.path.exists(self.path + "/tmp/"): os.makedirs(self.path + "/tmp/")
|
||||
subprocess.run(["./tools/szs/wszst", "AUTOADD", get_nodir(self.path) + "/files/Race/Course/",
|
||||
"--DEST", get_nodir(self.path) + "/tmp/auto-add/"],
|
||||
creationflags=CREATE_NO_WINDOW, cwd=get_dir(self.path),
|
||||
check=True, stdout=subprocess.PIPE)
|
||||
shutil.move(self.path + "/tmp/auto-add/", auto_add_dir)
|
||||
shutil.rmtree(self.path + "/tmp/")
|
||||
|
||||
def install_mod(self, gui):
|
||||
def func():
|
||||
try:
|
||||
with open("./fs.json") as f: fs = json.load(f)
|
||||
|
||||
# This part is used to estimate the max_step
|
||||
extracted_file = []
|
||||
max_step, step = 1, 0
|
||||
|
||||
def count_rf(path):
|
||||
nonlocal max_step
|
||||
max_step += 1
|
||||
if get_extension(path) == "szs":
|
||||
if not (os.path.realpath(path) in extracted_file):
|
||||
extracted_file.append(os.path.realpath(path))
|
||||
max_step += 1
|
||||
|
||||
for fp in fs:
|
||||
for f in glob.glob(self.path + "/files/" + fp, recursive=True):
|
||||
if type(fs[fp]) == str:
|
||||
count_rf(path=f)
|
||||
elif type(fs[fp]) == dict:
|
||||
for nf in fs[fp]:
|
||||
if type(fs[fp][nf]) == str:
|
||||
count_rf(path=f)
|
||||
elif type(fs[fp][nf]) == list:
|
||||
for ffp in fs[fp][nf]: count_rf(path=f)
|
||||
###
|
||||
extracted_file = []
|
||||
max_step += 4 # PATCH main.dol and PATCH lecode.bin, converting, changing ID
|
||||
# self.Progress(show=True, indeter=False, statut=self.translate("Installing mod"), max=max_step, step=0)
|
||||
|
||||
def replace_file(path, file, subpath="/"):
|
||||
# self.Progress(statut=self.translate("Editing", "\n", get_nodir(path)), add=1)
|
||||
extension = get_extension(path)
|
||||
|
||||
if extension == "szs":
|
||||
if not (os.path.realpath(path) in extracted_file):
|
||||
subprocess.run(["./tools/szs/wszst", "EXTRACT", get_nodir(path), "-d", get_nodir(path) + ".d",
|
||||
"--overwrite"], creationflags=CREATE_NO_WINDOW, cwd=get_dir(path),
|
||||
check=True, stdout=subprocess.PIPE)
|
||||
extracted_file.append(os.path.realpath(path))
|
||||
|
||||
szs_extract_path = path + ".d"
|
||||
if os.path.exists(szs_extract_path + subpath):
|
||||
if subpath[-1] == "/":
|
||||
filecopy(f"./file/{file}", szs_extract_path + subpath + file)
|
||||
else:
|
||||
filecopy(f"./file/{file}", szs_extract_path + subpath)
|
||||
|
||||
elif path[-1] == "/":
|
||||
filecopy(f"./file/{file}", path + file)
|
||||
else:
|
||||
filecopy(f"./file/{file}", path)
|
||||
|
||||
for fp in fs:
|
||||
for f in glob.glob(self.path + "/files/" + fp, recursive=True):
|
||||
if type(fs[fp]) == str:
|
||||
replace_file(path=f, file=fs[fp])
|
||||
elif type(fs[fp]) == dict:
|
||||
for nf in fs[fp]:
|
||||
if type(fs[fp][nf]) == str:
|
||||
replace_file(path=f, subpath=nf, file=fs[fp][nf])
|
||||
elif type(fs[fp][nf]) == list:
|
||||
for ffp in fs[fp][nf]: replace_file(path=f, subpath=nf, file=ffp)
|
||||
|
||||
for file in extracted_file:
|
||||
# self.Progress(statut=self.translate("Recompilating", "\n", get_nodir(file)), add=1)
|
||||
subprocess.run(["./tools/szs/wszst", "CREATE", get_nodir(file) + ".d", "-d", get_nodir(file),
|
||||
"--overwrite"], creationflags=CREATE_NO_WINDOW, cwd=get_dir(file),
|
||||
check=True, stdout=subprocess.PIPE)
|
||||
if os.path.exists(file + ".d"): shutil.rmtree(file + ".d")
|
||||
|
||||
# self.Progress(statut=self.translate("Patch main.dol"), add=1)
|
||||
subprocess.run(["./tools/szs/wstrt", "patch", get_nodir(self.path) + "/sys/main.dol", "--clean-dol",
|
||||
"--add-lecode"], creationflags=CREATE_NO_WINDOW, cwd=get_dir(self.path),
|
||||
check=True, stdout=subprocess.PIPE)
|
||||
|
||||
# self.Progress(statut=self.translate("Patch lecode.bin"), add=1)
|
||||
|
||||
shutil.copytree("./file/Track/", self.path+"/files/Race/Course/", dirs_exist_ok=True)
|
||||
if not(os.path.exists(self.path+"/tmp/")): os.makedirs(self.path+"/tmp/")
|
||||
filecopy("./file/CTFILE.txt", self.path+"/tmp/CTFILE.txt")
|
||||
filecopy("./file/lpar-default.txt", self.path + "/tmp/lpar-default.txt")
|
||||
filecopy(f"./file/lecode-{self.region}.bin", self.path + f"/tmp/lecode-{self.region}.bin")
|
||||
|
||||
subprocess.run(
|
||||
["./tools/szs/wlect", "patch", f"./tmp/lecode-{self.region}.bin", "-od",
|
||||
f"./files/rel/lecode-{self.region}.bin", "--track-dir", "./files/Race/Course/",
|
||||
"--move-tracks", "./files/Race/Course/", "--le-define", "./tmp/CTFILE.txt", "--lpar",
|
||||
"./tmp/lpar-default.txt", "--overwrite"],
|
||||
creationflags=CREATE_NO_WINDOW, cwd=self.path, check=True, stdout=subprocess.PIPE)
|
||||
|
||||
shutil.rmtree(self.path + "/tmp/")
|
||||
|
||||
output_format = gui.stringvar_game_format.get()
|
||||
# self.Progress(statut=self.translate("Converting to", " ", output_format), add=1)
|
||||
|
||||
if output_format in ["ISO", "WBFS", "CISO"]:
|
||||
path_game_format: str = os.path.realpath(self.path + "/../MKWFaraphel." + output_format.lower())
|
||||
subprocess.run(["./tools/wit/wit", "COPY", get_nodir(self.path), "--DEST",
|
||||
get_nodir(path_game_format), f"--{output_format.lower()}", "--overwrite"],
|
||||
creationflags=CREATE_NO_WINDOW, cwd=get_dir(path_game_format),
|
||||
check=True, stdout=subprocess.PIPE)
|
||||
shutil.rmtree(self.path)
|
||||
self.path = path_game_format
|
||||
|
||||
# self.Progress(statut=self.translate("Changing game's ID"), add=1)
|
||||
subprocess.run(["./tools/wit/wit", "EDIT", get_nodir(self.path), "--id",
|
||||
f"RMC{self.region_ID}60", "--name",
|
||||
f"Mario Kart Wii Faraphel {gui.ctconfig.version}", "--modify", "ALL"],
|
||||
creationflags=CREATE_NO_WINDOW, cwd=get_dir(self.path),
|
||||
check=True, stdout=subprocess.PIPE)
|
||||
|
||||
# messagebox.showinfo(self.translate("End"), self.translate("The mod has been installed !"))
|
||||
|
||||
except: pass # self.log_error()
|
||||
finally: pass # self.Progress(show=False)
|
||||
|
||||
t = Thread(target=func)
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
return t
|
||||
|
||||
def convert_to(self, format: str = "FST"):
|
||||
"""
|
||||
|
|
34
source/Option.py
Normal file
34
source/Option.py
Normal file
|
@ -0,0 +1,34 @@
|
|||
import json
|
||||
import os
|
||||
|
||||
|
||||
class Option:
|
||||
def __init__(self):
|
||||
self.language = "en"
|
||||
self.format = "FST"
|
||||
self.disable_download = False
|
||||
self.del_track_after_conv = False
|
||||
self.dont_check_for_update = False
|
||||
self.dont_check_track_sha1 = False
|
||||
self.process_track = 8
|
||||
|
||||
def load_from_json(self, option_json: dict):
|
||||
for key, value in option_json.items(): # load all value in the json as class attribute
|
||||
setattr(self, key, value)
|
||||
|
||||
def load_from_file(self, option_file: str = "./option.json"):
|
||||
if os.path.exists(option_file):
|
||||
with open(option_file, encoding="utf-8") as file:
|
||||
file_json = json.load(file)
|
||||
self.load_from_json(file_json)
|
||||
|
||||
def save_to_file(self, option_file: str = "./option.json"):
|
||||
option_json: dict = self.__dict__ # this return all attribute of the class as a dict
|
||||
with open(option_file, "w", encoding="utf-8") as file:
|
||||
json.dump(option_json, file, ensure_ascii=False)
|
||||
|
||||
def edit(self, option, value, need_restart=False, gui=None):
|
||||
if type(value) in [str, int, bool]: setattr(self, option, value)
|
||||
else: setattr(self, option, value.get())
|
||||
self.save_to_file()
|
||||
if need_restart: gui.restart()
|
|
@ -1,11 +1,14 @@
|
|||
from .definition import *
|
||||
import source.wszst
|
||||
import requests
|
||||
import os
|
||||
|
||||
|
||||
class Track:
|
||||
def __init__(self, name: str = "_", file_wu8: str = None, file_szs: str = None, prefix: str = None, suffix: str = None,
|
||||
author="Nintendo", special="T11", music="T11", new=True, sha1: str = None, since_version: str = None,
|
||||
score: int = 0, warning: int = 0, note: str = "", *args, **kwargs):
|
||||
score: int = 0, warning: int = 0, note: str = "", track_wu8_dir: str = "./file/Track-WU8/",
|
||||
track_szs_dir: str = "./file/Track/", *args, **kwargs):
|
||||
|
||||
self.name = name # Track name
|
||||
self.prefix = prefix # Prefix, often used for game or original console like Wii U, DS, ...
|
||||
|
@ -19,8 +22,8 @@ class Track:
|
|||
self.score = score # Track score between 1 and 3 stars
|
||||
self.warning = warning # Track bug level (1 = minor, 2 = major)
|
||||
self.note = note # Note about the track
|
||||
self.file_wu8 = f"./file/Track-WU8/{self.get_track_name()}.wu8"
|
||||
self.file_szs = f"./file/Track/{self.get_track_name()}.szs"
|
||||
self.file_wu8 = f"{track_wu8_dir}/{self.get_track_name()}.wu8"
|
||||
self.file_szs = f"{track_szs_dir}/{self.get_track_name()}.szs"
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.get_track_name()} sha1={self.sha1} score={self.score}"
|
||||
|
@ -32,8 +35,8 @@ class Track:
|
|||
name = (prefix + self.name + suffix)
|
||||
return name
|
||||
|
||||
def load_from_json(self, track: dict):
|
||||
for key, value in track.items(): # load all value in the json as class attribute
|
||||
def load_from_json(self, track_json: dict):
|
||||
for key, value in track_json.items(): # load all value in the json as class attribute
|
||||
setattr(self, key, value)
|
||||
|
||||
def get_track_formatted_name(self, highlight_track_from_version: str = None):
|
||||
|
@ -67,7 +70,24 @@ class Track:
|
|||
def convert_wu8_to_szs(self):
|
||||
return source.wszst.normalize(src_file=self.file_wu8, use_popen=True)
|
||||
|
||||
def download_wu8(self): pass
|
||||
def download_wu8(self):
|
||||
returncode = 0
|
||||
|
||||
dl = requests.get(get_github_content_root(self) + self.file_wu8, allow_redirects=True, stream=True)
|
||||
if os.path.exists(self.file_wu8):
|
||||
if int(dl.headers['Content-Length']) == os.path.getsize(self.file_wu8): return 1
|
||||
else: returncode = 3
|
||||
|
||||
if dl.status_code == 200: # if page is found
|
||||
with open(self.file_wu8, "wb") as file:
|
||||
chunk_size = 4096
|
||||
for i, chunk in enumerate(dl.iter_content(chunk_size=chunk_size)):
|
||||
file.write(chunk)
|
||||
file.flush()
|
||||
return returncode
|
||||
else:
|
||||
print(f"error {dl.status_code} {self.file_wu8}")
|
||||
return -1
|
||||
|
||||
def check_sha1(self):
|
||||
if source.wszst.sha1(self.file_wu8) == self.sha1: return 0
|
||||
|
|
|
@ -9,24 +9,25 @@ from .definition import *
|
|||
from .check_update import check_update
|
||||
from .translate import translate
|
||||
from .CT_Config import *
|
||||
from .Option import *
|
||||
from .Game import *
|
||||
|
||||
def __init__(self):
|
||||
try:
|
||||
self.root = Tk()
|
||||
|
||||
self.load_option()
|
||||
self.option = Option()
|
||||
self.option.load_from_file("./option.json")
|
||||
self.ctconfig = CT_Config()
|
||||
self.ctconfig.load_ctconfig_file("./ct_config.json")
|
||||
|
||||
self.is_dev_version = False # Is this installer version a dev ?
|
||||
self.stringvar_language = StringVar(value=self.option["language"])
|
||||
self.stringvar_game_format = StringVar(value=self.option["format"])
|
||||
self.boolvar_disable_download = BooleanVar(value=self.option["disable_download"])
|
||||
self.boolvar_del_track_after_conv = BooleanVar(value=self.option["del_track_after_conv"])
|
||||
self.boolvar_dont_check_for_update = BooleanVar(value=self.option["dont_check_for_update"])
|
||||
self.boolvar_dont_check_track_sha1 = BooleanVar(value=self.option["dont_check_track_sha1"])
|
||||
self.intvar_process_track = IntVar(value=self.option["process_track"])
|
||||
self.stringvar_language = StringVar(value=self.option.language)
|
||||
self.stringvar_game_format = StringVar(value=self.option.format)
|
||||
self.boolvar_disable_download = BooleanVar(value=self.option.disable_download)
|
||||
self.boolvar_del_track_after_conv = BooleanVar(value=self.option.del_track_after_conv)
|
||||
self.boolvar_dont_check_for_update = BooleanVar(value=self.option.dont_check_for_update)
|
||||
self.boolvar_dont_check_track_sha1 = BooleanVar(value=self.option.dont_check_track_sha1)
|
||||
self.intvar_process_track = IntVar(value=self.option.process_track)
|
||||
self.boolvar_use_1star_track = BooleanVar(value=True)
|
||||
self.boolvar_use_2star_track = BooleanVar(value=True)
|
||||
self.boolvar_use_3star_track = BooleanVar(value=True)
|
||||
|
@ -43,15 +44,15 @@ def __init__(self):
|
|||
|
||||
self.menu_language = Menu(self.menu_bar, tearoff=0)
|
||||
self.menu_bar.add_cascade(label=self.translate("Language"), menu=self.menu_language)
|
||||
self.menu_language.add_radiobutton(label="Français", variable=self.stringvar_language, value="fr", command=lambda: self.change_option("language", "fr", restart=True))
|
||||
self.menu_language.add_radiobutton(label="English", variable=self.stringvar_language, value="en", command=lambda: self.change_option("language", "en", restart=True))
|
||||
self.menu_language.add_radiobutton(label="Français", variable=self.stringvar_language, value="fr", command=lambda: self.option.edit("language", "fr", restart=True))
|
||||
self.menu_language.add_radiobutton(label="English", variable=self.stringvar_language, value="en", command=lambda: self.option.edit("language", "en", restart=True))
|
||||
|
||||
self.menu_format = Menu(self.menu_bar, tearoff=0)
|
||||
self.menu_bar.add_cascade(label=self.translate("Format"), menu=self.menu_format)
|
||||
self.menu_format.add_radiobutton(label=self.translate("FST (Directory)"), variable=self.stringvar_game_format, value="FST", command=lambda: self.change_option("format", "FST"))
|
||||
self.menu_format.add_radiobutton(label="ISO", variable=self.stringvar_game_format, value="ISO", command=lambda: self.change_option("format", "ISO"))
|
||||
self.menu_format.add_radiobutton(label="CISO", variable=self.stringvar_game_format, value="CISO", command=lambda: self.change_option("format", "CISO"))
|
||||
self.menu_format.add_radiobutton(label="WBFS", variable=self.stringvar_game_format, value="WBFS", command=lambda: self.change_option("format", "WBFS"))
|
||||
self.menu_format.add_radiobutton(label=self.translate("FST (Directory)"), variable=self.stringvar_game_format, value="FST", command=lambda: self.option.edit("format", "FST"))
|
||||
self.menu_format.add_radiobutton(label="ISO", variable=self.stringvar_game_format, value="ISO", command=lambda: self.option.edit("format", "ISO"))
|
||||
self.menu_format.add_radiobutton(label="CISO", variable=self.stringvar_game_format, value="CISO", command=lambda: self.option.edit("format", "CISO"))
|
||||
self.menu_format.add_radiobutton(label="WBFS", variable=self.stringvar_game_format, value="WBFS", command=lambda: self.option.edit("format", "WBFS"))
|
||||
|
||||
self.menu_trackselection = Menu(self.menu_bar, tearoff=0)
|
||||
self.menu_bar.add_cascade(label=self.translate("Track selection"), menu=self.menu_trackselection)
|
||||
|
@ -67,17 +68,17 @@ def __init__(self):
|
|||
|
||||
self.menu_advanced = Menu(self.menu_bar, tearoff=0)
|
||||
self.menu_bar.add_cascade(label=self.translate("Advanced"), menu=self.menu_advanced)
|
||||
self.menu_advanced.add_checkbutton(label=self.translate("Disable downloads"), variable=self.boolvar_disable_download, command=lambda: self.change_option("disable_download", self.boolvar_disable_download))
|
||||
self.menu_advanced.add_checkbutton(label=self.translate("Delete track after wu8 to szs conversion"), variable=self.boolvar_del_track_after_conv, command=lambda: self.change_option("del_track_after_conv", self.boolvar_del_track_after_conv))
|
||||
self.menu_advanced.add_checkbutton(label=self.translate("Don't check for update"), variable=self.boolvar_dont_check_for_update, command=lambda: self.change_option("dont_check_for_update", self.boolvar_dont_check_for_update))
|
||||
self.menu_advanced.add_checkbutton(label=self.translate("Don't check track's sha1"), variable=self.boolvar_dont_check_track_sha1, command=lambda: self.change_option("dont_check_track_sha1",self.boolvar_dont_check_track_sha1))
|
||||
self.menu_advanced.add_checkbutton(label=self.translate("Disable downloads"), variable=self.boolvar_disable_download, command=lambda: self.option.edit("disable_download", self.boolvar_disable_download))
|
||||
self.menu_advanced.add_checkbutton(label=self.translate("Delete track after wu8 to szs conversion"), variable=self.boolvar_del_track_after_conv, command=lambda: self.option.edit("del_track_after_conv", self.boolvar_del_track_after_conv))
|
||||
self.menu_advanced.add_checkbutton(label=self.translate("Don't check for update"), variable=self.boolvar_dont_check_for_update, command=lambda: self.option.edit("dont_check_for_update", self.boolvar_dont_check_for_update))
|
||||
self.menu_advanced.add_checkbutton(label=self.translate("Don't check track's sha1"), variable=self.boolvar_dont_check_track_sha1, command=lambda: self.option.edit("dont_check_track_sha1",self.boolvar_dont_check_track_sha1))
|
||||
|
||||
self.menu_advanced.add_separator()
|
||||
self.menu_advanced.add_command(label=self.translate("Number of track conversion process", " :"))
|
||||
self.menu_advanced.add_radiobutton(label=self.translate("1 ", "process"), variable=self.intvar_process_track, value=1, command=lambda: self.change_option("process_track", 1))
|
||||
self.menu_advanced.add_radiobutton(label=self.translate("2 ", "process"), variable=self.intvar_process_track, value=2, command=lambda: self.change_option("process_track", 2))
|
||||
self.menu_advanced.add_radiobutton(label=self.translate("4 ", "process"), variable=self.intvar_process_track, value=4, command=lambda: self.change_option("process_track", 4))
|
||||
self.menu_advanced.add_radiobutton(label=self.translate("8 ", "process"), variable=self.intvar_process_track, value=8, command=lambda: self.change_option("process_track", 8))
|
||||
self.menu_advanced.add_radiobutton(label=self.translate("1 ", "process"), variable=self.intvar_process_track, value=1, command=lambda: self.option.edit("process_track", 1))
|
||||
self.menu_advanced.add_radiobutton(label=self.translate("2 ", "process"), variable=self.intvar_process_track, value=2, command=lambda: self.option.edit("process_track", 2))
|
||||
self.menu_advanced.add_radiobutton(label=self.translate("4 ", "process"), variable=self.intvar_process_track, value=4, command=lambda: self.option.edit("process_track", 4))
|
||||
self.menu_advanced.add_radiobutton(label=self.translate("8 ", "process"), variable=self.intvar_process_track, value=8, command=lambda: self.option.edit("process_track", 8))
|
||||
|
||||
|
||||
self.frame_language = Frame(self.root)
|
||||
|
@ -132,7 +133,7 @@ def __init__(self):
|
|||
def func():
|
||||
use_path().join()
|
||||
self.patch_file().join()
|
||||
self.install_mod().join()
|
||||
self.game.install_mod(self).join()
|
||||
|
||||
if messagebox.askyesno(self.translate("Experimental functionality"),
|
||||
self.translate("This will extract the selected ROM, prepare files and install mod. "
|
||||
|
@ -141,22 +142,16 @@ def __init__(self):
|
|||
t.setDaemon(True)
|
||||
t.start()
|
||||
|
||||
self.button_do_everything = Button(self.frame_game_path_action, text=self.translate("Do everything"),
|
||||
relief=RIDGE, command=do_everything)
|
||||
self.button_do_everything = Button(self.frame_game_path_action, text=self.translate("Do everything"), relief=RIDGE, command=do_everything)
|
||||
self.button_do_everything.grid(row=1, column=2, sticky="NEWS")
|
||||
|
||||
|
||||
self.frame_action = LabelFrame(self.root, text=self.translate("Action"))
|
||||
|
||||
self.button_prepare_file = Button(self.frame_action, text=self.translate("Prepare files"), relief=RIDGE,
|
||||
command=self.patch_file, width=45)
|
||||
self.button_prepare_file = Button(self.frame_action, text=self.translate("Prepare files"), relief=RIDGE, command=self.patch_file, width=45)
|
||||
self.button_prepare_file.grid(row=1, column=1, columnspan=2, sticky="NEWS")
|
||||
self.button_install_mod = Button(self.frame_action, text=self.translate("Install mod"), relief=RIDGE,
|
||||
command=self.install_mod, width=45)
|
||||
self.button_install_mod = Button(self.frame_action, text=self.translate("Install mod"), relief=RIDGE, command=lambda: self.game.install_mod(self), width=45)
|
||||
# Install mod button will only appear after prepare file step
|
||||
|
||||
self.progressbar = ttk.Progressbar(self.root)
|
||||
self.progresslabel = Label(self.root)
|
||||
|
||||
except:
|
||||
self.log_error()
|
||||
|
|
|
@ -46,6 +46,6 @@ def check_update(self):
|
|||
except requests.ConnectionError:
|
||||
messagebox.showwarning(self.translate("Warning"),
|
||||
self.translate("Can't connect to internet. Download will be disabled."))
|
||||
self.option["disable_download"] = True
|
||||
self.option.disable_download = True
|
||||
|
||||
except: self.log_error()
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
import requests
|
||||
import os
|
||||
|
||||
from .definition import *
|
||||
|
||||
|
||||
def get_github_file(self, file):
|
||||
try:
|
||||
returncode = 0
|
||||
if self.boolvar_disable_download.get(): return 2
|
||||
|
||||
dl = requests.get(get_github_content_root(self)+file, allow_redirects=True, stream=True)
|
||||
if os.path.exists(file):
|
||||
if int(dl.headers['Content-Length']) == os.path.getsize(file): return 1
|
||||
else: returncode = 3
|
||||
|
||||
if dl.status_code == 200: # if page is found
|
||||
with open(file, "wb") as file:
|
||||
chunk_size = 4096
|
||||
for i, chunk in enumerate(dl.iter_content(chunk_size=chunk_size)):
|
||||
file.write(chunk)
|
||||
file.flush()
|
||||
return returncode
|
||||
else:
|
||||
print(f"error {dl.status_code} {file}")
|
||||
return -1
|
||||
except:
|
||||
self.log_error()
|
||||
return -1
|
||||
|
||||
# TODO: if version > github version, do not search in master branch but dev branch
|
|
@ -1,137 +0,0 @@
|
|||
from tkinter import messagebox
|
||||
from threading import Thread
|
||||
import subprocess
|
||||
import shutil
|
||||
import json
|
||||
import glob
|
||||
import os
|
||||
|
||||
from .definition import *
|
||||
|
||||
|
||||
def install_mod(self):
|
||||
def func():
|
||||
try:
|
||||
with open("./fs.json") as f:
|
||||
fs = json.load(f)
|
||||
|
||||
# This part is used to estimate the max_step
|
||||
extracted_file = []
|
||||
max_step, step = 1, 0
|
||||
|
||||
def count_rf(path):
|
||||
nonlocal max_step
|
||||
max_step += 1
|
||||
if get_extension(path) == "szs":
|
||||
if not (os.path.realpath(path) in extracted_file):
|
||||
extracted_file.append(os.path.realpath(path))
|
||||
max_step += 1
|
||||
|
||||
for fp in fs:
|
||||
for f in glob.glob(self.game.path + "/files/" + fp, recursive=True):
|
||||
if type(fs[fp]) == str:
|
||||
count_rf(path=f)
|
||||
elif type(fs[fp]) == dict:
|
||||
for nf in fs[fp]:
|
||||
if type(fs[fp][nf]) == str:
|
||||
count_rf(path=f)
|
||||
elif type(fs[fp][nf]) == list:
|
||||
for ffp in fs[fp][nf]: count_rf(path=f)
|
||||
###
|
||||
extracted_file = []
|
||||
max_step += 4 # PATCH main.dol and PATCH lecode.bin, converting, changing ID
|
||||
self.Progress(show=True, indeter=False, statut=self.translate("Installing mod"), max=max_step, step=0)
|
||||
|
||||
def replace_file(path, file, subpath="/"):
|
||||
self.Progress(statut=self.translate("Editing", "\n", get_nodir(path)), add=1)
|
||||
extension = get_extension(path)
|
||||
|
||||
if extension == "szs":
|
||||
if not (os.path.realpath(path) in extracted_file):
|
||||
subprocess.run(["./tools/szs/wszst", "EXTRACT", get_nodir(path), "-d", get_nodir(path) + ".d",
|
||||
"--overwrite"], creationflags=CREATE_NO_WINDOW, cwd=get_dir(path),
|
||||
check=True, stdout=subprocess.PIPE)
|
||||
extracted_file.append(os.path.realpath(path))
|
||||
|
||||
szs_extract_path = path + ".d"
|
||||
if os.path.exists(szs_extract_path + subpath):
|
||||
if subpath[-1] == "/":
|
||||
filecopy(f"./file/{file}", szs_extract_path + subpath + file)
|
||||
else:
|
||||
filecopy(f"./file/{file}", szs_extract_path + subpath)
|
||||
|
||||
elif path[-1] == "/":
|
||||
filecopy(f"./file/{file}", path + file)
|
||||
else:
|
||||
filecopy(f"./file/{file}", path)
|
||||
|
||||
for fp in fs:
|
||||
for f in glob.glob(self.game.path + "/files/" + fp, recursive=True):
|
||||
if type(fs[fp]) == str:
|
||||
replace_file(path=f, file=fs[fp])
|
||||
elif type(fs[fp]) == dict:
|
||||
for nf in fs[fp]:
|
||||
if type(fs[fp][nf]) == str:
|
||||
replace_file(path=f, subpath=nf, file=fs[fp][nf])
|
||||
elif type(fs[fp][nf]) == list:
|
||||
for ffp in fs[fp][nf]: replace_file(path=f, subpath=nf, file=ffp)
|
||||
|
||||
for file in extracted_file:
|
||||
self.Progress(statut=self.translate("Recompilating", "\n", get_nodir(file)), add=1)
|
||||
subprocess.run(["./tools/szs/wszst", "CREATE", get_nodir(file) + ".d", "-d", get_nodir(file),
|
||||
"--overwrite"], creationflags=CREATE_NO_WINDOW, cwd=get_dir(file),
|
||||
check=True, stdout=subprocess.PIPE)
|
||||
if os.path.exists(file + ".d"): shutil.rmtree(file + ".d")
|
||||
|
||||
self.Progress(statut=self.translate("Patch main.dol"), add=1)
|
||||
subprocess.run(["./tools/szs/wstrt", "patch", get_nodir(self.game.path) + "/sys/main.dol", "--clean-dol",
|
||||
"--add-lecode"], creationflags=CREATE_NO_WINDOW, cwd=get_dir(self.game.path),
|
||||
check=True, stdout=subprocess.PIPE)
|
||||
|
||||
self.Progress(statut=self.translate("Patch lecode.bin"), add=1)
|
||||
|
||||
shutil.copytree("./file/Track/", self.game.path+"/files/Race/Course/", dirs_exist_ok=True)
|
||||
if not(os.path.exists(self.game.path+"/tmp/")): os.makedirs(self.game.path+"/tmp/")
|
||||
filecopy("./file/CTFILE.txt", self.game.path+"/tmp/CTFILE.txt")
|
||||
filecopy("./file/lpar-default.txt", self.game.path + "/tmp/lpar-default.txt")
|
||||
filecopy(f"./file/lecode-{self.game.region}.bin", self.game.path + f"/tmp/lecode-{self.game.region}.bin")
|
||||
|
||||
subprocess.run(
|
||||
["./tools/szs/wlect", "patch", f"./tmp/lecode-{self.game.region}.bin", "-od",
|
||||
f"./files/rel/lecode-{self.game.region}.bin", "--track-dir", "./files/Race/Course/",
|
||||
"--move-tracks", "./files/Race/Course/", "--le-define", "./tmp/CTFILE.txt", "--lpar",
|
||||
"./tmp/lpar-default.txt", "--overwrite"],
|
||||
creationflags=CREATE_NO_WINDOW, cwd=self.game.path, check=True, stdout=subprocess.PIPE)
|
||||
|
||||
shutil.rmtree(self.game.path + "/tmp/")
|
||||
|
||||
outputformat = self.stringvar_game_format.get()
|
||||
self.Progress(statut=self.translate("Converting to", " ", outputformat), add=1)
|
||||
|
||||
if outputformat in ["ISO", "WBFS", "CISO"]:
|
||||
path_game_format: str = os.path.realpath(self.game.path + "/../MKWFaraphel." + outputformat.lower())
|
||||
subprocess.run(["./tools/wit/wit", "COPY", get_nodir(self.game.path), "--DEST",
|
||||
get_nodir(path_game_format), f"--{outputformat.lower()}", "--overwrite"],
|
||||
creationflags=CREATE_NO_WINDOW, cwd=get_dir(path_game_format),
|
||||
check=True, stdout=subprocess.PIPE)
|
||||
shutil.rmtree(self.game.path)
|
||||
self.game.path = path_game_format
|
||||
|
||||
self.Progress(statut=self.translate("Changing game's ID"), add=1)
|
||||
subprocess.run(["./tools/wit/wit", "EDIT", get_nodir(self.game.path), "--id",
|
||||
f"RMC{self.game.region_ID}60", "--name",
|
||||
f"Mario Kart Wii Faraphel {self.ctconfig.version}", "--modify", "ALL"],
|
||||
creationflags=CREATE_NO_WINDOW, cwd=get_dir(self.game.path),
|
||||
check=True, stdout=subprocess.PIPE)
|
||||
|
||||
messagebox.showinfo(self.translate("End"), self.translate("The mod has been installed !"))
|
||||
|
||||
except: self.log_error()
|
||||
finally: self.Progress(show=False)
|
||||
|
||||
t = Thread(target=func)
|
||||
t.setDaemon(True)
|
||||
t.start()
|
||||
return t
|
||||
|
||||
# TODO: use wszst module instead of subprocess
|
|
@ -1,8 +1,9 @@
|
|||
import traceback
|
||||
from tkinter import messagebox
|
||||
|
||||
|
||||
def log_error(self):
|
||||
def log_error(func):
|
||||
try: func()
|
||||
except Exception:
|
||||
error = traceback.format_exc()
|
||||
with open("./error.log", "a") as f: f.write(f"---\n{error}\n")
|
||||
messagebox.showerror(self.translate("Error"), self.translate("An error occured", " :", "\n", error, "\n\n"))
|
||||
# messagebox.showerror(self.translate("Error"), self.translate("An error occured", " :", "\n", error, "\n\n"))
|
|
@ -1,32 +0,0 @@
|
|||
import json
|
||||
import os
|
||||
|
||||
default_option = {
|
||||
"language": "en",
|
||||
"format": "FST",
|
||||
"disable_download": False,
|
||||
"del_track_after_conv": False,
|
||||
"dont_check_for_update": False,
|
||||
"dont_check_track_sha1": False,
|
||||
"process_track": 8
|
||||
}
|
||||
|
||||
with open("./translation.json", encoding="utf-8") as f:
|
||||
translation_dict = json.load(f)
|
||||
|
||||
|
||||
def change_option(self, option, value, restart=False):
|
||||
if type(value) in [str, int, bool]: self.option[option] = value
|
||||
else: self.option[option] = value.get()
|
||||
with open("./option.json", "w", encoding="utf-8") as f: json.dump(self.option, f, ensure_ascii=False)
|
||||
if restart: self.restart()
|
||||
|
||||
|
||||
def load_option(self):
|
||||
if not(os.path.exists("./option.json")):
|
||||
with open("./option.json", "w", encoding="utf-8") as f: json.dump(default_option, f, ensure_ascii=False)
|
||||
with open("./option.json", encoding="utf-8") as f: self.option = json.load(f)
|
||||
|
||||
for option_key, option_value in default_option.items():
|
||||
if not(option_key in self.option):
|
||||
self.option[option_key] = option_value
|
|
@ -1,21 +1,7 @@
|
|||
from .definition import *
|
||||
from tkinter import messagebox
|
||||
import subprocess
|
||||
import shutil
|
||||
import os
|
||||
|
||||
|
||||
def patch_autoadd(self):
|
||||
if os.path.exists("./file/auto-add"): shutil.rmtree("./file/auto-add")
|
||||
if not os.path.exists(self.game.path + "/tmp/"): os.makedirs(self.game.path + "/tmp/")
|
||||
subprocess.run(["./tools/szs/wszst", "AUTOADD", get_nodir(self.game.path) + "/files/Race/Course/",
|
||||
"--DEST", get_nodir(self.game.path) + "/tmp/auto-add/"],
|
||||
creationflags=CREATE_NO_WINDOW, cwd=get_dir(self.game.path),
|
||||
check=True, stdout=subprocess.PIPE)
|
||||
shutil.move(self.game.path + "/tmp/auto-add/", "./file/auto-add/")
|
||||
shutil.rmtree(self.game.path + "/tmp/")
|
||||
|
||||
|
||||
def patch_track(self):
|
||||
max_process = self.intvar_process_track.get()
|
||||
process_list = {}
|
||||
|
@ -35,8 +21,9 @@ def patch_track(self):
|
|||
if os.path.getsize(_track) < 1000: # File under this size are corrupted
|
||||
os.remove(_track)
|
||||
|
||||
if not self.boolvar_disable_download.get():
|
||||
while True:
|
||||
download_returncode = self.get_github_file(track.file_wu8)
|
||||
download_returncode = track.download_wu8()
|
||||
if download_returncode == -1: # can't download
|
||||
error_count += 1
|
||||
if error_count > error_max: # Too much track wasn't correctly converted
|
||||
|
@ -94,7 +81,7 @@ def patch_track(self):
|
|||
else: # if the error max hasn't been reach
|
||||
messagebox.showwarning(
|
||||
self.translate("Warning"),
|
||||
self.translate("The track", " ", get_track_wu8(track_file),
|
||||
self.translate("The track", " ", track.file_wu8,
|
||||
"do not have been properly converted.",
|
||||
f" ({error_count} / {error_max})"))
|
||||
else:
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
from .option import translation_dict
|
||||
import json
|
||||
|
||||
with open("./translation.json", encoding="utf-8") as f:
|
||||
translation_dict = json.load(f)
|
||||
|
||||
|
||||
def translate(self, *texts, lang=None):
|
||||
|
|
|
@ -32,6 +32,11 @@ def normalize(src_file: str, dest_dir: str = "./file/Track/", dest_name: str = "
|
|||
|
||||
|
||||
def extract(file: str, dest_dir: str):
|
||||
"""
|
||||
:param file: game's file to extract (can be WBFS, ISO, CISO)
|
||||
:param dest_dir: where to extract the game
|
||||
:return: ?
|
||||
"""
|
||||
subprocess.run(["./tools/wit/wit", "EXTRACT", get_nodir(file), "--DEST", dest_dir],
|
||||
creationflags=CREATE_NO_WINDOW, cwd=get_dir(file))
|
||||
|
||||
|
@ -51,3 +56,9 @@ def wlect_patch(file: str,
|
|||
ctfile_path: str = "./tmp/CTFILE.txt",
|
||||
lpar_path: str = "./tmp/lpar-default.txt"):
|
||||
pass
|
||||
|
||||
|
||||
def edit(): pass
|
||||
|
||||
|
||||
def autoadd(): pass
|
Loading…
Reference in a new issue