240 lines
9.2 KiB
YAML
240 lines
9.2 KiB
YAML
name: Test safe standalone core V8 Debug
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- test/safe-core-v8-debug
|
|
workflow_dispatch:
|
|
|
|
# V8 debug diagnostics build
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
build:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- uses: mlugg/setup-zig@v2
|
|
with:
|
|
version: 0.16.0
|
|
|
|
- name: Build safe standalone variants
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
zig build all-variants -Doptimize=ReleaseSmall \
|
|
-Dweirdperformance=false \
|
|
-Doutline=true
|
|
|
|
- name: Verify minimal core layout
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
python3 - <<'PY'
|
|
from pathlib import Path
|
|
|
|
root = Path("zig-out/variants")
|
|
|
|
addr = {
|
|
"lua_protection": 0x42A320,
|
|
"register_commands": 0x490250,
|
|
"glue_commands": 0x46ABB0,
|
|
"engine_init": 0x46A400,
|
|
"logout": 0x491180,
|
|
"shutdown": 0x490BD0,
|
|
"file_fallback": 0x648620,
|
|
"open_file": 0x6477C0,
|
|
"file_size": 0x6487F0,
|
|
"read_file": 0x648460,
|
|
"cleanup_file": 0x648730,
|
|
"model_load": 0x71D4E0,
|
|
"check_file": 0x654DD0,
|
|
}
|
|
|
|
def has(data, value):
|
|
return value.to_bytes(4, "little") in data
|
|
|
|
outline = (root / "outline.dll").read_bytes()
|
|
custom = (root / "customassets.dll").read_bytes()
|
|
transmog = (root / "transmogfix.dll").read_bytes()
|
|
|
|
# Outline: only its Lua registration + engine init core hooks are allowed.
|
|
required_outline = ("register_commands", "engine_init")
|
|
forbidden_outline = tuple(k for k in addr if k not in required_outline)
|
|
for k in required_outline:
|
|
if not has(outline, addr[k]):
|
|
raise SystemExit(f"outline.dll missing required {k}")
|
|
bad = [k for k in forbidden_outline if has(outline, addr[k])]
|
|
if bad:
|
|
raise SystemExit(f"outline.dll still contains unwanted core hooks: {bad}")
|
|
print("outline.dll: minimal core verified")
|
|
|
|
# CustomAssets: only CheckFileExistence is allowed from the generic core.
|
|
if not has(custom, addr["check_file"]):
|
|
raise SystemExit("customassets.dll missing CheckFileExistence")
|
|
bad = [k for k,v in addr.items() if k != "check_file" and has(custom, v)]
|
|
if bad:
|
|
raise SystemExit(f"customassets.dll still contains unwanted core hooks: {bad}")
|
|
print("customassets.dll: minimal core verified")
|
|
|
|
# TransmogFix: none of the generic core hook target addresses should remain.
|
|
bad = [k for k,v in addr.items() if has(transmog, v)]
|
|
if bad:
|
|
raise SystemExit(f"transmogfix.dll still contains unwanted core hooks: {bad}")
|
|
print("transmogfix.dll: minimal core verified")
|
|
|
|
# Compatibility repair must exist in customassets and outline.
|
|
for name, data in (("outline.dll", outline), ("customassets.dll", custom)):
|
|
for gate in (0x654B5C, 0x654B6A):
|
|
if not has(data, gate):
|
|
raise SystemExit(f"{name} missing MPQ gate restore address 0x{gate:X}")
|
|
for seq in (bytes([0x74,0x25]), bytes([0x75,0x17])):
|
|
if seq not in data:
|
|
raise SystemExit(f"{name} missing original MPQ branch bytes {seq.hex()}")
|
|
print("legacy MPQ gate repair verified")
|
|
PY
|
|
|
|
- name: Verify Outline registration + Lua ABI
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
python3 - <<'PY'
|
|
from pathlib import Path
|
|
|
|
main = Path("src/main.zig").read_text()
|
|
outline = Path("src/outline/outline.zig").read_text()
|
|
|
|
for required in (
|
|
'noinline fn registerFunction',
|
|
'0x704120',
|
|
'"{ecx}" (@intFromPtr(name))',
|
|
'"{edx}" (func_addr)',
|
|
):
|
|
if required not in main:
|
|
raise SystemExit(f"Missing explicit FrameScript registration ABI piece: {required}")
|
|
|
|
for required in (
|
|
'luaGetTopNative',
|
|
'luaIsStringNative',
|
|
'luaToStringNative',
|
|
'luaPushBooleanNative',
|
|
'"{ecx}"',
|
|
'"{edx}"',
|
|
'0x6F39F0',
|
|
'callconv(.{ .x86_thiscall = .{} })',
|
|
'luaPushStringNative',
|
|
'pub fn outlineDebug',
|
|
'OutlineDBG en=',
|
|
):
|
|
if required not in outline:
|
|
raise SystemExit(f"Missing Outline callback/native wrapper ABI piece: {required}")
|
|
|
|
print("source: FrameScript registration uses ECX/EDX; Outline callback receives L in ECX")
|
|
PY
|
|
|
|
objdump -d -Mintel zig-out/variants/outline.dll > /tmp/outline.disasm
|
|
python3 - <<'PY'
|
|
import re
|
|
from pathlib import Path
|
|
|
|
lines = Path("/tmp/outline.disasm").read_text(errors="replace").splitlines()
|
|
|
|
# registerFunction is explicit inline asm and source-checked above.
|
|
# Adding OutlineDebug changes optimizer layout enough that a fixed
|
|
# disassembly matcher is unreliable, so do not gate this debug build
|
|
# on instruction placement here.
|
|
|
|
# OutlineCommand must capture the Lua state from ECX. Search function
|
|
# prologues for the characteristic saved-ESI form and reject the old
|
|
# [ebp+8] capture used by the cdecl experiment.
|
|
good_callback = False
|
|
for i, line in enumerate(lines):
|
|
if re.search(r"push\s+ebp\b", line, re.I):
|
|
block = "\n".join(lines[i:i + 12])
|
|
if re.search(r"mov\s+esi,ecx\b", block, re.I):
|
|
good_callback = True
|
|
break
|
|
|
|
if not good_callback:
|
|
raise SystemExit("BAD ABI: no callback body captures Lua state from ECX")
|
|
|
|
print("outline.dll machine code: registration and callback ABIs verified")
|
|
PY
|
|
|
|
- name: Verify direct player and target GUID path
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
python3 - <<'PY'
|
|
from pathlib import Path
|
|
wow = Path("src/wow.zig").read_text()
|
|
offsets = Path("src/offsets.zig").read_text()
|
|
for required in (
|
|
'const guid = getPlayerGUID();',
|
|
'return readGUID(o.LOCKED_TARGET_GUID);',
|
|
):
|
|
if required not in wow:
|
|
raise SystemExit(f"Missing direct player/target GUID path: {required}")
|
|
for required in (
|
|
'FN_GET_PLAYER_GUID: usize = 0x00468550',
|
|
'LOCKED_TARGET_GUID: usize = 0x00B4E2D8',
|
|
'FN_GET_OBJECT_BY_GUID: usize = 0x464870',
|
|
):
|
|
if required not in offsets:
|
|
raise SystemExit(f"Missing verified WoW offset: {required}")
|
|
print("source: player GUID, target GUID and GUID->object path verified")
|
|
PY
|
|
|
|
- name: Stage package
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
mkdir -p package/DLL
|
|
mkdir -p package/Interface/AddOns/WeirdUtils_Outline
|
|
|
|
cp zig-out/variants/outline.dll package/DLL/
|
|
cp zig-out/variants/customassets.dll package/DLL/
|
|
cp zig-out/variants/transmogfix.dll package/DLL/
|
|
|
|
cp src/outline/addon/Outline.lua package/Interface/AddOns/WeirdUtils_Outline/
|
|
cp src/outline/addon/Bindings.xml package/Interface/AddOns/WeirdUtils_Outline/
|
|
cp src/outline/addon/WeirdUtils_Outline.toc package/Interface/AddOns/WeirdUtils_Outline/
|
|
|
|
cat > package/README_TEST.txt <<'EOF'
|
|
WeirdUtils Safe Standalone Core Test V8 DEBUG
|
|
|
|
This debug build uses ClntObjMgrGetActivePlayer for the local player and the locked target GUID at 0xB4E2D8, matching Nampower's proven object path. WoW Lua API calls stay on explicit native register wrappers.
|
|
|
|
outline.dll
|
|
- Adds OutlineDebug() sticky in-game diagnostics for the render pipeline.
|
|
- Keeps only the Player_LoadScriptFunctions hook required to register OutlineCommand/OutlineDebug.
|
|
- Keeps only the GameEngine_MainInitialize hook required to initialise the renderer.
|
|
- Does not register the shared WeirdUtils version table.
|
|
- Does not install generic MPQ/file hooks.
|
|
- Uses the external WeirdUtils_Outline addon included here.
|
|
|
|
customassets.dll
|
|
- Keeps only CheckFileExistence from the shared file core.
|
|
- No shared Lua registration hooks.
|
|
- No shared engine/logout/shutdown hooks.
|
|
- Repairs legacy File_FindInArchive NOPs if present.
|
|
|
|
transmogfix.dll
|
|
- Installs only TransmogFix's own module hooks.
|
|
- No shared Lua/file/engine/logout/shutdown hooks.
|
|
|
|
weirdperformance.dll
|
|
- Not built here.
|
|
- The final ZIP will use the user's original binary unchanged.
|
|
EOF
|
|
|
|
sha256sum package/DLL/*.dll > package/SHA256SUMS.txt
|
|
|
|
- uses: actions/upload-artifact@v4
|
|
with:
|
|
name: safe-core-v8-debug
|
|
path: package/
|
|
if-no-files-found: error
|