mirror of
https://github.com/Faraphel/Atlas-Install.git
synced 2025-07-01 18:28:27 +02:00
added a 2nd progress bar
This commit is contained in:
parent
917f491ad1
commit
c0915ae13e
10 changed files with 118 additions and 100 deletions
|
@ -13,6 +13,7 @@ from source.gui import better_gui_error, mystuff, mod_settings
|
||||||
from source.mkw.Game import Game
|
from source.mkw.Game import Game
|
||||||
from source.mkw.ModConfig import ModConfig
|
from source.mkw.ModConfig import ModConfig
|
||||||
from source.option import Option
|
from source.option import Option
|
||||||
|
from source.progress import Progress
|
||||||
from source.translation import translate as _
|
from source.translation import translate as _
|
||||||
from source import plugins
|
from source import plugins
|
||||||
from source import *
|
from source import *
|
||||||
|
@ -95,18 +96,23 @@ class Window(tkinter.Tk):
|
||||||
for child in self.winfo_children():
|
for child in self.winfo_children():
|
||||||
getattr(child, "set_state", lambda *_: "pass")(state)
|
getattr(child, "set_state", lambda *_: "pass")(state)
|
||||||
|
|
||||||
def progress_function(self, func_gen: Generator) -> None:
|
def progress_function(self, func_gen: Generator[Progress, None, None]) -> None:
|
||||||
"""
|
"""
|
||||||
Run a generator function that yield status for the progress bar
|
Run a generator function that yield status for the progress bar
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
# get the generator data yield by the generator function
|
# get the generator data yield by the generator function
|
||||||
for step_data in func_gen:
|
for progress in func_gen:
|
||||||
if "description" in step_data: self.progress_bar.set_description(step_data["description"])
|
if progress.title is not None: self.progress_bar.set_title(progress.title)
|
||||||
if "maximum" in step_data: self.progress_bar.set_maximum(step_data["maximum"])
|
if progress.part is not None: self.progress_bar.part(progress.part)
|
||||||
if "step" in step_data: self.progress_bar.step(step_data["step"])
|
if progress.set_part is not None: self.progress_bar.set_part(progress.set_part)
|
||||||
if "value" in step_data: self.progress_bar.set_value(step_data["value"])
|
if progress.max_part is not None: self.progress_bar.set_max_part(progress.max_part)
|
||||||
if "determinate" in step_data: self.progress_bar.set_determinate(step_data["determinate"])
|
|
||||||
|
if progress.description is not None: self.progress_bar.set_description(progress.description)
|
||||||
|
if progress.step is not None: self.progress_bar.step(progress.step)
|
||||||
|
if progress.set_step is not None: self.progress_bar.set_step(progress.set_step)
|
||||||
|
if progress.max_step is not None: self.progress_bar.set_max_step(progress.max_step)
|
||||||
|
if progress.determinate is not None: self.progress_bar.set_determinate(progress.determinate)
|
||||||
|
|
||||||
def get_mod_config(self) -> ModConfig:
|
def get_mod_config(self) -> ModConfig:
|
||||||
"""
|
"""
|
||||||
|
@ -450,11 +456,17 @@ class ProgressBar(ttk.LabelFrame):
|
||||||
# make the element fill the whole frame
|
# make the element fill the whole frame
|
||||||
self.columnconfigure(1, weight=1)
|
self.columnconfigure(1, weight=1)
|
||||||
|
|
||||||
self.progress_bar = ttk.Progressbar(self, orient="horizontal")
|
self.progress_bar_part = ttk.Progressbar(self, orient="horizontal")
|
||||||
self.progress_bar.grid(row=1, column=1, sticky="nsew")
|
self.progress_bar_part.grid(row=1, column=1, sticky="nsew")
|
||||||
|
|
||||||
|
self.title = ttk.Label(self, text="", anchor="center", font=("TkDefaultFont", 10), wraplength=350)
|
||||||
|
self.title.grid(row=2, column=1, sticky="nsew")
|
||||||
|
|
||||||
|
self.progress_bar_step = ttk.Progressbar(self, orient="horizontal")
|
||||||
|
self.progress_bar_step.grid(row=3, column=1, sticky="nsew")
|
||||||
|
|
||||||
self.description = ttk.Label(self, text="", anchor="center", font=("TkDefaultFont", 10), wraplength=350)
|
self.description = ttk.Label(self, text="", anchor="center", font=("TkDefaultFont", 10), wraplength=350)
|
||||||
self.description.grid(row=2, column=1, sticky="nsew")
|
self.description.grid(row=4, column=1, sticky="nsew")
|
||||||
|
|
||||||
def set_state(self, state: InstallerState) -> None:
|
def set_state(self, state: InstallerState) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -466,37 +478,15 @@ class ProgressBar(ttk.LabelFrame):
|
||||||
case InstallerState.IDLE: self.grid_remove()
|
case InstallerState.IDLE: self.grid_remove()
|
||||||
case InstallerState.INSTALLING: self.grid()
|
case InstallerState.INSTALLING: self.grid()
|
||||||
|
|
||||||
def set_description(self, desc: str) -> None:
|
def set_title(self, title: str): self.title.config(text=title)
|
||||||
"""
|
def set_max_part(self, maximum: int): self.progress_bar_part.configure(maximum=maximum)
|
||||||
Set the progress bar description
|
def set_part(self, value: int): self.progress_bar_part.configure(value=value)
|
||||||
:param desc: description
|
def part(self, value: int = 1): self.progress_bar_part.step(value)
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
self.description.config(text=desc)
|
|
||||||
|
|
||||||
def set_maximum(self, maximum: int) -> None:
|
def set_description(self, desc: str) -> None: self.description.config(text=desc)
|
||||||
"""
|
def set_max_step(self, maximum: int) -> None: self.progress_bar_step.configure(maximum=maximum)
|
||||||
Set the progress bar maximum value
|
def set_step(self, value: int) -> None: self.progress_bar_step.configure(value=value)
|
||||||
:param maximum: the maximum value
|
def step(self, value: int = 1) -> None: self.progress_bar_step.step(value)
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
self.progress_bar.configure(maximum=maximum)
|
|
||||||
|
|
||||||
def set_value(self, value: int) -> None:
|
|
||||||
"""
|
|
||||||
Set the progress bar value
|
|
||||||
:param value: the value
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
self.progress_bar.configure(value=value)
|
|
||||||
|
|
||||||
def step(self, value: int = 1) -> None:
|
|
||||||
"""
|
|
||||||
Set the progress bar by the value
|
|
||||||
:param value: the step
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
self.progress_bar.step(value)
|
|
||||||
|
|
||||||
def set_determinate(self, value: bool) -> None:
|
def set_determinate(self, value: bool) -> None:
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -5,6 +5,7 @@ from typing import Generator, IO, TYPE_CHECKING
|
||||||
|
|
||||||
from source.mkw.ModConfig import ModConfig
|
from source.mkw.ModConfig import ModConfig
|
||||||
from source.mkw.Patch.Patch import Patch
|
from source.mkw.Patch.Patch import Patch
|
||||||
|
from source.progress import Progress
|
||||||
from source.wt import szs, lec, wit
|
from source.wt import szs, lec, wit
|
||||||
from source.wt.wstrt import StrPath
|
from source.wt.wstrt import StrPath
|
||||||
|
|
||||||
|
@ -27,35 +28,35 @@ class ExtractedGame:
|
||||||
self.original_game = original_game
|
self.original_game = original_game
|
||||||
self._special_file: dict[str, IO] = {}
|
self._special_file: dict[str, IO] = {}
|
||||||
|
|
||||||
def extract_autoadd(self, destination_path: "Path | str") -> Generator[dict, None, None]:
|
def extract_autoadd(self, destination_path: "Path | str") -> Generator[Progress, None, None]:
|
||||||
"""
|
"""
|
||||||
Extract all the autoadd files from the game to destination_path
|
Extract all the autoadd files from the game to destination_path
|
||||||
:param destination_path: directory where the autoadd files will be extracted
|
:param destination_path: directory where the autoadd files will be extracted
|
||||||
"""
|
"""
|
||||||
yield {"description": "Extracting autoadd files...", "determinate": False}
|
yield Progress(description="Extracting autoadd files...", determinate=False)
|
||||||
szs.autoadd(self.path / "files/Race/Course/", destination_path)
|
szs.autoadd(self.path / "files/Race/Course/", destination_path)
|
||||||
|
|
||||||
def extract_original_tracks(self, destination_path: "Path | str") -> Generator[dict, None, None]:
|
def extract_original_tracks(self, destination_path: "Path | str") -> Generator[Progress, None, None]:
|
||||||
"""
|
"""
|
||||||
Move all the original tracks to the destination path
|
Move all the original tracks to the destination path
|
||||||
:param destination_path: destination of the track
|
:param destination_path: destination of the track
|
||||||
"""
|
"""
|
||||||
destination_path = Path(destination_path)
|
destination_path = Path(destination_path)
|
||||||
destination_path.mkdir(parents=True, exist_ok=True)
|
destination_path.mkdir(parents=True, exist_ok=True)
|
||||||
yield {"description": "Extracting original tracks...", "determinate": False}
|
yield Progress(description="Extracting original tracks...", determinate=False)
|
||||||
for track_file in (self.path / "files/Race/Course/").glob("*.szs"):
|
for track_file in (self.path / "files/Race/Course/").glob("*.szs"):
|
||||||
yield {"description": f"Extracting original tracks ({track_file.name})...", "determinate": False}
|
yield Progress(description=f"Extracting original tracks ({track_file.name})...", determinate=False)
|
||||||
if not (destination_path / track_file.name).exists(): track_file.rename(destination_path / track_file.name)
|
if not (destination_path / track_file.name).exists(): track_file.rename(destination_path / track_file.name)
|
||||||
else: track_file.unlink()
|
else: track_file.unlink()
|
||||||
|
|
||||||
def install_mystuff(self, mystuff_path: "Path | str") -> Generator[dict, None, None]:
|
def install_mystuff(self, mystuff_path: "Path | str") -> Generator[Progress, None, None]:
|
||||||
"""
|
"""
|
||||||
Install mystuff directory. If any files of the game have the same name as a file at the root of the MyStuff
|
Install mystuff directory. If any files of the game have the same name as a file at the root of the MyStuff
|
||||||
Patch, then it is copied.
|
Patch, then it is copied.
|
||||||
:mystuff_path: path to the MyStuff directory
|
:mystuff_path: path to the MyStuff directory
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
yield {"description": f"Installing MyStuff '{mystuff_path}'...", "determinate": False}
|
yield Progress(description=f"Installing MyStuff '{mystuff_path}'...", determinate=False)
|
||||||
mystuff_path = Path(mystuff_path)
|
mystuff_path = Path(mystuff_path)
|
||||||
|
|
||||||
mystuff_rootfiles: dict[str, Path] = {}
|
mystuff_rootfiles: dict[str, Path] = {}
|
||||||
|
@ -67,49 +68,49 @@ class ExtractedGame:
|
||||||
if (mystuff_file := mystuff_rootfiles.get(game_file.name)) is None: continue
|
if (mystuff_file := mystuff_rootfiles.get(game_file.name)) is None: continue
|
||||||
shutil.copy(mystuff_file, game_file)
|
shutil.copy(mystuff_file, game_file)
|
||||||
|
|
||||||
def install_multiple_mystuff(self, mystuff_paths: list["Path | str"]) -> Generator[dict, None, None]:
|
def install_multiple_mystuff(self, mystuff_paths: list["Path | str"]) -> Generator[Progress, None, None]:
|
||||||
"""
|
"""
|
||||||
Install multiple mystuff patch
|
Install multiple mystuff patch
|
||||||
:param mystuff_paths: paths to all the mystuff patch
|
:param mystuff_paths: paths to all the mystuff patch
|
||||||
"""
|
"""
|
||||||
yield {"description": "Installing all the mystuff patchs"}
|
yield Progress(description="Installing all the mystuff patchs")
|
||||||
|
|
||||||
for mystuff_path in mystuff_paths:
|
for mystuff_path in mystuff_paths:
|
||||||
yield from self.install_mystuff(mystuff_path)
|
yield from self.install_mystuff(mystuff_path)
|
||||||
|
|
||||||
def prepare_special_file(self, mod_config: ModConfig) -> Generator[dict, None, None]:
|
def prepare_special_file(self, mod_config: ModConfig) -> Generator[Progress, None, None]:
|
||||||
"""
|
"""
|
||||||
Prepare special files for the patch
|
Prepare special files for the patch
|
||||||
:return: the special files dict
|
:return: the special files dict
|
||||||
"""
|
"""
|
||||||
yield {"description": "Preparing ct_icon special file...", "determinate": False}
|
yield Progress(description="Preparing ct_icon special file...", determinate=False)
|
||||||
ct_icons = BytesIO()
|
ct_icons = BytesIO()
|
||||||
mod_config.get_full_cticon().save(ct_icons, format="PNG")
|
mod_config.get_full_cticon().save(ct_icons, format="PNG")
|
||||||
ct_icons.seek(0)
|
ct_icons.seek(0)
|
||||||
self._special_file["ct_icons"] = ct_icons
|
self._special_file["ct_icons"] = ct_icons
|
||||||
|
|
||||||
def prepare_dol(self) -> Generator[dict, None, None]:
|
def prepare_dol(self) -> Generator[Progress, None, None]:
|
||||||
"""
|
"""
|
||||||
Prepare main.dol and StaticR.rel files (clean them and add lecode)
|
Prepare main.dol and StaticR.rel files (clean them and add lecode)
|
||||||
"""
|
"""
|
||||||
yield {"description": "Preparing main.dol...", "determinate": False}
|
yield Progress(description="Preparing main.dol...", determinate=False)
|
||||||
StrPath(self.path / "sys/main.dol").patch(clean_dol=True, add_lecode=True)
|
StrPath(self.path / "sys/main.dol").patch(clean_dol=True, add_lecode=True)
|
||||||
|
|
||||||
def recreate_all_szs(self) -> Generator[dict, None, None]:
|
def recreate_all_szs(self) -> Generator[Progress, None, None]:
|
||||||
"""
|
"""
|
||||||
Repack all the .d directory into .szs files.
|
Repack all the .d directory into .szs files.
|
||||||
"""
|
"""
|
||||||
yield {"description": f"Repacking all szs", "determinate": False}
|
yield Progress(description=f"Repacking all szs", determinate=False)
|
||||||
|
|
||||||
for extracted_szs in filter(lambda path: path.is_dir(), self.path.rglob("*.d")):
|
for extracted_szs in filter(lambda path: path.is_dir(), self.path.rglob("*.d")):
|
||||||
# for every directory that end with a .d in the extracted game, recreate the szs
|
# for every directory that end with a .d in the extracted game, recreate the szs
|
||||||
yield {"description": f"Repacking {extracted_szs} to szs", "determinate": False}
|
yield Progress(description=f"Repacking {extracted_szs} to szs", determinate=False)
|
||||||
|
|
||||||
szs.create(extracted_szs, extracted_szs.with_suffix(".szs"), overwrite=True)
|
szs.create(extracted_szs, extracted_szs.with_suffix(".szs"), overwrite=True)
|
||||||
shutil.rmtree(str(extracted_szs.resolve()))
|
shutil.rmtree(str(extracted_szs.resolve()))
|
||||||
|
|
||||||
def patch_lecode(self, mod_config: ModConfig, cache_directory: Path | str,
|
def patch_lecode(self, mod_config: ModConfig, cache_directory: Path | str,
|
||||||
cttracks_directory: Path | str, ogtracks_directory: Path | str) -> Generator[dict, None, None]:
|
cttracks_directory: Path | str, ogtracks_directory: Path | str) -> Generator[Progress, None, None]:
|
||||||
"""
|
"""
|
||||||
install lecode on the mod
|
install lecode on the mod
|
||||||
:param cttracks_directory: directory to the customs tracks
|
:param cttracks_directory: directory to the customs tracks
|
||||||
|
@ -117,7 +118,7 @@ class ExtractedGame:
|
||||||
:param cache_directory: Path to the cache
|
:param cache_directory: Path to the cache
|
||||||
:param mod_config: mod configuration
|
:param mod_config: mod configuration
|
||||||
"""
|
"""
|
||||||
yield {"description": "Patching LECODE.bin"}
|
yield Progress(description="Patching LECODE.bin")
|
||||||
cache_directory = Path(cache_directory)
|
cache_directory = Path(cache_directory)
|
||||||
cttracks_directory = Path(cttracks_directory)
|
cttracks_directory = Path(cttracks_directory)
|
||||||
ogtracks_directory = Path(ogtracks_directory)
|
ogtracks_directory = Path(ogtracks_directory)
|
||||||
|
@ -139,42 +140,44 @@ class ExtractedGame:
|
||||||
copy_tracks_directories=[ogtracks_directory, cttracks_directory]
|
copy_tracks_directories=[ogtracks_directory, cttracks_directory]
|
||||||
)
|
)
|
||||||
|
|
||||||
def _install_all_patch(self, mod_config: ModConfig, patch_directory_name: str) -> Generator[dict, None, None]:
|
def _install_all_patch(self, mod_config: ModConfig, patch_directory_name: str) -> Generator[Progress, None, None]:
|
||||||
"""
|
"""
|
||||||
for all directory that are in the root of the mod, and don't start with an underscore,
|
for all directory that are in the root of the mod, and don't start with an underscore,
|
||||||
for all the subdirectory named by the patch_directory_name, apply the patch
|
for all the subdirectory named by the patch_directory_name, apply the patch
|
||||||
:param mod_config: the mod to install
|
:param mod_config: the mod to install
|
||||||
"""
|
"""
|
||||||
yield {} # yield an empty dict so that if nothing is yielded by the Patch, still is considered a generator
|
# yield an empty dict so that if nothing is yielded by the Patch, still is considered a generator
|
||||||
|
yield Progress()
|
||||||
|
|
||||||
for part_directory in mod_config.get_mod_directory().glob("[!_]*"):
|
for part_directory in mod_config.get_mod_directory().glob("[!_]*"):
|
||||||
for patch_directory in part_directory.glob(patch_directory_name):
|
for patch_directory in part_directory.glob(patch_directory_name):
|
||||||
yield from Patch(patch_directory, mod_config, self._special_file).install(self)
|
yield from Patch(patch_directory, mod_config, self._special_file).install(self)
|
||||||
|
|
||||||
def install_all_prepatch(self, mod_config: ModConfig) -> Generator[dict, None, None]:
|
def install_all_prepatch(self, mod_config: ModConfig) -> Generator[Progress, None, None]:
|
||||||
"""
|
"""
|
||||||
Install all patchs of the mod_config into the game.
|
Install all patchs of the mod_config into the game.
|
||||||
Used before the lecode patch is applied
|
Used before the lecode patch is applied
|
||||||
:param mod_config: the mod to install
|
:param mod_config: the mod to install
|
||||||
"""
|
"""
|
||||||
yield {"description": "Installing all Pre-Patch...", "determinate": False}
|
yield Progress(description="Installing all Pre-Patch...", determinate=False)
|
||||||
yield from self._install_all_patch(mod_config, "_PREPATCH/")
|
yield from self._install_all_patch(mod_config, "_PREPATCH/")
|
||||||
|
|
||||||
def install_all_patch(self, mod_config: ModConfig) -> Generator[dict, None, None]:
|
def install_all_patch(self, mod_config: ModConfig) -> Generator[Progress, None, None]:
|
||||||
"""
|
"""
|
||||||
Install all patchs of the mod_config into the game.
|
Install all patchs of the mod_config into the game.
|
||||||
Used after the lecode patch is applied
|
Used after the lecode patch is applied
|
||||||
:param mod_config: the mod to install
|
:param mod_config: the mod to install
|
||||||
"""
|
"""
|
||||||
yield {"description": "Installing all Patch...", "determinate": False}
|
yield Progress(description="Installing all Patch...", determinate=False)
|
||||||
yield from self._install_all_patch(mod_config, "_PATCH/")
|
yield from self._install_all_patch(mod_config, "_PATCH/")
|
||||||
|
|
||||||
def convert_to(self, output_type: wit.Extension) -> Generator[dict, None, wit.WITPath | None]:
|
def convert_to(self, output_type: wit.Extension) -> Generator[Progress, None, wit.WITPath | None]:
|
||||||
"""
|
"""
|
||||||
Convert the extracted game to another format
|
Convert the extracted game to another format
|
||||||
:param output_type: path to the destination of the game
|
:param output_type: path to the destination of the game
|
||||||
:output_type: format of the destination game
|
:output_type: format of the destination game
|
||||||
"""
|
"""
|
||||||
yield {"description": f"Converting game to {output_type}", "determinate": False}
|
yield Progress(description=f"Converting game to {output_type}", determinate=False)
|
||||||
if output_type == wit.Extension.FST: return
|
if output_type == wit.Extension.FST: return
|
||||||
|
|
||||||
destination_file = self.path.with_suffix(self.path.suffix + output_type.value)
|
destination_file = self.path.with_suffix(self.path.suffix + output_type.value)
|
||||||
|
@ -190,7 +193,7 @@ class ExtractedGame:
|
||||||
destination_file=destination_file,
|
destination_file=destination_file,
|
||||||
)
|
)
|
||||||
|
|
||||||
yield {"description": "Deleting the extracted game...", "determinate": False}
|
yield Progress(description="Deleting the extracted game...", determinate=False)
|
||||||
shutil.rmtree(self.path)
|
shutil.rmtree(self.path)
|
||||||
|
|
||||||
return converted_game
|
return converted_game
|
||||||
|
|
|
@ -4,6 +4,7 @@ from typing import Generator
|
||||||
from source.mkw.ExtractedGame import ExtractedGame
|
from source.mkw.ExtractedGame import ExtractedGame
|
||||||
from source.mkw.ModConfig import ModConfig
|
from source.mkw.ModConfig import ModConfig
|
||||||
from source.option import Option
|
from source.option import Option
|
||||||
|
from source.progress import Progress
|
||||||
from source.wt.wit import WITPath, Region, Extension
|
from source.wt.wit import WITPath, Region, Extension
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,7 +38,7 @@ class Game:
|
||||||
"""
|
"""
|
||||||
return not any(self.wit_path[f"./files/rel/lecode-{region.value}.bin"].exists() for region in Region)
|
return not any(self.wit_path[f"./files/rel/lecode-{region.value}.bin"].exists() for region in Region)
|
||||||
|
|
||||||
def extract(self, dest: "Path | str") -> Generator[dict, None, Path]:
|
def extract(self, dest: "Path | str") -> Generator[Progress, None, Path]:
|
||||||
"""
|
"""
|
||||||
Extract the game to the destination directory. If the game is a FST, just copy to the destination
|
Extract the game to the destination directory. If the game is a FST, just copy to the destination
|
||||||
:param dest: destination directory
|
:param dest: destination directory
|
||||||
|
@ -45,30 +46,25 @@ class Game:
|
||||||
gen = self.wit_path.progress_extract_all(dest)
|
gen = self.wit_path.progress_extract_all(dest)
|
||||||
|
|
||||||
if self.wit_path.extension == Extension.FST:
|
if self.wit_path.extension == Extension.FST:
|
||||||
for gen_data in gen:
|
for _ in gen: yield Progress(description="Copying Game...", determinate=False)
|
||||||
yield {
|
|
||||||
"description": "Copying Game...",
|
|
||||||
"determinate": False
|
|
||||||
}
|
|
||||||
try: next(gen)
|
try: next(gen)
|
||||||
except StopIteration as e:
|
except StopIteration as e: return e.value
|
||||||
return e.value
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
for gen_data in gen:
|
for gen_data in gen:
|
||||||
yield {
|
yield Progress(
|
||||||
"description": f'Extracting - {gen_data["percentage"]}% - (estimated time remaining: '
|
description=f'Extracting - {gen_data["percentage"]}% - (estimated time remaining: '
|
||||||
f'{gen_data["estimation"] if gen_data["estimation"] is not None else "-:--"})',
|
f'{gen_data["estimation"] if gen_data["estimation"] is not None else "-:--"})',
|
||||||
"maximum": 100,
|
max_step=100,
|
||||||
"value": gen_data["percentage"],
|
set_step=gen_data["percentage"],
|
||||||
"determinate": True
|
determinate=True
|
||||||
}
|
)
|
||||||
try: next(gen)
|
try: next(gen)
|
||||||
except StopIteration as e:
|
except StopIteration as e:
|
||||||
return e.value
|
return e.value
|
||||||
|
|
||||||
def edit(self, mod_config: ModConfig) -> Generator[dict, None, None]:
|
def edit(self, mod_config: ModConfig) -> Generator[Progress, None, None]:
|
||||||
yield {"description": "Changing game metadata...", "determinate": False}
|
yield Progress(description="Changing game metadata...", determinate=False)
|
||||||
self.wit_path.edit(
|
self.wit_path.edit(
|
||||||
name=mod_config.name,
|
name=mod_config.name,
|
||||||
game_id=self.wit_path.id[:4] + mod_config.variant
|
game_id=self.wit_path.id[:4] + mod_config.variant
|
||||||
|
@ -96,7 +92,7 @@ class Game:
|
||||||
return extracted_game
|
return extracted_game
|
||||||
|
|
||||||
def install_mod(self, dest: Path, mod_config: ModConfig, options: "Option", output_type: Extension
|
def install_mod(self, dest: Path, mod_config: ModConfig, options: "Option", output_type: Extension
|
||||||
) -> Generator[dict, None, None]:
|
) -> Generator[Progress, None, None]:
|
||||||
"""
|
"""
|
||||||
Patch the game with the mod
|
Patch the game with the mod
|
||||||
:dest: destination directory
|
:dest: destination directory
|
||||||
|
|
|
@ -13,6 +13,7 @@ from source.mkw.Track import CustomTrack, DefaultTrack, Arena
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from source.mkw.OriginalTrack import OriginalTrack
|
from source.mkw.OriginalTrack import OriginalTrack
|
||||||
|
from source.progress import Progress
|
||||||
from source.safe_eval import safe_eval, multiple_safe_eval
|
from source.safe_eval import safe_eval, multiple_safe_eval
|
||||||
from source.wt.szs import SZSPath
|
from source.wt.szs import SZSPath
|
||||||
|
|
||||||
|
@ -404,7 +405,8 @@ class ModConfig:
|
||||||
return full_cticon
|
return full_cticon
|
||||||
|
|
||||||
def normalize_all_tracks(self, autoadd_path: "Path | str", destination_path: "Path | str",
|
def normalize_all_tracks(self, autoadd_path: "Path | str", destination_path: "Path | str",
|
||||||
original_tracks_path: "Path | str", thread_amount: int = 8) -> Generator[dict, None, None]:
|
original_tracks_path: "Path | str",
|
||||||
|
thread_amount: int = 8) -> Generator[Progress, None, None]:
|
||||||
"""
|
"""
|
||||||
Convert all tracks of the mod to szs into the destination_path
|
Convert all tracks of the mod to szs into the destination_path
|
||||||
:param original_tracks_path: path to the originals tracks (if a track is disabled for multiplayer)
|
:param original_tracks_path: path to the originals tracks (if a track is disabled for multiplayer)
|
||||||
|
@ -412,21 +414,23 @@ class ModConfig:
|
||||||
:param autoadd_path: autoadd directory
|
:param autoadd_path: autoadd directory
|
||||||
:param destination_path: destination where the files are converted
|
:param destination_path: destination where the files are converted
|
||||||
"""
|
"""
|
||||||
yield {"description": "Normalizing track..."}
|
yield Progress(description="Normalizing track...")
|
||||||
destination_path = Path(destination_path)
|
destination_path = Path(destination_path)
|
||||||
original_tracks_path = Path(original_tracks_path)
|
original_tracks_path = Path(original_tracks_path)
|
||||||
destination_path.mkdir(parents=True, exist_ok=True)
|
destination_path.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
normalize_threads: list[dict] = []
|
normalize_threads: list[dict] = []
|
||||||
|
|
||||||
def remove_finished_threads() -> Generator[dict, None, None]:
|
def remove_finished_threads() -> Generator[Progress, None, None]:
|
||||||
"""
|
"""
|
||||||
Remove all the thread that stopped in a thread list
|
Remove all the thread that stopped in a thread list
|
||||||
:return: the list without the stopped thread
|
:return: the list without the stopped thread
|
||||||
"""
|
"""
|
||||||
nonlocal normalize_threads
|
nonlocal normalize_threads
|
||||||
|
|
||||||
yield {"description": f"Normalizing tracks :\n" + "\n".join(thread['name'] for thread in normalize_threads)}
|
yield Progress(
|
||||||
|
description=f"Normalizing tracks :\n" + "\n".join(thread['name'] for thread in normalize_threads)
|
||||||
|
)
|
||||||
normalize_threads = list(filter(lambda thread: thread["thread"].is_alive(), normalize_threads))
|
normalize_threads = list(filter(lambda thread: thread["thread"].is_alive(), normalize_threads))
|
||||||
|
|
||||||
track_directory = self.path.parent / "_TRACKS"
|
track_directory = self.path.parent / "_TRACKS"
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Generator, IO, TYPE_CHECKING
|
from typing import Generator, IO, TYPE_CHECKING
|
||||||
|
|
||||||
|
from source.progress import Progress
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from source.mkw.ModConfig import ModConfig
|
from source.mkw.ModConfig import ModConfig
|
||||||
from source.mkw.ExtractedGame import ExtractedGame
|
from source.mkw.ExtractedGame import ExtractedGame
|
||||||
|
@ -19,13 +21,13 @@ class Patch:
|
||||||
def __repr__(self) -> str:
|
def __repr__(self) -> str:
|
||||||
return f"<{self.__class__.__name__} {self.path}>"
|
return f"<{self.__class__.__name__} {self.path}>"
|
||||||
|
|
||||||
def install(self, extracted_game: "ExtractedGame") -> Generator[dict, None, None]:
|
def install(self, extracted_game: "ExtractedGame") -> Generator[Progress, None, None]:
|
||||||
"""
|
"""
|
||||||
patch a game with this Patch
|
patch a game with this Patch
|
||||||
:param extracted_game: the extracted game
|
:param extracted_game: the extracted game
|
||||||
"""
|
"""
|
||||||
from source.mkw.Patch.PatchDirectory import PatchDirectory
|
from source.mkw.Patch.PatchDirectory import PatchDirectory
|
||||||
yield {"description": f"Installing the patch", "determinate": False}
|
yield Progress(description=f"Installing the patch", determinate=False)
|
||||||
|
|
||||||
# take all the files in the root directory, and patch them into the game.
|
# take all the files in the root directory, and patch them into the game.
|
||||||
# Patch is not directly applied to the root to avoid custom configuration
|
# Patch is not directly applied to the root to avoid custom configuration
|
||||||
|
|
|
@ -3,6 +3,7 @@ from typing import Generator, TYPE_CHECKING
|
||||||
|
|
||||||
from source.mkw.Patch import PathOutsidePatch, InvalidPatchMode
|
from source.mkw.Patch import PathOutsidePatch, InvalidPatchMode
|
||||||
from source.mkw.Patch.PatchObject import PatchObject
|
from source.mkw.Patch.PatchObject import PatchObject
|
||||||
|
from source.progress import Progress
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from source.mkw.ExtractedGame import ExtractedGame
|
from source.mkw.ExtractedGame import ExtractedGame
|
||||||
|
@ -22,11 +23,11 @@ class PatchDirectory(PatchObject):
|
||||||
if subpath.suffix == ".json": continue
|
if subpath.suffix == ".json": continue
|
||||||
yield self.subfile_from_path(subpath)
|
yield self.subfile_from_path(subpath)
|
||||||
|
|
||||||
def install(self, extracted_game: "ExtractedGame", game_subpath: Path) -> Generator[dict, None, None]:
|
def install(self, extracted_game: "ExtractedGame", game_subpath: Path) -> Generator[Progress, None, None]:
|
||||||
"""
|
"""
|
||||||
patch a subdirectory of the game with the PatchDirectory
|
patch a subdirectory of the game with the PatchDirectory
|
||||||
"""
|
"""
|
||||||
yield {"description": f"Patching {game_subpath}"}
|
yield Progress(description=f"Patching {game_subpath}")
|
||||||
|
|
||||||
# check if the directory should be patched
|
# check if the directory should be patched
|
||||||
if not self.is_enabled(extracted_game): return
|
if not self.is_enabled(extracted_game): return
|
||||||
|
|
|
@ -5,6 +5,7 @@ from typing import Generator, IO, TYPE_CHECKING
|
||||||
from source.mkw.Patch import PathOutsidePatch, InvalidPatchMode, InvalidSourceMode
|
from source.mkw.Patch import PathOutsidePatch, InvalidPatchMode, InvalidSourceMode
|
||||||
from source.mkw.Patch.PatchOperation import AbstractPatchOperation
|
from source.mkw.Patch.PatchOperation import AbstractPatchOperation
|
||||||
from source.mkw.Patch.PatchObject import PatchObject
|
from source.mkw.Patch.PatchObject import PatchObject
|
||||||
|
from source.progress import Progress
|
||||||
from source.wt.szs import SZSPath
|
from source.wt.szs import SZSPath
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
@ -76,11 +77,11 @@ class PatchFile(PatchObject):
|
||||||
if not szs_path.exists() and szs_path.with_suffix(".szs").exists():
|
if not szs_path.exists() and szs_path.with_suffix(".szs").exists():
|
||||||
SZSPath(szs_path.with_suffix(".szs")).extract_all(szs_path)
|
SZSPath(szs_path.with_suffix(".szs")).extract_all(szs_path)
|
||||||
|
|
||||||
def install(self, extracted_game: "ExtractedGame", game_subpath: Path) -> Generator[dict, None, None]:
|
def install(self, extracted_game: "ExtractedGame", game_subpath: Path) -> Generator[Progress, None, None]:
|
||||||
"""
|
"""
|
||||||
patch a subfile of the game with the PatchFile
|
patch a subfile of the game with the PatchFile
|
||||||
"""
|
"""
|
||||||
yield {"description": f"Patching {game_subpath}"}
|
yield Progress(description=f"Patching {game_subpath}")
|
||||||
|
|
||||||
# check if the file should be patched
|
# check if the file should be patched
|
||||||
if not self.is_enabled(extracted_game): return
|
if not self.is_enabled(extracted_game): return
|
||||||
|
@ -118,7 +119,7 @@ class PatchFile(PatchObject):
|
||||||
if not game_subfile.relative_to(extracted_game.path):
|
if not game_subfile.relative_to(extracted_game.path):
|
||||||
raise PathOutsidePatch(game_subfile, extracted_game.path)
|
raise PathOutsidePatch(game_subfile, extracted_game.path)
|
||||||
|
|
||||||
yield {"description": f"Patching {game_subfile}"}
|
yield Progress(description=f"Patching {game_subfile}")
|
||||||
|
|
||||||
# if the source is the game, then recalculate the content for every game subfile
|
# if the source is the game, then recalculate the content for every game subfile
|
||||||
if self.configuration["source"] == "game":
|
if self.configuration["source"] == "game":
|
||||||
|
|
|
@ -3,6 +3,8 @@ from abc import abstractmethod, ABC
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Generator, TYPE_CHECKING
|
from typing import Generator, TYPE_CHECKING
|
||||||
|
|
||||||
|
from source.progress import Progress
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from source.mkw.Patch import Patch
|
from source.mkw.Patch import Patch
|
||||||
from source.mkw.ExtractedGame import ExtractedGame
|
from source.mkw.ExtractedGame import ExtractedGame
|
||||||
|
@ -64,7 +66,7 @@ class PatchObject(ABC):
|
||||||
return obj(self.patch, str(path.relative_to(self.patch.path)))
|
return obj(self.patch, str(path.relative_to(self.patch.path)))
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def install(self, extracted_game: "ExtractedGame", game_subpath: Path) -> Generator[dict, None, None]:
|
def install(self, extracted_game: "ExtractedGame", game_subpath: Path) -> Generator[Progress, None, None]:
|
||||||
"""
|
"""
|
||||||
install the PatchObject into the game
|
install the PatchObject into the game
|
||||||
yield the step of the process
|
yield the step of the process
|
||||||
|
|
21
source/progress.py
Normal file
21
source/progress.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
from dataclasses import dataclass
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Progress:
|
||||||
|
"""
|
||||||
|
Represent the level of progression of the installer. Used for progress bar.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# this represents the first progress bar, showing every big part in the process
|
||||||
|
title: str = None
|
||||||
|
part: int = None
|
||||||
|
set_part: int = None
|
||||||
|
max_part: int = None
|
||||||
|
|
||||||
|
# this represents the second progress bar, showing every step of the current part of the process
|
||||||
|
description: str = None
|
||||||
|
step: int = None
|
||||||
|
set_step: int = None
|
||||||
|
max_step: int = None
|
||||||
|
determinate: bool = None
|
|
@ -148,9 +148,7 @@ class WITPath:
|
||||||
:return: the extracted file path
|
:return: the extracted file path
|
||||||
"""
|
"""
|
||||||
if self.extension == Extension.FST:
|
if self.extension == Extension.FST:
|
||||||
yield {
|
yield {}
|
||||||
"determinate": False
|
|
||||||
}
|
|
||||||
shutil.copytree(self._get_fst_root(), dest)
|
shutil.copytree(self._get_fst_root(), dest)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
|
Loading…
Reference in a new issue