Make Vanilla Tweaks selections fully authoritative
This commit is contained in:
+192
-1689
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,7 @@ import tempfile
|
||||
import unittest
|
||||
from unittest import mock
|
||||
|
||||
import setup_tool_dynamic
|
||||
from setup_tool import WowSetupTool
|
||||
from setup_tool_dynamic import ModernWowSetupTool
|
||||
|
||||
@@ -20,44 +21,109 @@ class FakeVar:
|
||||
|
||||
|
||||
class VanillaTweaksNormalizationTests(unittest.TestCase):
|
||||
def _tool(self, *, fov, sound, quickloot, background):
|
||||
def _tool(
|
||||
self,
|
||||
*,
|
||||
fov,
|
||||
sound,
|
||||
quickloot,
|
||||
background,
|
||||
farclip=777,
|
||||
frill=300,
|
||||
nameplate=41,
|
||||
maxcam=100,
|
||||
laa=True,
|
||||
camera=True,
|
||||
custom_glues=True,
|
||||
crossfaction=False,
|
||||
bluemoon=False,
|
||||
):
|
||||
tool = ModernWowSetupTool.__new__(ModernWowSetupTool)
|
||||
tool.vt_fov = FakeVar(fov)
|
||||
tool.vt_soundchan = FakeVar(sound)
|
||||
tool.vt_quickloot = FakeVar(quickloot)
|
||||
tool.vt_bg_sound = FakeVar(background)
|
||||
|
||||
# Remaining values are required by the executable settings signature.
|
||||
tool.vt_farclip = FakeVar(777)
|
||||
tool.vt_frill = FakeVar(300)
|
||||
tool.vt_nameplate = FakeVar(41)
|
||||
tool.vt_maxcam = FakeVar(100)
|
||||
tool.vt_laa = FakeVar(True)
|
||||
tool.vt_cam_fix = FakeVar(True)
|
||||
tool.vt_crossfaction_res = FakeVar(False)
|
||||
tool.vt_custom_glues = FakeVar(True)
|
||||
tool.vt_bluemoon = FakeVar(False)
|
||||
tool.vt_farclip = FakeVar(farclip)
|
||||
tool.vt_frill = FakeVar(frill)
|
||||
tool.vt_nameplate = FakeVar(nameplate)
|
||||
tool.vt_maxcam = FakeVar(maxcam)
|
||||
tool.vt_laa = FakeVar(laa)
|
||||
tool.vt_cam_fix = FakeVar(camera)
|
||||
tool.vt_crossfaction_res = FakeVar(crossfaction)
|
||||
tool.vt_custom_glues = FakeVar(custom_glues)
|
||||
tool.vt_bluemoon = FakeVar(bluemoon)
|
||||
tool.core_plugins = {"SuperWoWhook.dll": FakeVar(True)}
|
||||
return tool
|
||||
|
||||
def _write_exe(self, root, quick1, quick2, background, fov, sound):
|
||||
data = bytearray(0x435D3C + 16)
|
||||
def _write_exe(
|
||||
self,
|
||||
root,
|
||||
quick1,
|
||||
quick2,
|
||||
background,
|
||||
fov,
|
||||
sound,
|
||||
*,
|
||||
farclip=777.0,
|
||||
frill=70.0,
|
||||
nameplate=20.0,
|
||||
maxcam=50.0,
|
||||
laa_patched=False,
|
||||
camera_patched=False,
|
||||
custom_patched=False,
|
||||
crossfaction_byte=0x01,
|
||||
bluemoon_bytes=None,
|
||||
):
|
||||
data = bytearray(0x46795C + 16)
|
||||
data[0x0C1ECF:0x0C1ED1] = quick1
|
||||
data[0x0C2B25:0x0C2B27] = quick2
|
||||
data[0x3A4869] = background
|
||||
data[0x4089B4:0x4089B8] = struct.pack("<f", fov)
|
||||
data[0x126:0x128] = b"\x2F\x01" if laa_patched else b"\x0F\x01"
|
||||
|
||||
for offset, original, patched in setup_tool_dynamic._CAMERA_REGIONS:
|
||||
selected = patched if camera_patched else original
|
||||
data[offset:offset + len(selected)] = selected
|
||||
|
||||
for offset, original, patched in setup_tool_dynamic._CUSTOM_GLUES_SITES:
|
||||
data[offset] = patched if custom_patched else original
|
||||
|
||||
struct.pack_into("<f", data, 0x4089B4, fov)
|
||||
struct.pack_into("<f", data, 0x40FED8, farclip)
|
||||
struct.pack_into("<f", data, 0x467958, frill)
|
||||
struct.pack_into("<f", data, 0x40C448, nameplate)
|
||||
struct.pack_into("<f", data, 0x4089A4, maxcam)
|
||||
data[0x435D38:0x435D3C] = sound
|
||||
|
||||
data[0x2067DE] = crossfaction_byte
|
||||
if bluemoon_bytes is None:
|
||||
bluemoon_bytes = bytes(range(1, 14))
|
||||
data[0x3E5B83:0x3E5B83 + len(bluemoon_bytes)] = bluemoon_bytes
|
||||
|
||||
# Unrelated data must survive normalization byte-for-byte.
|
||||
data[0x123456:0x12345E] = b"KEEPTHIS"
|
||||
|
||||
path = os.path.join(root, "WoW_Modernized.exe")
|
||||
with open(path, "wb") as handle:
|
||||
handle.write(data)
|
||||
return path
|
||||
|
||||
@staticmethod
|
||||
def _read_float(data, offset):
|
||||
return struct.unpack("<f", data[offset:offset + 4])[0]
|
||||
|
||||
def test_disabled_selections_restore_inherited_patches(self):
|
||||
tool = self._tool(
|
||||
fov=1.5708,
|
||||
sound=12,
|
||||
quickloot=False,
|
||||
background=False,
|
||||
farclip=777,
|
||||
frill=70,
|
||||
nameplate=20,
|
||||
maxcam=50,
|
||||
laa=False,
|
||||
camera=False,
|
||||
custom_glues=False,
|
||||
)
|
||||
|
||||
with tempfile.TemporaryDirectory() as root:
|
||||
@@ -68,6 +134,13 @@ class VanillaTweaksNormalizationTests(unittest.TestCase):
|
||||
0x27,
|
||||
1.919862,
|
||||
b"64\x00\x00",
|
||||
farclip=3000.0,
|
||||
frill=300.0,
|
||||
nameplate=41.0,
|
||||
maxcam=100.0,
|
||||
laa_patched=True,
|
||||
camera_patched=True,
|
||||
custom_patched=True,
|
||||
)
|
||||
tool._normalize_selected_vanilla_tweaks_output(path)
|
||||
with open(path, "rb") as handle:
|
||||
@@ -76,19 +149,32 @@ class VanillaTweaksNormalizationTests(unittest.TestCase):
|
||||
self.assertEqual(result[0x0C1ECF:0x0C1ED1], b"\x74\x10")
|
||||
self.assertEqual(result[0x0C2B25:0x0C2B27], b"\x74\x0B")
|
||||
self.assertEqual(result[0x3A4869], 0x14)
|
||||
self.assertAlmostEqual(
|
||||
struct.unpack("<f", result[0x4089B4:0x4089B8])[0],
|
||||
1.5708,
|
||||
places=4,
|
||||
)
|
||||
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, 0x467958), 70.0)
|
||||
self.assertEqual(self._read_float(result, 0x40C448), 20.0)
|
||||
self.assertEqual(self._read_float(result, 0x4089A4), 50.0)
|
||||
self.assertEqual(result[0x435D38:0x435D3C], b"12\x00\x00")
|
||||
for offset, original, _patched in setup_tool_dynamic._CAMERA_REGIONS:
|
||||
self.assertEqual(result[offset:offset + len(original)], original)
|
||||
for offset, original, _patched in setup_tool_dynamic._CUSTOM_GLUES_SITES:
|
||||
self.assertEqual(result[offset], original)
|
||||
self.assertEqual(result[0x123456:0x12345E], b"KEEPTHIS")
|
||||
|
||||
def test_enabled_selections_override_vanilla_or_nop_input(self):
|
||||
def test_enabled_selections_override_vanilla_input(self):
|
||||
tool = self._tool(
|
||||
fov=1.9199,
|
||||
sound=64,
|
||||
quickloot=True,
|
||||
background=True,
|
||||
farclip=1500,
|
||||
frill=300,
|
||||
nameplate=41,
|
||||
maxcam=100,
|
||||
laa=True,
|
||||
camera=True,
|
||||
custom_glues=True,
|
||||
)
|
||||
|
||||
with tempfile.TemporaryDirectory() as root:
|
||||
@@ -97,7 +183,7 @@ class VanillaTweaksNormalizationTests(unittest.TestCase):
|
||||
b"\x90\x90",
|
||||
b"\x90\x90",
|
||||
0x14,
|
||||
1.5708,
|
||||
1.5707963705,
|
||||
b"12\x00\x00",
|
||||
)
|
||||
tool._normalize_selected_vanilla_tweaks_output(path)
|
||||
@@ -107,12 +193,18 @@ class VanillaTweaksNormalizationTests(unittest.TestCase):
|
||||
self.assertEqual(result[0x0C1ECF:0x0C1ED1], b"\x75\x10")
|
||||
self.assertEqual(result[0x0C2B25:0x0C2B27], b"\x75\x0B")
|
||||
self.assertEqual(result[0x3A4869], 0x27)
|
||||
self.assertAlmostEqual(
|
||||
struct.unpack("<f", result[0x4089B4:0x4089B8])[0],
|
||||
1.9199,
|
||||
places=4,
|
||||
)
|
||||
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, 0x467958), 300.0)
|
||||
self.assertEqual(self._read_float(result, 0x40C448), 41.0)
|
||||
self.assertEqual(self._read_float(result, 0x4089A4), 100.0)
|
||||
self.assertEqual(result[0x435D38:0x435D3C], b"64\x00\x00")
|
||||
for offset, _original, patched in setup_tool_dynamic._CAMERA_REGIONS:
|
||||
self.assertEqual(result[offset:offset + len(patched)], patched)
|
||||
for offset, _original, patched in setup_tool_dynamic._CUSTOM_GLUES_SITES:
|
||||
self.assertEqual(result[offset], patched)
|
||||
self.assertEqual(result[0x123456:0x12345E], b"KEEPTHIS")
|
||||
|
||||
def test_unknown_quickloot_bytes_fail_safe(self):
|
||||
tool = self._tool(
|
||||
@@ -134,6 +226,63 @@ class VanillaTweaksNormalizationTests(unittest.TestCase):
|
||||
with self.assertRaisesRegex(RuntimeError, "Unexpected QuickLoot bytes"):
|
||||
tool._normalize_selected_vanilla_tweaks_output(path)
|
||||
|
||||
def test_unknown_custom_glues_bytes_fail_safe(self):
|
||||
tool = self._tool(
|
||||
fov=1.9199,
|
||||
sound=64,
|
||||
quickloot=True,
|
||||
background=True,
|
||||
custom_glues=False,
|
||||
)
|
||||
|
||||
with tempfile.TemporaryDirectory() as root:
|
||||
path = self._write_exe(
|
||||
root,
|
||||
b"\x74\x10",
|
||||
b"\x74\x0B",
|
||||
0x14,
|
||||
1.5708,
|
||||
b"12\x00\x00",
|
||||
)
|
||||
with open(path, "r+b") as handle:
|
||||
handle.seek(0x2F113A)
|
||||
handle.write(b"\xAA")
|
||||
|
||||
with self.assertRaisesRegex(RuntimeError, "Unexpected Custom GlueXML bytes"):
|
||||
tool._normalize_selected_vanilla_tweaks_output(path)
|
||||
|
||||
def test_blue_moon_and_crossfaction_keep_legacy_output(self):
|
||||
tool = self._tool(
|
||||
fov=1.9199,
|
||||
sound=64,
|
||||
quickloot=True,
|
||||
background=True,
|
||||
crossfaction=True,
|
||||
bluemoon=True,
|
||||
)
|
||||
blue_bytes = bytes.fromhex("a1 a2 a3 a4 a5 a6 a7 a8 a9 aa ab ac ad")
|
||||
|
||||
with tempfile.TemporaryDirectory() as root:
|
||||
path = self._write_exe(
|
||||
root,
|
||||
b"\x74\x10",
|
||||
b"\x74\x0B",
|
||||
0x14,
|
||||
1.5708,
|
||||
b"12\x00\x00",
|
||||
crossfaction_byte=0x7A,
|
||||
bluemoon_bytes=blue_bytes,
|
||||
)
|
||||
tool._normalize_selected_vanilla_tweaks_output(path)
|
||||
with open(path, "rb") as handle:
|
||||
result = handle.read()
|
||||
|
||||
self.assertEqual(result[0x2067DE], 0x7A)
|
||||
self.assertEqual(
|
||||
result[0x3E5B83:0x3E5B83 + len(blue_bytes)],
|
||||
blue_bytes,
|
||||
)
|
||||
|
||||
def test_transaction_keeps_existing_output_when_normalization_fails(self):
|
||||
tool = self._tool(
|
||||
fov=1.9199,
|
||||
@@ -177,12 +326,19 @@ class VanillaTweaksNormalizationTests(unittest.TestCase):
|
||||
any(name.startswith(".modernization-vt-") for name in os.listdir(root))
|
||||
)
|
||||
|
||||
def test_transaction_commits_normalized_output_after_validation(self):
|
||||
def test_transaction_commits_total_normalized_output_after_validation(self):
|
||||
tool = self._tool(
|
||||
fov=1.5708,
|
||||
sound=12,
|
||||
quickloot=False,
|
||||
background=False,
|
||||
farclip=777,
|
||||
frill=70,
|
||||
nameplate=20,
|
||||
maxcam=50,
|
||||
laa=False,
|
||||
camera=False,
|
||||
custom_glues=False,
|
||||
)
|
||||
tool._inspect_wow_executable = lambda _path: (True, "ok")
|
||||
|
||||
@@ -203,6 +359,13 @@ class VanillaTweaksNormalizationTests(unittest.TestCase):
|
||||
0x27,
|
||||
1.919862,
|
||||
b"64\x00\x00",
|
||||
farclip=3000.0,
|
||||
frill=300.0,
|
||||
nameplate=41.0,
|
||||
maxcam=100.0,
|
||||
laa_patched=True,
|
||||
camera_patched=True,
|
||||
custom_patched=True,
|
||||
)
|
||||
|
||||
with mock.patch.object(WowSetupTool, "run_vanilla_tweaks", new=fake_run):
|
||||
@@ -219,12 +382,17 @@ class VanillaTweaksNormalizationTests(unittest.TestCase):
|
||||
self.assertEqual(result[0x0C1ECF:0x0C1ED1], b"\x74\x10")
|
||||
self.assertEqual(result[0x0C2B25:0x0C2B27], b"\x74\x0B")
|
||||
self.assertEqual(result[0x3A4869], 0x14)
|
||||
self.assertAlmostEqual(
|
||||
struct.unpack("<f", result[0x4089B4:0x4089B8])[0],
|
||||
1.5708,
|
||||
places=4,
|
||||
)
|
||||
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, 0x467958), 70.0)
|
||||
self.assertEqual(self._read_float(result, 0x40C448), 20.0)
|
||||
self.assertEqual(self._read_float(result, 0x4089A4), 50.0)
|
||||
self.assertEqual(result[0x435D38:0x435D3C], b"12\x00\x00")
|
||||
for offset, original, _patched in setup_tool_dynamic._CAMERA_REGIONS:
|
||||
self.assertEqual(result[offset:offset + len(original)], original)
|
||||
for offset, original, _patched in setup_tool_dynamic._CUSTOM_GLUES_SITES:
|
||||
self.assertEqual(result[offset], original)
|
||||
self.assertFalse(os.path.exists(output_exe + ".modernization-new"))
|
||||
self.assertFalse(
|
||||
any(name.startswith(".modernization-vt-") for name in os.listdir(root))
|
||||
@@ -242,7 +410,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"], 1)
|
||||
self.assertEqual(new_signature["selected_patch_normalization"], 2)
|
||||
|
||||
tool.core_plugins["SuperWoWhook.dll"].set(False)
|
||||
self.assertEqual(new_signature, tool._vanilla_tweaks_signature())
|
||||
|
||||
Reference in New Issue
Block a user