Compare commits
3 Commits
80f1ea87d7
...
ca03718bf1
Author | SHA1 | Date | |
---|---|---|---|
ca03718bf1 | |||
9f9a63c9b0 | |||
4c851b999a |
@ -10,6 +10,7 @@ class GameABC(ABC):
|
||||
"""
|
||||
|
||||
path: Path
|
||||
cache: Path
|
||||
version_override: tuple[int, int, int] | None
|
||||
channel_override: Any
|
||||
|
||||
@ -83,12 +84,6 @@ class GameABC(ABC):
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_voiceover_update(self, language: str):
|
||||
"""
|
||||
Get the voiceover update
|
||||
"""
|
||||
pass
|
||||
|
||||
def get_channel(self):
|
||||
"""
|
||||
Get the game channel
|
||||
|
@ -25,7 +25,7 @@ default_options = [
|
||||
option("patch-type", "p", description="Patch type", flag=False),
|
||||
option("temporary-path", "t", description="Temporary path", flag=False),
|
||||
option("silent", "s", description="Silent mode"),
|
||||
option("noconfirm", "y", description="Do not ask for confirmation"),
|
||||
option("noconfirm", "y", description="Do not ask for confirmation (yes to all)"),
|
||||
]
|
||||
|
||||
|
||||
@ -62,6 +62,16 @@ def callback(
|
||||
utils.silent_message = silent
|
||||
if noconfirm:
|
||||
utils.no_confirm = noconfirm
|
||||
|
||||
def confirm(
|
||||
question: str, default: bool = False, true_answer_regex: str = r"(?i)^y"
|
||||
):
|
||||
command.line(
|
||||
f"<question>{question} (yes/no)</question> [<comment>{'yes' if default else 'no'}</comment>] y"
|
||||
)
|
||||
return True
|
||||
|
||||
command.confirm = confirm
|
||||
command.add_style("warn", fg="yellow")
|
||||
|
||||
|
||||
@ -116,8 +126,13 @@ class PatchInstallCommand(Command):
|
||||
self.line(
|
||||
"You need to <warn>run the game using Jadeite</warn> to use the patch."
|
||||
)
|
||||
self.line(f'E.g: <question>{exe_path} "{State.game.path}"</question>')
|
||||
print()
|
||||
self.line(
|
||||
f'E.g: <question>I_WANT_A_BAN=1 {exe_path} "{State.game.path}"</question>'
|
||||
"To activate the experimental patching method, set the environment variable BREAK_CATHACK=1"
|
||||
)
|
||||
self.line(
|
||||
"Read more about it here: https://codeberg.org/mkrsym1/jadeite/issues/37"
|
||||
)
|
||||
print()
|
||||
self.line(
|
||||
@ -302,7 +317,7 @@ class UpdateCommand(Command):
|
||||
self.line("<error>Update aborted.</error>")
|
||||
return
|
||||
self.line("Downloading update package...")
|
||||
out_path = State.game._cache.joinpath(update_diff.name)
|
||||
out_path = State.game.cache.joinpath(update_diff.name)
|
||||
try:
|
||||
download_result = utils.download(
|
||||
update_diff.path, out_path, file_len=update_diff.size
|
||||
@ -324,7 +339,40 @@ class UpdateCommand(Command):
|
||||
f"<error>Couldn't apply update: {e} ({e.__context__})</error>"
|
||||
)
|
||||
return
|
||||
progress.finish("<comment>Update applied.</comment>")
|
||||
progress.finish("<comment>Update applied for base game.</comment>")
|
||||
# Get installed voicepacks
|
||||
installed_voicepacks = State.game.get_installed_voicepacks()
|
||||
# Voicepack update
|
||||
for remote_voicepack in update_diff.voice_packs:
|
||||
if remote_voicepack.language not in installed_voicepacks:
|
||||
continue
|
||||
# Voicepack is installed, update it
|
||||
archive_file = State.game.cache.joinpath(remote_voicepack.name)
|
||||
try:
|
||||
download_result = utils.download(
|
||||
update_diff.path, archive_file, file_len=update_diff.size
|
||||
)
|
||||
except Exception as e:
|
||||
self.line_error(f"<error>Couldn't download update: {e}</error>")
|
||||
return
|
||||
if not download_result:
|
||||
self.line_error("<error>Download failed.</error>")
|
||||
return
|
||||
self.line("Download completed.")
|
||||
progress = utils.ProgressIndicator(self)
|
||||
progress.start("Applying update package...")
|
||||
try:
|
||||
State.game.apply_update_archive(
|
||||
archive_file=archive_file, auto_repair=auto_repair
|
||||
)
|
||||
except Exception as e:
|
||||
progress.finish(
|
||||
f"<error>Couldn't apply update: {e} ({e.__context__})</error>"
|
||||
)
|
||||
return
|
||||
progress.finish(
|
||||
f"<comment>Update applied for language {remote_voicepack.language}.</comment>"
|
||||
)
|
||||
self.line("Setting version config... ")
|
||||
self.set_version_config()
|
||||
self.line(
|
||||
|
@ -47,6 +47,7 @@ class ProgressIndicator:
|
||||
interval=interval, values=values
|
||||
)
|
||||
self.thread = Thread(target=self.auto_advance)
|
||||
self.thread.daemon = True
|
||||
|
||||
def start(self, message: str):
|
||||
"""
|
||||
|
@ -67,7 +67,7 @@ def apply_update_archive(
|
||||
|
||||
# Patch function
|
||||
def extract_and_patch(file, patch_file):
|
||||
patchpath = game._cache.joinpath(patch_file)
|
||||
patchpath = game.cache.joinpath(patch_file)
|
||||
# Delete old patch file if exists
|
||||
patchpath.unlink(missing_ok=True)
|
||||
# Extract patch file
|
||||
|
@ -1,3 +1,4 @@
|
||||
from configparser import ConfigParser
|
||||
from hashlib import md5
|
||||
from io import IOBase
|
||||
from os import PathLike
|
||||
@ -5,6 +6,7 @@ from pathlib import Path
|
||||
from vollerei.abc.launcher.game import GameABC
|
||||
from vollerei.common import ConfigFile, functions
|
||||
from vollerei.common.api import resource
|
||||
from vollerei.common.enums import VoicePackLanguage
|
||||
from vollerei.exceptions.game import (
|
||||
GameAlreadyUpdatedError,
|
||||
GameNotInstalledError,
|
||||
@ -32,8 +34,8 @@ class Game(GameABC):
|
||||
if not cache_path:
|
||||
cache_path = paths.cache_path
|
||||
cache_path = Path(cache_path)
|
||||
self._cache: Path = cache_path.joinpath("game/hsr/")
|
||||
self._cache.mkdir(parents=True, exist_ok=True)
|
||||
self.cache: Path = cache_path.joinpath("game/hsr/")
|
||||
self.cache.mkdir(parents=True, exist_ok=True)
|
||||
self._version_override: tuple[int, int, int] | None = None
|
||||
self._channel_override: GameChannel | None = None
|
||||
|
||||
@ -111,6 +113,42 @@ class Game(GameABC):
|
||||
return False
|
||||
return True
|
||||
|
||||
def get_channel(self) -> GameChannel:
|
||||
"""
|
||||
Gets the current game channel.
|
||||
|
||||
Only works for Star Rail version 1.0.5, other versions will return the
|
||||
overridden channel or GameChannel.Overseas if no channel is overridden.
|
||||
|
||||
This is not needed for game patching, since the patcher will automatically
|
||||
detect the channel.
|
||||
|
||||
Returns:
|
||||
GameChannel: The current game channel.
|
||||
"""
|
||||
version = self._version_override or self.get_version()
|
||||
if version == (1, 0, 5):
|
||||
for channel, v in MD5SUMS["1.0.5"].values():
|
||||
for file, md5sum in v.values():
|
||||
if (
|
||||
md5(self._path.joinpath(file).read_bytes()).hexdigest()
|
||||
!= md5sum
|
||||
):
|
||||
continue
|
||||
match channel:
|
||||
case "cn":
|
||||
return GameChannel.China
|
||||
case "os":
|
||||
return GameChannel.Overseas
|
||||
else:
|
||||
# if self._path.joinpath("StarRail_Data").is_dir():
|
||||
# return GameChannel.Overseas
|
||||
# elif self._path.joinpath("StarRail_Data").exists():
|
||||
# return GameChannel.China
|
||||
# No reliable method there, so we'll just return the overridden channel or
|
||||
# fallback to overseas.
|
||||
return self._channel_override or GameChannel.Overseas
|
||||
|
||||
def get_version_config(self) -> tuple[int, int, int]:
|
||||
"""
|
||||
Gets the current installed game version from config.ini.
|
||||
@ -147,11 +185,24 @@ class Game(GameABC):
|
||||
This method is meant to keep compatibility with the official launcher only.
|
||||
"""
|
||||
cfg_file = self._path.joinpath("config.ini")
|
||||
if not cfg_file.exists():
|
||||
raise FileNotFoundError("config.ini not found.")
|
||||
cfg = ConfigFile(cfg_file)
|
||||
cfg.set("General", "game_version", self.get_version_str())
|
||||
cfg.save()
|
||||
if cfg_file.exists():
|
||||
cfg = ConfigFile(cfg_file)
|
||||
cfg.set("General", "game_version", self.get_version_str())
|
||||
cfg.save()
|
||||
else:
|
||||
cfg = ConfigParser()
|
||||
cfg.read_dict(
|
||||
{
|
||||
"General": {
|
||||
"channel": 1,
|
||||
"cps": "hoyoverse_PC",
|
||||
"game_version": self.get_version_str(),
|
||||
"sub_channel": 1,
|
||||
"plugin_2_version": "0.0.1",
|
||||
}
|
||||
}
|
||||
)
|
||||
cfg.write(cfg_file.open("w"))
|
||||
|
||||
def get_version(self) -> tuple[int, int, int]:
|
||||
"""
|
||||
@ -232,41 +283,27 @@ class Game(GameABC):
|
||||
"""
|
||||
return ".".join(str(i) for i in self.get_version())
|
||||
|
||||
def get_channel(self) -> GameChannel:
|
||||
def get_installed_voicepacks(self) -> list[VoicePackLanguage]:
|
||||
"""
|
||||
Gets the current game channel.
|
||||
|
||||
Only works for Star Rail version 1.0.5, other versions will return the
|
||||
overridden channel or GameChannel.Overseas if no channel is overridden.
|
||||
|
||||
This is not needed for game patching, since the patcher will automatically
|
||||
detect the channel.
|
||||
Gets the installed voicepacks.
|
||||
|
||||
Returns:
|
||||
GameChannel: The current game channel.
|
||||
list[VoicePackLanguage]: A list of installed voicepacks.
|
||||
"""
|
||||
version = self._version_override or self.get_version()
|
||||
if version == (1, 0, 5):
|
||||
for channel, v in MD5SUMS["1.0.5"].values():
|
||||
for file, md5sum in v.values():
|
||||
if (
|
||||
md5(self._path.joinpath(file).read_bytes()).hexdigest()
|
||||
!= md5sum
|
||||
):
|
||||
continue
|
||||
match channel:
|
||||
case "cn":
|
||||
return GameChannel.China
|
||||
case "os":
|
||||
return GameChannel.Overseas
|
||||
else:
|
||||
# if self._path.joinpath("StarRail_Data").is_dir():
|
||||
# return GameChannel.Overseas
|
||||
# elif self._path.joinpath("StarRail_Data").exists():
|
||||
# return GameChannel.China
|
||||
# No reliable method there, so we'll just return the overridden channel or
|
||||
# fallback to overseas.
|
||||
return self._channel_override or GameChannel.Overseas
|
||||
if not self.is_installed():
|
||||
raise GameNotInstalledError("Game is not installed.")
|
||||
voicepacks = []
|
||||
for child in (
|
||||
self.data_folder()
|
||||
.joinpath("Persistent/Audio/AudioPackage/Windows/")
|
||||
.iterdir()
|
||||
):
|
||||
if child.is_dir():
|
||||
try:
|
||||
voicepacks.append(VoicePackLanguage(child.name))
|
||||
except ValueError:
|
||||
pass
|
||||
return voicepacks
|
||||
|
||||
def get_remote_game(self, pre_download: bool = False) -> resource.Game:
|
||||
"""
|
||||
@ -393,7 +430,20 @@ class Game(GameABC):
|
||||
update_info = self.get_update()
|
||||
if not update_info or update_info.version == self.get_version_str():
|
||||
raise GameAlreadyUpdatedError("Game is already updated.")
|
||||
archive_file = self._cache.joinpath(update_info.name)
|
||||
# Base game update
|
||||
archive_file = self.cache.joinpath(update_info.name)
|
||||
download(update_info.path, archive_file)
|
||||
self.apply_update_archive(archive_file=archive_file, auto_repair=auto_repair)
|
||||
# Get installed voicepacks
|
||||
installed_voicepacks = self.get_installed_voicepacks()
|
||||
# Voicepack update
|
||||
for remote_voicepack in update_info.voice_packs:
|
||||
if remote_voicepack.language not in installed_voicepacks:
|
||||
continue
|
||||
# Voicepack is installed, update it
|
||||
archive_file = self.cache.joinpath(remote_voicepack.name)
|
||||
download(remote_voicepack.path, archive_file)
|
||||
self.apply_update_archive(
|
||||
archive_file=archive_file, auto_repair=auto_repair
|
||||
)
|
||||
self.set_version_config()
|
||||
|
Loading…
Reference in New Issue
Block a user