fallbacks: preserve installed versions and use bundled backups

This commit is contained in:
Dusk-92
2026-08-27 15:06:50 +02:00
parent c30f00a9fe
commit 52086ae178
+128 -26
View File
@@ -200,7 +200,7 @@ class ModernWowSetupTool(WowSetupTool):
"SuperWoWhook.dll": ("SuperWoW", "by balakethelock"),
"transmogfix.dll": ("TransmogFix", "by MarcelineVQ"),
"perf_boost.dll": ("PerfBoost", "by avitasia"),
"weirdperformance.dll": ("WeirdPerformance", "by MarcelineVQ"),
"weirdperformance.dll": ("WeirdPerformance", "Dusk92 build 0.7.3"),
"VanillaHelpers.dll": ("VanillaHelpers", "by isfir"),
}
@@ -323,14 +323,42 @@ class ModernWowSetupTool(WowSetupTool):
if os.path.exists(addon_path):
shutil.rmtree(addon_path, ignore_errors=True)
def _warn_offline(self, component, action, error):
self._close_download_progress()
messagebox.showwarning(
"Online update unavailable",
f"Could not download the latest {component}.\n\n"
f"{action}\n\nDetails: {error}",
)
def _fallback_core_dll(self, payload_base, target, dll_name, error):
source_dll = os.path.join(payload_base, dll_name)
if not os.path.exists(source_dll):
target_dll = os.path.join(target, dll_name)
addon_folder = self.addon_dependencies.get(dll_name)
target_addon = (
os.path.join(target, "Interface", "AddOns", addon_folder)
if addon_folder
else None
)
# Never downgrade a complete existing install because an upstream link
# happens to be unavailable during an update.
existing_complete = os.path.isfile(target_dll) and (
target_addon is None or os.path.isdir(target_addon)
)
if existing_complete:
self._warn_offline(
dll_name,
"The version already installed in your WoW folder was kept unchanged.",
error,
)
return
if not os.path.isfile(source_dll):
raise RuntimeError(
f"Could not download the latest {dll_name}, and no bundled fallback exists.\n\n{error}"
) from error
addon_folder = self.addon_dependencies.get(dll_name)
source_addon = None
if addon_folder:
source_addon = os.path.join(payload_base, "Interface", "Addons", addon_folder)
@@ -340,24 +368,100 @@ class ModernWowSetupTool(WowSetupTool):
f"{addon_folder} is missing.\n\n{error}"
) from error
shutil.copy2(source_dll, target)
shutil.copy2(source_dll, target_dll)
if addon_folder and source_addon:
remote_packages._replace_directory(
source_addon,
os.path.join(target, "Interface", "AddOns", addon_folder),
)
remote_packages._replace_directory(source_addon, target_addon)
self._close_download_progress()
messagebox.showwarning(
"Online update unavailable",
f"Could not download the latest {dll_name}.\n\n"
f"The bundled version will be used instead.\n\nDetails: {error}",
self._warn_offline(
dll_name,
"The bundled known-good backup was installed instead.",
error,
)
def _fallback_simple_dll(self, target, dll_name, error):
target_dll = os.path.join(target, dll_name)
if os.path.isfile(target_dll):
self._warn_offline(
dll_name,
"The version already installed in your WoW folder was kept unchanged.",
error,
)
return
fallback = os.path.join(get_base_path(), "Payload", "Fallback", dll_name)
if not os.path.isfile(fallback):
raise RuntimeError(
f"Could not download the latest {dll_name}, and its bundled backup is missing.\n\n{error}"
) from error
shutil.copy2(fallback, target_dll)
self._warn_offline(
dll_name,
"The bundled known-good backup was installed instead.",
error,
)
def _fallback_vmmfix(self, target, error):
target_dll = os.path.join(target, "VanillaMultiMonitorFix.dll")
if os.path.isfile(target_dll):
self._warn_offline(
"VanillaMultiMonitorFix",
"The version already installed in your WoW folder was kept unchanged.",
error,
)
return
fallback_dir = os.path.join(
get_base_path(), "Payload", "Fallback", "VanillaMultiMonitorFix"
)
fallback_dll = os.path.join(fallback_dir, "VanillaMultiMonitorFix.dll")
fallback_config = os.path.join(fallback_dir, "VMMFix_preferred_monitor.txt")
if not os.path.isfile(fallback_dll):
raise RuntimeError(
f"VanillaMultiMonitorFix update failed and its bundled backup is missing.\n\n{error}"
) from error
shutil.copy2(fallback_dll, target_dll)
target_config = os.path.join(target, "VMMFix_preferred_monitor.txt")
if not os.path.exists(target_config) and os.path.isfile(fallback_config):
shutil.copy2(fallback_config, target_config)
self._warn_offline(
"VanillaMultiMonitorFix",
"The bundled known-good backup was installed instead.",
error,
)
def _fallback_interact(self, target, error):
target_dll = os.path.join(target, "Interact.dll")
target_addon = os.path.join(target, "Interface", "AddOns", "Interact")
if os.path.isfile(target_dll) and os.path.isdir(target_addon):
self._warn_offline(
"Interact",
"The version already installed in your WoW folder was kept unchanged.",
error,
)
return
fallback_dir = os.path.join(get_base_path(), "Payload", "Fallback", "Interact")
fallback_dll = os.path.join(fallback_dir, "Interact.dll")
fallback_addon = os.path.join(fallback_dir, "Addon")
if not os.path.isfile(fallback_dll) or not os.path.isdir(fallback_addon):
raise RuntimeError(
f"Interact update failed and its bundled backup is incomplete.\n\n{error}"
) from error
shutil.copy2(fallback_dll, target_dll)
remote_packages._replace_directory(fallback_addon, target_addon)
self._warn_offline(
"Interact",
"The bundled known-good backup was installed instead.",
error,
)
def run_vanilla_tweaks(self, target):
# Prefer the latest stable tubtubs build on every Apply. The bundled
# brndd executable remains an offline fallback.
# Prefer the latest stable tubtubs build on every Apply. A known-good
# tubtubs build is bundled as the offline fallback.
try:
tweaks_exe, extract_root, version = remote_packages.prepare_vanilla_tweaks(
progress=self._report_download_progress,
@@ -367,11 +471,11 @@ class ModernWowSetupTool(WowSetupTool):
messagebox.showwarning(
"Latest vanilla-tweaks unavailable",
"Could not download the latest tubtubs/vanilla-tweaks build.\n\n"
"The bundled legacy patcher will be used instead. Modern-only "
"patches (Cross-faction Res, Custom Glues and Bluemoon) cannot "
f"be applied by the legacy fallback.\n\nDetails: {exc}",
"The bundled known-good tubtubs build will be used instead, so "
"the same modern patch options remain available.\n\n"
f"Details: {exc}",
)
return super().run_vanilla_tweaks(target, modern_cli=False)
return super().run_vanilla_tweaks(target, modern_cli=True)
try:
self._report_download_progress(
@@ -456,7 +560,7 @@ class ModernWowSetupTool(WowSetupTool):
progress=self._report_download_progress,
)
except Exception as exc:
raise RuntimeError(f"ClassicAPI update failed:\n{exc}") from exc
self._fallback_simple_dll(target, "ClassicAPI.dll", exc)
dlls_text_lines.append("ClassicAPI.dll")
if self.auction_throttle_enabled.get():
@@ -466,7 +570,7 @@ class ModernWowSetupTool(WowSetupTool):
progress=self._report_download_progress,
)
except Exception as exc:
raise RuntimeError(f"Auction Query Throttle update failed:\n{exc}") from exc
self._fallback_simple_dll(target, "AuctionQueryThrottle.dll", exc)
dlls_text_lines.append("AuctionQueryThrottle.dll")
# Clean dependent addons when the matching core DLL is disabled.
@@ -501,9 +605,7 @@ class ModernWowSetupTool(WowSetupTool):
progress=self._report_download_progress,
)
except Exception as exc:
raise RuntimeError(
f"VanillaMultiMonitorFix update failed:\n{exc}"
) from exc
self._fallback_vmmfix(target, exc)
dlls_text_lines.append("VanillaMultiMonitorFix.dll")
if self.interact_enabled.get():
@@ -513,7 +615,7 @@ class ModernWowSetupTool(WowSetupTool):
progress=self._report_download_progress,
)
except Exception as exc:
raise RuntimeError(f"Interact update failed:\n{exc}") from exc
self._fallback_interact(target, exc)
dlls_text_lines.append("Interact.dll")
# Optional WeirdUtils.