diff --git a/setup_tool_responsive.py b/setup_tool_responsive.py index 6bff730..9741a23 100644 --- a/setup_tool_responsive.py +++ b/setup_tool_responsive.py @@ -1,7 +1,5 @@ import json import os -import re -import stat import tkinter as tk from tkinter import messagebox, ttk @@ -9,9 +7,6 @@ import dxvk_fps import setup_tool_dynamic -_FARCLIP_EXE_FLOOR = 3000.0 - - class ResponsiveModernWowSetupTool(setup_tool_dynamic.ModernWowSetupTool): """Production entry point with display-scaling-safe UI and DXVK FPS control.""" @@ -247,83 +242,6 @@ class ResponsiveModernWowSetupTool(setup_tool_dynamic.ModernWowSetupTool): return True - def _desired_normalized_values(self): - desired = super()._desired_normalized_values() - # The EXE field is a maximum allowed Farclip, not the active distance. - # Keep a 3000 baseline ceiling so an existing Config.wtf value cannot - # exceed a newly reduced executable limit. Values explicitly selected - # above 3000 still raise the ceiling so the safety override keeps working. - desired["farclip"] = max(_FARCLIP_EXE_FLOOR, desired["farclip"]) - return desired - - def _configure_farclip_cvar(self, target): - """Apply the selected render distance to WTF/Config.wtf.""" - try: - farclip = int(self.vt_farclip.get()) - except (tk.TclError, TypeError, ValueError) as exc: - raise RuntimeError("Render Distance (Farclip) is not a valid number.") from exc - if farclip <= 0: - raise RuntimeError("Render Distance (Farclip) must be greater than 0.") - - wtf_dir = os.path.join(target, "WTF") - config_path = os.path.join(wtf_dir, "Config.wtf") - staged = config_path + ".modernization-farclip" - original_mode = None - restore_readonly = False - - try: - os.makedirs(wtf_dir, exist_ok=True) - - if os.path.exists(config_path): - original_mode = os.stat(config_path).st_mode - if not (original_mode & stat.S_IWRITE): - os.chmod(config_path, original_mode | stat.S_IWRITE) - restore_readonly = True - - existing = "" - if os.path.exists(config_path): - with open(config_path, "r", encoding="utf-8", errors="ignore") as handle: - existing = handle.read() - - setting = f'SET farclip "{farclip}"' - pattern = re.compile( - r'^\s*SET\s+farclip\s+"[^"]*"\s*$', - re.IGNORECASE | re.MULTILINE, - ) - if pattern.search(existing): - updated = pattern.sub(setting, existing) - else: - if existing and not existing.endswith(("\n", "\r")): - existing += "\n" - updated = existing + setting + "\n" - - with open(staged, "w", encoding="utf-8", newline="") as handle: - handle.write(updated) - os.replace(staged, config_path) - - except OSError as exc: - raise RuntimeError( - "Could not synchronize Render Distance in WTF\\Config.wtf. " - "Close WoW and any program using the file, then try again." - ) from exc - finally: - if os.path.exists(staged): - try: - os.remove(staged) - except OSError: - pass - if restore_readonly and original_mode is not None and os.path.exists(config_path): - try: - os.chmod(config_path, original_mode) - except OSError: - pass - - def configure_script_memory(self, target): - # Keep the existing script-memory and SuperWoW FoV behavior, then make - # the Tool's Render Distance selection authoritative at runtime too. - super().configure_script_memory(target) - self._configure_farclip_cvar(target) - def configure_dxvk(self, target): super().configure_dxvk(target) diff --git a/tests/test_farclip_config_sync.py b/tests/test_farclip_config_sync.py index c46eeea..6d7a2b2 100644 --- a/tests/test_farclip_config_sync.py +++ b/tests/test_farclip_config_sync.py @@ -4,7 +4,6 @@ import unittest from unittest import mock import setup_tool_dynamic -import setup_tool_responsive class _Var: @@ -17,29 +16,46 @@ class _Var: class FarclipConfigSyncTests(unittest.TestCase): def _tool(self, farclip=777): - tool = object.__new__(setup_tool_responsive.ResponsiveModernWowSetupTool) + tool = object.__new__(setup_tool_dynamic.ModernWowSetupTool) tool.vt_farclip = _Var(farclip) return tool - def test_executable_farclip_ceiling_has_3000_floor(self): - tool = self._tool() - with mock.patch.object( - setup_tool_dynamic.ModernWowSetupTool, - "_desired_normalized_values", - return_value={"farclip": 777.0}, - ): - desired = tool._desired_normalized_values() + @staticmethod + def _add_numeric_vars(tool): + tool.vt_fov = _Var(1.9199) + tool.vt_frill = _Var(300) + tool.vt_nameplate = _Var(41) + tool.vt_maxcam = _Var(100) + tool.vt_soundchan = _Var(64) + + def test_executable_farclip_ceiling_is_always_3000(self): + tool = self._tool(777) + self._add_numeric_vars(tool) + desired = tool._desired_normalized_values() self.assertEqual(desired["farclip"], 3000.0) - def test_executable_farclip_ceiling_keeps_explicit_value_above_3000(self): + tool.vt_farclip = _Var(3000) + desired = tool._desired_normalized_values() + self.assertEqual(desired["farclip"], 3000.0) + + def test_farclip_above_3000_is_rejected_even_with_direct_internal_call(self): tool = self._tool(5000) - with mock.patch.object( - setup_tool_dynamic.ModernWowSetupTool, - "_desired_normalized_values", - return_value={"farclip": 5000.0}, - ): - desired = tool._desired_normalized_values() - self.assertEqual(desired["farclip"], 5000.0) + self._add_numeric_vars(tool) + with self.assertRaisesRegex(RuntimeError, "Farclip"): + tool._desired_normalized_values() + + def test_normalization_signature_bump_forces_existing_install_refresh(self): + tool = self._tool(777) + self._add_numeric_vars(tool) + tool.vt_quickloot = _Var(True) + tool.vt_bg_sound = _Var(True) + tool.vt_laa = _Var(True) + tool.vt_cam_fix = _Var(True) + tool.vt_crossfaction_res = _Var(False) + tool.vt_custom_glues = _Var(True) + tool.vt_bluemoon = _Var(False) + signature = tool._vanilla_tweaks_signature() + self.assertEqual(signature["selected_patch_normalization"], 4) def test_existing_farclip_cvar_is_replaced_without_touching_other_settings(self): tool = self._tool(777) @@ -88,10 +104,18 @@ class FarclipConfigSyncTests(unittest.TestCase): result = handle.read() self.assertEqual(result, 'SET farclip "1000"\n') + def test_farclip_cvar_rejects_value_above_fixed_ceiling(self): + tool = self._tool(3001) + with tempfile.TemporaryDirectory() as root: + with self.assertRaisesRegex(RuntimeError, "3000"): + tool._configure_farclip_cvar(root) + self.assertFalse(os.path.exists(os.path.join(root, "WTF", "Config.wtf"))) + def test_configure_script_memory_also_synchronizes_farclip(self): tool = self._tool(777) + tool.core_plugins = {"SuperWoWhook.dll": _Var(False)} with mock.patch.object( - setup_tool_dynamic.ModernWowSetupTool, + setup_tool_dynamic._ModernWowSetupToolCore, "configure_script_memory", ) as parent_configure, mock.patch.object( tool, diff --git a/tests/test_vanilla_tweaks_normalization.py b/tests/test_vanilla_tweaks_normalization.py index 8990cb1..c5c11cc 100644 --- a/tests/test_vanilla_tweaks_normalization.py +++ b/tests/test_vanilla_tweaks_normalization.py @@ -193,7 +193,7 @@ class VanillaTweaksNormalizationTests(unittest.TestCase): self.assertEqual(result[0x3A4869], 0x14) self.assertEqual(result[0x126:0x128], b"\x0F\x01") self.assertAlmostEqual(self._read_float(result, 0x4089B4), 1.5708, places=4) - self.assertEqual(self._read_float(result, 0x40FED8), 777.0) + self.assertEqual(self._read_float(result, 0x40FED8), 3000.0) self.assertEqual(self._read_float(result, 0x467958), 70.0) self.assertEqual(self._read_float(result, 0x40C448), 20.0) self.assertEqual(self._read_float(result, 0x4089A4), 50.0) @@ -237,7 +237,7 @@ class VanillaTweaksNormalizationTests(unittest.TestCase): self.assertEqual(result[0x3A4869], 0x27) self.assertEqual(result[0x126:0x128], b"\x2F\x01") self.assertAlmostEqual(self._read_float(result, 0x4089B4), 1.9199, places=4) - self.assertEqual(self._read_float(result, 0x40FED8), 1500.0) + self.assertEqual(self._read_float(result, 0x40FED8), 3000.0) self.assertEqual(self._read_float(result, 0x467958), 300.0) self.assertEqual(self._read_float(result, 0x40C448), 41.0) self.assertEqual(self._read_float(result, 0x4089A4), 100.0) @@ -581,7 +581,7 @@ class VanillaTweaksNormalizationTests(unittest.TestCase): self.assertEqual(result[0x3A4869], 0x14) self.assertEqual(result[0x126:0x128], b"\x0F\x01") self.assertAlmostEqual(self._read_float(result, 0x4089B4), 1.5708, places=4) - self.assertEqual(self._read_float(result, 0x40FED8), 777.0) + self.assertEqual(self._read_float(result, 0x40FED8), 3000.0) self.assertEqual(self._read_float(result, 0x467958), 70.0) self.assertEqual(self._read_float(result, 0x40C448), 20.0) self.assertEqual(self._read_float(result, 0x4089A4), 50.0) @@ -627,7 +627,7 @@ class VanillaTweaksNormalizationTests(unittest.TestCase): new_signature = tool._vanilla_tweaks_signature() self.assertNotIn("selected_patch_normalization", old_signature) - self.assertEqual(new_signature["selected_patch_normalization"], 3) + self.assertEqual(new_signature["selected_patch_normalization"], 4) tool.core_plugins["SuperWoWhook.dll"].set(False) self.assertEqual(new_signature, tool._vanilla_tweaks_signature())