Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 30 additions & 55 deletions games/game_cyberpunk2077.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,6 @@ class CyberpunkModDataChecker(BasicModDataChecker):
def __init__(self):
super().__init__(
GlobPatterns(
delete=[
"*.gif",
"*.jpg",
"*.jpeg",
"*.jxl",
"*.md",
"*.png",
"*.txt",
"*.webp",
],
move={
# archive and ArchiveXL
"*.archive": "archive/pc/mod/",
Expand Down Expand Up @@ -200,7 +190,7 @@ def active_mod_paths(self, reverse: bool = False) -> Iterable[Path]:
class Cyberpunk2077Game(BasicGame):
Name = "Cyberpunk 2077 Support Plugin"
Author = "6788, Zash"
Version = "3.0.1"
Version = "3.0.0"

GameName = "Cyberpunk 2077"
GameShortName = "cyberpunk2077"
Expand Down Expand Up @@ -233,7 +223,7 @@ class Cyberpunk2077Game(BasicGame):

def init(self, organizer: mobase.IOrganizer) -> bool:
super().init(organizer)
self._register_feature(BasicLocalSavegames(self))
self._register_feature(BasicLocalSavegames(self.savesDirectory()))
self._register_feature(
BasicGameSaveGameInfo(
lambda p: Path(p or "", "screenshot.png"),
Expand All @@ -256,7 +246,6 @@ def init(self, organizer: mobase.IOrganizer) -> bool:
),
)
organizer.onAboutToRun(self._onAboutToRun)
organizer.onFinishedRun(self._onFinishedRun)
organizer.onPluginSettingChanged(self._on_settings_changed)
organizer.modList().onModInstalled(self._check_disable_crashreporter)
organizer.onUserInterfaceInitialized(self._on_user_interface_initialized)
Expand Down Expand Up @@ -429,11 +418,6 @@ def settings(self) -> list[mobase.PluginSetting]:
),
True,
),
mobase.PluginSetting(
"crash_message",
("Show a crash message as replacement of disabled CrashReporter"),
True,
),
mobase.PluginSetting(
"show_rootbuilder_conversion",
(
Expand All @@ -455,22 +439,22 @@ def executables(self) -> list[mobase.ExecutableInfo]:
game_dir = self.gameDirectory()
bin_path = game_dir.absoluteFilePath(self.binaryName())
skip_start_screen = (
"-skipStartScreen" if self._get_setting("skipStartScreen") else ""
" -skipStartScreen" if self._get_setting("skipStartScreen") else ""
)
return [
# Default, runs REDmod deploy if necessary
mobase.ExecutableInfo(
f"{game_name} (REDmod)",
f"{game_name}",
bin_path,
).withArgument(f"--launcher-skip -modded {skip_start_screen}"),
).withArgument(f"--launcher-skip -modded{skip_start_screen}"),
# Start game without REDmod
mobase.ExecutableInfo(
f"{game_name}",
f"{game_name} - skip REDmod deploy",
bin_path,
).withArgument(f"--launcher-skip {skip_start_screen}"),
# Deploy REDmods only
mobase.ExecutableInfo(
"REDmod",
"Manually deploy REDmod",
self._get_redmod_binary(),
).withArgument("deploy -reportProgress -force %modlist%"),
# Launcher
Expand Down Expand Up @@ -527,35 +511,6 @@ def _onAboutToRun(self, app_path_str: str, wd: QDir, args: str) -> bool:
self._modlist_files.update_modlist("archive")
return True

def _onFinishedRun(self, path: str, exit_code: int) -> None:
if not self._get_setting("crash_message"):
return
if path.endswith(self.binaryName()) and exit_code > 0:
crash_message = QMessageBox(
QMessageBox.Icon.Critical,
"Cyberpunk Crashed",
textwrap.dedent(
f"""
Cyberpunk crashed. Tips:
- disable mods (create backup of modlist or use new profile)
- clear overwrite or delete at least overwrite/r6/cache (to keep mod settings)
- check log files of CET/redscript/RED4ext (in overwrite)
- read [FAQ & Troubleshooting]({self.GameSupportURL}#faq--troubleshooting)
"""
),
QMessageBox.StandardButton.Ok,
self._parentWidget,
)
crash_message.setTextFormat(Qt.TextFormat.MarkdownText)
hide_cb = QCheckBox("&Do not show again*", crash_message)
hide_cb.setToolTip(f"Settings/Plugins/{self.name()}/crash_message")
crash_message.setCheckBox(hide_cb)
crash_message.open( # type: ignore
lambda: (
hide_cb.isChecked() and self._set_setting("crash_message", False)
)
)

def _check_redmod_result(self, result: tuple[bool, int]) -> bool:
if result == (True, 0):
return True
Expand Down Expand Up @@ -649,21 +604,41 @@ def _is_cache_file_updated(self, file: Path, data_path: Path) -> bool:
Args:
file: Relative to data dir.
"""

game_file = data_path.absolute() / file

mapped_files = self._organizer.findFiles(file.parent, file.name)

# guard against missing mapped files early to avoid index/access issues
if not mapped_files:
return False

mapped_file = Path(mapped_files[0])

# ensure both paths exist before any filesystem comparisons
# (prevents pathlib.samefile / filecmp from raising FileNotFoundError)
if not game_file.exists() or not mapped_file.exists():
return False

return bool(
mapped_files
and (mapped_file := mapped_files[0])
mapped_file
and not (
# samefile is only safe after existence checks
game_file.samefile(mapped_file)
# file comparison only executed when both files exist
or filecmp.cmp(game_file, mapped_file)
or ( # different backup file
(
backup_files := self._organizer.findFiles(
file.parent, f"{file.name}.bk"
)
)
and filecmp.cmp(game_file, backup_files[0])
and (
# validate backup exists before comparison
Path(backup_files[0]).exists()
and game_file.exists()
and filecmp.cmp(game_file, backup_files[0])
)
)
)
)
Expand Down
Loading