Skip to content

Commit 2431e1f

Browse files
committed
cyberpunk fix cache crash
1 parent e293a98 commit 2431e1f

1 file changed

Lines changed: 35 additions & 60 deletions

File tree

games/game_cyberpunk2077.py

Lines changed: 35 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from pathlib import Path
1111
from typing import Any, Literal, TypeVar
1212

13+
import mobase
1314
from PyQt6.QtCore import QDateTime, QDir, Qt, qCritical, qInfo, qWarning
1415
from PyQt6.QtWidgets import (
1516
QCheckBox,
@@ -19,8 +20,6 @@
1920
QWidget,
2021
)
2122

22-
import mobase
23-
2423
from ..basic_features import BasicLocalSavegames, BasicModDataChecker, GlobPatterns
2524
from ..basic_features.basic_save_game_info import (
2625
BasicGameSaveGame,
@@ -34,16 +33,6 @@ class CyberpunkModDataChecker(BasicModDataChecker):
3433
def __init__(self):
3534
super().__init__(
3635
GlobPatterns(
37-
delete=[
38-
"*.gif",
39-
"*.jpg",
40-
"*.jpeg",
41-
"*.jxl",
42-
"*.md",
43-
"*.png",
44-
"*.txt",
45-
"*.webp",
46-
],
4736
move={
4837
# archive and ArchiveXL
4938
"*.archive": "archive/pc/mod/",
@@ -85,7 +74,7 @@ def parse_cyberpunk_save_metadata(save_path: Path, save: mobase.ISaveGame):
8574
"Street Cred": int(meta_data["streetCred"]),
8675
"Life Path": meta_data["lifePath"],
8776
"Difficulty": meta_data["difficulty"],
88-
"Gender": f"{meta_data['bodyGender']} / {meta_data['brainGender']}",
77+
"Gender": f'{meta_data["bodyGender"]} / {meta_data["brainGender"]}',
8978
"Game version": meta_data["buildPatch"],
9079
}
9180
except (FileNotFoundError, json.JSONDecodeError):
@@ -200,7 +189,7 @@ def active_mod_paths(self, reverse: bool = False) -> Iterable[Path]:
200189
class Cyberpunk2077Game(BasicGame):
201190
Name = "Cyberpunk 2077 Support Plugin"
202191
Author = "6788, Zash"
203-
Version = "3.0.1"
192+
Version = "3.0.0"
204193

205194
GameName = "Cyberpunk 2077"
206195
GameShortName = "cyberpunk2077"
@@ -233,7 +222,7 @@ class Cyberpunk2077Game(BasicGame):
233222

234223
def init(self, organizer: mobase.IOrganizer) -> bool:
235224
super().init(organizer)
236-
self._register_feature(BasicLocalSavegames(self))
225+
self._register_feature(BasicLocalSavegames(self.savesDirectory()))
237226
self._register_feature(
238227
BasicGameSaveGameInfo(
239228
lambda p: Path(p or "", "screenshot.png"),
@@ -256,7 +245,6 @@ def init(self, organizer: mobase.IOrganizer) -> bool:
256245
),
257246
)
258247
organizer.onAboutToRun(self._onAboutToRun)
259-
organizer.onFinishedRun(self._onFinishedRun)
260248
organizer.onPluginSettingChanged(self._on_settings_changed)
261249
organizer.modList().onModInstalled(self._check_disable_crashreporter)
262250
organizer.onUserInterfaceInitialized(self._on_user_interface_initialized)
@@ -429,11 +417,6 @@ def settings(self) -> list[mobase.PluginSetting]:
429417
),
430418
True,
431419
),
432-
mobase.PluginSetting(
433-
"crash_message",
434-
("Show a crash message as replacement of disabled CrashReporter"),
435-
True,
436-
),
437420
mobase.PluginSetting(
438421
"show_rootbuilder_conversion",
439422
(
@@ -455,22 +438,22 @@ def executables(self) -> list[mobase.ExecutableInfo]:
455438
game_dir = self.gameDirectory()
456439
bin_path = game_dir.absoluteFilePath(self.binaryName())
457440
skip_start_screen = (
458-
"-skipStartScreen" if self._get_setting("skipStartScreen") else ""
441+
" -skipStartScreen" if self._get_setting("skipStartScreen") else ""
459442
)
460443
return [
461444
# Default, runs REDmod deploy if necessary
462445
mobase.ExecutableInfo(
463-
f"{game_name} (REDmod)",
446+
f"{game_name}",
464447
bin_path,
465-
).withArgument(f"--launcher-skip -modded {skip_start_screen}"),
448+
).withArgument(f"--launcher-skip -modded{skip_start_screen}"),
466449
# Start game without REDmod
467450
mobase.ExecutableInfo(
468-
f"{game_name}",
451+
f"{game_name} - skip REDmod deploy",
469452
bin_path,
470453
).withArgument(f"--launcher-skip {skip_start_screen}"),
471454
# Deploy REDmods only
472455
mobase.ExecutableInfo(
473-
"REDmod",
456+
"Manually deploy REDmod",
474457
self._get_redmod_binary(),
475458
).withArgument("deploy -reportProgress -force %modlist%"),
476459
# Launcher
@@ -504,7 +487,7 @@ def _onAboutToRun(self, app_path_str: str, wd: QDir, args: str) -> bool:
504487
_,
505488
) = self._modlist_files.update_modlist("redmod")
506489
modlist_param = f'-modlist="{modlist_path}"' if modlist else ""
507-
args = f"{args[: m.start()]}{modlist_param}{args[m.end() :]}"
490+
args = f"{args[:m.start()]}{modlist_param}{args[m.end():]}"
508491
qInfo(f"Manual modlist deployment: replacing {m[0]}, new args = {args}")
509492
self._check_redmod_result(
510493
self._organizer.waitForApplication(
@@ -527,35 +510,6 @@ def _onAboutToRun(self, app_path_str: str, wd: QDir, args: str) -> bool:
527510
self._modlist_files.update_modlist("archive")
528511
return True
529512

530-
def _onFinishedRun(self, path: str, exit_code: int) -> None:
531-
if not self._get_setting("crash_message"):
532-
return
533-
if path.endswith(self.binaryName()) and exit_code > 0:
534-
crash_message = QMessageBox(
535-
QMessageBox.Icon.Critical,
536-
"Cyberpunk Crashed",
537-
textwrap.dedent(
538-
f"""
539-
Cyberpunk crashed. Tips:
540-
- disable mods (create backup of modlist or use new profile)
541-
- clear overwrite or delete at least overwrite/r6/cache (to keep mod settings)
542-
- check log files of CET/redscript/RED4ext (in overwrite)
543-
- read [FAQ & Troubleshooting]({self.GameSupportURL}#faq--troubleshooting)
544-
"""
545-
),
546-
QMessageBox.StandardButton.Ok,
547-
self._parentWidget,
548-
)
549-
crash_message.setTextFormat(Qt.TextFormat.MarkdownText)
550-
hide_cb = QCheckBox("&Do not show again*", crash_message)
551-
hide_cb.setToolTip(f"Settings/Plugins/{self.name()}/crash_message")
552-
crash_message.setCheckBox(hide_cb)
553-
crash_message.open( # type: ignore
554-
lambda: (
555-
hide_cb.isChecked() and self._set_setting("crash_message", False)
556-
)
557-
)
558-
559513
def _check_redmod_result(self, result: tuple[bool, int]) -> bool:
560514
if result == (True, 0):
561515
return True
@@ -649,25 +603,46 @@ def _is_cache_file_updated(self, file: Path, data_path: Path) -> bool:
649603
Args:
650604
file: Relative to data dir.
651605
"""
606+
652607
game_file = data_path.absolute() / file
608+
653609
mapped_files = self._organizer.findFiles(file.parent, file.name)
610+
611+
# guard against missing mapped files early to avoid index/access issues
612+
if not mapped_files:
613+
return False
614+
615+
mapped_file = Path(mapped_files[0])
616+
617+
# ensure both paths exist before any filesystem comparisons
618+
# (prevents pathlib.samefile / filecmp from raising FileNotFoundError)
619+
if not game_file.exists() or not mapped_file.exists():
620+
return False
621+
654622
return bool(
655-
mapped_files
656-
and (mapped_file := mapped_files[0])
623+
mapped_file
657624
and not (
625+
# samefile is only safe after existence checks
658626
game_file.samefile(mapped_file)
627+
628+
# file comparison only executed when both files exist
659629
or filecmp.cmp(game_file, mapped_file)
630+
660631
or ( # different backup file
661632
(
662633
backup_files := self._organizer.findFiles(
663634
file.parent, f"{file.name}.bk"
664635
)
665636
)
666-
and filecmp.cmp(game_file, backup_files[0])
637+
and (
638+
# validate backup exists before comparison
639+
Path(backup_files[0]).exists()
640+
and game_file.exists()
641+
and filecmp.cmp(game_file, backup_files[0])
642+
)
667643
)
668644
)
669645
)
670-
671646
def _unmapped_cache_files(self, data_path: Path) -> Iterable[Path]:
672647
"""Yields unmapped cache files relative to `data_path`."""
673648
for file in self._organizer.findFiles("r6/cache", "*"):

0 commit comments

Comments
 (0)