version.dll is now sole unlocker — full hooks, no user WINEDLLOVERRIDES needed
- UnityPlayer.dll imports VERSION.dll + WINHTTP.dll (objdump -p) — version.dll beside DEVOUR.exe is auto-loaded on Windows, installer now silently auto-sets WINEDLLOVERRIDES=version=n,b in Steam localconfig.vdf for Proton so user just presses Play - src/main_version.cpp: now full HookThread (wait GameAssembly.dll + installPatches) linking devour_core (was minimal no-hooks 103K, now 14M full like winhttp) — unlocks all categories: robes/characters/perks/pets/flashlights/emotes/outfits via IsRobe/IsCharacter/HasPerk/HasOutfit + UpdateLocked* hooks - CMakeLists.txt: version target links devour_core + winpthread static, primary = version.dll less flagged than winhttp; winhttp retained only as optional compat - scripts/install.sh: copy version.dll primary (all categories), auto-set LaunchOptions silent, message no manual step; scripts/launch.sh: now uses version=n,b auto, checks version.dll - standalone/injector.py: find_built_dlls prefers version.dll, ensure_mod_deployed deploys version primary; standalone/devour_unlocker.py: diagnose hints updated to version.dll - .github/workflows/build.yml: runs-on docker (Forgejo runner media-server labels docker v6.4.0), package version.dll primary zip, linux job also docker
This commit is contained in:
parent
8119cdf686
commit
1e0f727ab7
8 changed files with 95 additions and 66 deletions
16
.github/workflows/build.yml
vendored
16
.github/workflows/build.yml
vendored
|
|
@ -7,10 +7,9 @@ on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
# media-server is the only runner on git.mithraic.cloud (no windows-latest/ubuntu-latest). Forgejo Act: runs-on must exactly match runner labels.
|
# git.mithraic.cloud Forgejo runner: name media-server, labels [docker] (v6.4.0). Use `docker` to match.
|
||||||
windows-cross:
|
windows-cross:
|
||||||
runs-on: media-server
|
runs-on: docker
|
||||||
continue-on-error: true
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with: { submodules: recursive }
|
with: { submodules: recursive }
|
||||||
|
|
@ -28,16 +27,17 @@ jobs:
|
||||||
- name: Package
|
- name: Package
|
||||||
run: |
|
run: |
|
||||||
mkdir -p dist
|
mkdir -p dist
|
||||||
cp build/winhttp.dll dist/ 2>/dev/null || cp build/*.dll dist/ 2>/dev/null || echo "no dll built (expected on cross without win32 SDK)"
|
cp build/version.dll dist/ 2>/dev/null || echo "no version.dll"
|
||||||
|
cp build/winhttp.dll dist/ 2>/dev/null || true
|
||||||
cp build/DevourUnlocker.dll dist/ 2>/dev/null || true
|
cp build/DevourUnlocker.dll dist/ 2>/dev/null || true
|
||||||
cp DevourUnlocker.json dist/ 2>/dev/null || echo '{"unlockRobes":true,"unlockCharacters":true,"unlockPerks":true,"unlockPets":true,"unlockFlashlights":true,"unlockEmotes":true,"unlockOutfits":true}' > dist/DevourUnlocker.json
|
cp DevourUnlocker.json dist/ 2>/dev/null || echo '{"unlockRobes":true,"unlockCharacters":true,"unlockPerks":true,"unlockPets":true,"unlockFlashlights":true,"unlockEmotes":true,"unlockOutfits":true}' > dist/DevourUnlocker.json
|
||||||
zip -j DevourUnlocker_winhttp_${{ github.ref_name }}.zip dist/* || true
|
zip -j DevourUnlocker_version_${{ github.ref_name }}.zip dist/* || zip -j DevourUnlocker_winhttp_${{ github.ref_name }}.zip dist/* || true
|
||||||
ls -lh dist/
|
ls -lh dist/
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
with: { name: winhttp-cross, path: DevourUnlocker_winhttp_*.zip }
|
with: { name: version-cross, path: DevourUnlocker_version_*.zip }
|
||||||
|
|
||||||
linux:
|
linux:
|
||||||
runs-on: media-server
|
runs-on: docker
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Install deps if apt
|
- name: Install deps if apt
|
||||||
|
|
@ -51,7 +51,7 @@ jobs:
|
||||||
with: { name: linux-so, path: build/*.so }
|
with: { name: linux-so, path: build/*.so }
|
||||||
|
|
||||||
standalone:
|
standalone:
|
||||||
runs-on: media-server
|
runs-on: docker
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- run: python3 -m py_compile standalone/devour_unlocker.py standalone/gui.py tools/dump_metadata.py standalone/injector.py 2>&1 || python3 -m py_compile standalone/devour_unlocker.py standalone/gui.py tools/dump_metadata.py
|
- run: python3 -m py_compile standalone/devour_unlocker.py standalone/gui.py tools/dump_metadata.py standalone/injector.py 2>&1 || python3 -m py_compile standalone/devour_unlocker.py standalone/gui.py tools/dump_metadata.py
|
||||||
|
|
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -33,6 +33,10 @@ BepInEx/config/
|
||||||
standalone/dist/
|
standalone/dist/
|
||||||
standalone/build/
|
standalone/build/
|
||||||
|
|
||||||
|
# BepInEx build
|
||||||
|
BepInEx/obj/
|
||||||
|
BepInEx/bin/
|
||||||
|
|
||||||
# IDE
|
# IDE
|
||||||
*.user
|
*.user
|
||||||
*.suo
|
*.suo
|
||||||
|
|
|
||||||
|
|
@ -79,16 +79,16 @@ if(BUILD_WINHTTP_PROXY AND WIN32)
|
||||||
target_link_options(winhttp PRIVATE -static-libgcc -static-libstdc++ -Wl,-Bstatic -lwinpthread -Wl,-Bdynamic)
|
target_link_options(winhttp PRIVATE -static-libgcc -static-libstdc++ -Wl,-Bstatic -lwinpthread -Wl,-Bdynamic)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# version.dll is minimal — just to satisfy loader, unlock is via collectables.json (no IL2CPP hook, no crash)
|
# version.dll is primary unlocker — full hooks (all categories) + proxy, no WINEDLLOVERRIDES needed for user (installer handles it silently)
|
||||||
add_library(version SHARED
|
add_library(version SHARED
|
||||||
src/platform/version_proxy.cpp
|
src/platform/version_proxy.cpp
|
||||||
src/main_version.cpp
|
src/main_version.cpp
|
||||||
)
|
)
|
||||||
target_link_libraries(version PRIVATE kernel32)
|
target_link_libraries(version PRIVATE devour_core kernel32)
|
||||||
set_target_properties(version PROPERTIES OUTPUT_NAME "version" PREFIX "" SUFFIX ".dll")
|
set_target_properties(version PROPERTIES OUTPUT_NAME "version" PREFIX "" SUFFIX ".dll")
|
||||||
target_compile_definitions(version PRIVATE VERSION_PROXY=1)
|
target_compile_definitions(version PRIVATE VERSION_PROXY=1)
|
||||||
if(MINGW)
|
if(MINGW)
|
||||||
target_link_options(version PRIVATE -static-libgcc -static-libstdc++)
|
target_link_options(version PRIVATE -static-libgcc -static-libstdc++ -Wl,-Bstatic -lwinpthread -Wl,-Bdynamic)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_library(DevourUnlocker SHARED src/main.cpp)
|
add_library(DevourUnlocker SHARED src/main.cpp)
|
||||||
|
|
|
||||||
|
|
@ -120,9 +120,9 @@ for dll in version.dll winhttp.dll; do
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# Prefer version.dll (less flagged) — copy both for compat
|
# version.dll is sole unlocker (full hooks, less flagged than winhttp) — winhttp kept only as optional compat
|
||||||
if [[ -f "$TMP/version.dll" ]]; then cp -v "$TMP/version.dll" "$GAME_DIR/version.dll"; echo "[*] Installed version.dll (primary, less detectable)"; fi
|
if [[ -f "$TMP/version.dll" ]]; then cp -v "$TMP/version.dll" "$GAME_DIR/version.dll"; echo "[*] Installed version.dll (primary unlocker — all categories)"; fi
|
||||||
if [[ -f "$TMP/winhttp.dll" ]]; then cp -v "$TMP/winhttp.dll" "$GAME_DIR/winhttp.dll"; echo "[*] Installed winhttp.dll (compat)"; fi
|
if [[ -f "$TMP/winhttp.dll" ]]; then cp -v "$TMP/winhttp.dll" "$GAME_DIR/winhttp.dll"; echo "[*] Installed winhttp.dll (optional compat, not needed)"; fi
|
||||||
cp -v "$TMP/DevourUnlocker.dll" "$GAME_DIR/DevourUnlocker.dll" 2>/dev/null || true
|
cp -v "$TMP/DevourUnlocker.dll" "$GAME_DIR/DevourUnlocker.dll" 2>/dev/null || true
|
||||||
# Record GameAssembly hash for future update checks
|
# Record GameAssembly hash for future update checks
|
||||||
GA_SHA=$(sha1sum "$GAME_DIR/GameAssembly.dll" 2>/dev/null | cut -d' ' -f1 || echo "")
|
GA_SHA=$(sha1sum "$GAME_DIR/GameAssembly.dll" 2>/dev/null | cut -d' ' -f1 || echo "")
|
||||||
|
|
@ -137,36 +137,29 @@ echo "[*] Patching Steam Cloud collectables.json (proper game call: HasCollected
|
||||||
python3 "$(dirname "$0")/../standalone/devour_unlocker.py" unlock --all 2>&1 | tail -n 20 || echo "[!] Could not patch collectables.json — will still unlock via runtime hook"
|
python3 "$(dirname "$0")/../standalone/devour_unlocker.py" unlock --all 2>&1 | tail -n 20 || echo "[!] Could not patch collectables.json — will still unlock via runtime hook"
|
||||||
|
|
||||||
echo "[*] Installed to $GAME_DIR"
|
echo "[*] Installed to $GAME_DIR"
|
||||||
# Auto-set Steam launch options for Proton (so user doesn't need to do it manually)
|
# Auto-set Steam launch options for Proton silently (so user never needs manual WINEDLLOVERRIDES)
|
||||||
if [[ "$OS" == "linux" ]]; then
|
if [[ "$OS" == "linux" ]]; then
|
||||||
# Try to set LaunchOptions in localconfig.vdf for 1274570 to include WINEDLLOVERRIDES
|
|
||||||
for lc in "$HOME/.local/share/Steam/userdata/"*/config/localconfig.vdf; do
|
for lc in "$HOME/.local/share/Steam/userdata/"*/config/localconfig.vdf; do
|
||||||
if [[ -f "$lc" ]] && grep -q "1274570" "$lc"; then
|
if [[ -f "$lc" ]] && grep -q "1274570" "$lc"; then
|
||||||
# Backup
|
|
||||||
cp "$lc" "$lc.bak.$(date +%s)" 2>/dev/null || true
|
cp "$lc" "$lc.bak.$(date +%s)" 2>/dev/null || true
|
||||||
# Use python to edit VDF (VDF is not JSON, but we can do crude sed for LaunchOptions)
|
|
||||||
python3 -c "
|
python3 -c "
|
||||||
import pathlib, re
|
import pathlib
|
||||||
p=pathlib.Path('$lc')
|
p=pathlib.Path('$lc')
|
||||||
t=p.read_text(errors='ignore')
|
t=p.read_text(errors='ignore')
|
||||||
# If LaunchOptions already contains WINEDLLOVERRIDES, leave it
|
|
||||||
if 'WINEDLLOVERRIDES' not in t:
|
if 'WINEDLLOVERRIDES' not in t:
|
||||||
# Find \"1274570\" block and add LaunchOptions
|
|
||||||
# VDF snippet for 1274570 is like \"1274570\" { ... \"LaunchOptions\" \"...\" }
|
|
||||||
# If LaunchOptions not present, add it
|
|
||||||
if '\"LaunchOptions\"' not in t.split('\"1274570\"')[1].split('}')[0]:
|
if '\"LaunchOptions\"' not in t.split('\"1274570\"')[1].split('}')[0]:
|
||||||
# Insert LaunchOptions after 1274570 block start
|
|
||||||
t=t.replace('\"1274570\"', '\"1274570\"\n\t\t\t\t\"LaunchOptions\"\t\t\"WINEDLLOVERRIDES=version=n,b %command%\"', 1)
|
t=t.replace('\"1274570\"', '\"1274570\"\n\t\t\t\t\"LaunchOptions\"\t\t\"WINEDLLOVERRIDES=version=n,b %command%\"', 1)
|
||||||
open('$lc','w').write(t)
|
pathlib.Path('$lc').write_text(t)
|
||||||
print('[*] Auto-set Steam launch options for Devour to WINEDLLOVERRIDES=\"version=n,b\" %command%')
|
print('[*] Auto-set Steam launch options for Devour to WINEDLLOVERRIDES=\"version=n,b\" %command% (silent, no user action needed)')
|
||||||
" 2>&1 | head -n 5
|
" 2>&1 | head -n 5
|
||||||
break
|
break
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
echo "[*] Linux/Proton: version.dll is auto-loaded beside DEVOUR.exe (if LaunchOptions not auto-set, set Steam → Devour → Properties → Launch Options: WINEDLLOVERRIDES=\"version=n,b\" %command% or just use scripts/launch.sh)"
|
echo "[*] Linux/Proton: version.dll is sole unlocker beside DEVOUR.exe — Steam Launch Options now auto-set, just press Play. No manual WINEDLLOVERRIDES needed."
|
||||||
echo "[*] Or run: bash $(dirname "$0")/launch.sh (auto sets WINEDLLOVERRIDES and launches via Proton)"
|
echo "[*] Fallback: bash $(dirname "$0")/launch.sh (also auto-sets WINEDLLOVERRIDES)"
|
||||||
else
|
else
|
||||||
echo "[*] Windows: version.dll beside DEVOUR.exe is auto-loaded — no launch option needed. Just launch Devour."
|
echo "[*] Windows: version.dll beside DEVOUR.exe is auto-loaded (UnityPlayer.dll imports VERSION.dll) — no launch option needed. Just launch Devour."
|
||||||
fi
|
fi
|
||||||
|
echo "[*] version.dll = full unlock (robes/characters/perks/pets/flashlights/emotes/outfits) — go in game, everything unlocked"
|
||||||
echo "[*] Verify: python $(dirname "$0")/../standalone/devour_unlocker.py diagnose"
|
echo "[*] Verify: python $(dirname "$0")/../standalone/devour_unlocker.py diagnose"
|
||||||
rm -rf "$TMP"
|
rm -rf "$TMP"
|
||||||
|
|
|
||||||
|
|
@ -10,20 +10,20 @@ if [[ ! -f "$GAME_DIR/DEVOUR.exe" ]]; then
|
||||||
echo "[!] No DEVOUR.exe at $GAME_DIR — set GAME_DIR=/path"
|
echo "[!] No DEVOUR.exe at $GAME_DIR — set GAME_DIR=/path"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
if [[ ! -f "$GAME_DIR/winhttp.dll" ]]; then
|
if [[ ! -f "$GAME_DIR/version.dll" ]]; then
|
||||||
echo "[!] winhttp.dll not found beside DEVOUR.exe — running injector --deploy-only..."
|
echo "[!] version.dll not found beside DEVOUR.exe — running injector --deploy-only..."
|
||||||
python3 "$(dirname "$0")/../standalone/injector.py" --deploy-only || true
|
python3 "$(dirname "$0")/../standalone/injector.py" --deploy-only || true
|
||||||
fi
|
fi
|
||||||
if [[ ! -f "$GAME_DIR/winhttp.dll" ]]; then
|
if [[ ! -f "$GAME_DIR/version.dll" ]]; then
|
||||||
echo "[!] Still no winhttp.dll — build or run scripts/install.sh"
|
echo "[!] Still no version.dll — build or run scripts/install.sh"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "[*] Game: $GAME_DIR"
|
echo "[*] Game: $GAME_DIR"
|
||||||
echo "[*] Prefix: $PREFX"
|
echo "[*] Prefix: $PREFX"
|
||||||
echo "[*] Proton: $PROTON"
|
echo "[*] Proton: $PROTON"
|
||||||
echo "[*] Launching with WINEDLLOVERRIDES=\"winhttp=n,b\" — check $GAME_DIR/DevourUnlocker.log after"
|
echo "[*] Launching with version.dll (primary unlocker) — no manual Steam Launch Options needed if installed via install.sh"
|
||||||
echo "[*] If Steam launch, instead set: Steam → Devour → Properties → Launch Options: WINEDLLOVERRIDES=\"winhttp=n,b\" %command%"
|
echo "[*] Check $GAME_DIR/DevourUnlocker.log after"
|
||||||
|
|
||||||
if [[ "${1:-}" == "--diagnose" ]]; then
|
if [[ "${1:-}" == "--diagnose" ]]; then
|
||||||
python3 "$(dirname "$0")/../standalone/devour_unlocker.py" diagnose
|
python3 "$(dirname "$0")/../standalone/devour_unlocker.py" diagnose
|
||||||
|
|
@ -34,7 +34,13 @@ export WINEPREFIX="$PREFX"
|
||||||
export STEAM_COMPAT_DATA_PATH="$HOME/.local/share/Steam/steamapps/compatdata/1274570"
|
export STEAM_COMPAT_DATA_PATH="$HOME/.local/share/Steam/steamapps/compatdata/1274570"
|
||||||
export STEAM_COMPAT_CLIENT_INSTALL_PATH="$HOME/.local/share/Steam"
|
export STEAM_COMPAT_CLIENT_INSTALL_PATH="$HOME/.local/share/Steam"
|
||||||
export SteamAppId=1274570
|
export SteamAppId=1274570
|
||||||
export WINEDLLOVERRIDES="winhttp=n,b"
|
# version.dll is primary unlocker (UnityPlayer.dll imports VERSION.dll, so native version.dll in game dir is auto-loaded on Windows;
|
||||||
|
# on Proton/Wine we still set WINEDLLOVERRIDES silently so user never needs to set it manually)
|
||||||
|
if [[ -z "${WINEDLLOVERRIDES:-}" ]]; then
|
||||||
|
export WINEDLLOVERRIDES="version=n,b"
|
||||||
|
else
|
||||||
|
export WINEDLLOVERRIDES="version=n,b;${WINEDLLOVERRIDES}"
|
||||||
|
fi
|
||||||
export WINEDEBUG=-all
|
export WINEDEBUG=-all
|
||||||
|
|
||||||
# Kill stale wineserver
|
# Kill stale wineserver
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,27 @@
|
||||||
|
#include "config.hpp"
|
||||||
|
#include "patches.hpp"
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <fstream>
|
||||||
|
static void logVer(const char* m){
|
||||||
|
char exe[MAX_PATH]; GetModuleFileNameA(nullptr,exe,MAX_PATH);
|
||||||
|
char* s=strrchr(exe,'\\'); if(!s) s=strrchr(exe,'/');
|
||||||
|
std::string p = s? std::string(exe,s-exe)+"\\DevourUnlocker.log":"DevourUnlocker.log";
|
||||||
|
std::ofstream f(p,std::ios::app); f<<m<<std::endl;
|
||||||
|
}
|
||||||
|
static DWORD WINAPI HookThreadVer(LPVOID){
|
||||||
|
logVer("[DevourUnlocker version.dll] HookThread start (always-on full unlock)");
|
||||||
|
for(int i=0;i<200;i++){ if(GetModuleHandleA("GameAssembly.dll")) break; Sleep(100); }
|
||||||
|
Sleep(2000);
|
||||||
|
bool ok = devour::installPatches();
|
||||||
|
logVer(ok ? "[DevourUnlocker version.dll] patches installed — all categories unlocked" : "[DevourUnlocker version.dll] patches not yet, retrying via installPatches retry thread");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
BOOL APIENTRY DllMain(HMODULE hMod, DWORD reason, LPVOID) {
|
BOOL APIENTRY DllMain(HMODULE hMod, DWORD reason, LPVOID) {
|
||||||
if (reason == DLL_PROCESS_ATTACH) {
|
if (reason == DLL_PROCESS_ATTACH) {
|
||||||
DisableThreadLibraryCalls(hMod);
|
DisableThreadLibraryCalls(hMod);
|
||||||
// Minimal version.dll — no hooks, just to satisfy loader
|
logVer("[DevourUnlocker version.dll] DllMain attach (always-on)");
|
||||||
// Unlock is via collectables.json (patched by standalone) which is always-on
|
CreateThread(nullptr,0,HookThreadVer,nullptr,0,nullptr);
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -164,8 +164,8 @@ def cmd_unlock(args):
|
||||||
try:
|
try:
|
||||||
import injector
|
import injector
|
||||||
injector.ensure_mod_deployed(verbose=True)
|
injector.ensure_mod_deployed(verbose=True)
|
||||||
print("[*] Mod DLLs ensured — launch with WINEDLLOVERRIDES=\"winhttp=n,b\" %command% or run: python standalone/injector.py")
|
print("[*] version.dll (sole unlocker) ensured — just launch Devour from Steam (no manual WINEDLLOVERRIDES needed, install.sh auto-sets it on Proton)")
|
||||||
print("[*] Also patched collectables.json directly — standalone should now work even without DLL after Steam Cloud sync")
|
print("[*] Also patched collectables.json directly — robes unlocked even without DLL after Steam Cloud sync")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[!] Could not auto-deploy mod: {e}")
|
print(f"[!] Could not auto-deploy mod: {e}")
|
||||||
return
|
return
|
||||||
|
|
@ -192,15 +192,14 @@ def cmd_unlock(args):
|
||||||
cfg["perkOverrides"] = {p: False for p in PERKS}
|
cfg["perkOverrides"] = {p: False for p in PERKS}
|
||||||
cfg["petOverrides"] = {p: False for p in PETS}
|
cfg["petOverrides"] = {p: False for p in PETS}
|
||||||
save_config(args.json, cfg)
|
save_config(args.json, cfg)
|
||||||
print("[*] Now launch Devour with winhttp.dll — selective unlock active via DevourUnlocker.json")
|
print("[*] Now launch Devour with version.dll (sole unlocker) — selective unlock active via DevourUnlocker.json")
|
||||||
try:
|
try:
|
||||||
import injector
|
import injector
|
||||||
ok = injector.ensure_mod_deployed(verbose=False)
|
ok = injector.ensure_mod_deployed(verbose=False)
|
||||||
if not ok:
|
if not ok:
|
||||||
print("[!] winhttp.dll not deployed — run: python standalone/injector.py --deploy-only")
|
print("[!] version.dll not deployed — run: python standalone/injector.py --deploy-only or bash scripts/install.sh")
|
||||||
else:
|
else:
|
||||||
# also ensure launch hint
|
print("[*] version.dll deployed — just launch Devour (no manual WINEDLLOVERRIDES needed)")
|
||||||
print("[*] Mod deployed — ensure Steam launch options: WINEDLLOVERRIDES=\"winhttp=n,b\" %command%")
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[!] diagnose: {e}")
|
print(f"[!] diagnose: {e}")
|
||||||
|
|
||||||
|
|
@ -241,13 +240,13 @@ def cmd_diagnose(args):
|
||||||
print("\n[!] Pets not hooked — IL2CPP not ready at first try. The retry thread should handle it, but if you see 'not found' after 10s, try restarting game or use BepInEx.")
|
print("\n[!] Pets not hooked — IL2CPP not ready at first try. The retry thread should handle it, but if you see 'not found' after 10s, try restarting game or use BepInEx.")
|
||||||
else:
|
else:
|
||||||
print(f"\n[!] No DevourUnlocker.log at {log} — DLL never loaded.")
|
print(f"\n[!] No DevourUnlocker.log at {log} — DLL never loaded.")
|
||||||
print(" Fixes: 1) Ensure winhttp.dll is beside DEVOUR.exe (run: python standalone/injector.py --deploy-only)")
|
print(" Fixes: 1) Ensure version.dll is beside DEVOUR.exe (run: python standalone/injector.py --deploy-only or bash scripts/install.sh)")
|
||||||
print(" 2) Set Steam launch options: WINEDLLOVERRIDES=\"winhttp=n,b\" %command%")
|
print(" 2) On Windows: version.dll is auto-loaded (UnityPlayer.dll imports VERSION.dll). On Proton, install.sh auto-sets Steam Launch Options to WINEDLLOVERRIDES=\"version=n,b\" %command% — no manual step needed")
|
||||||
print(" 3) Or run: bash scripts/launch.sh (auto sets WINEDLLOVERRIDES and launches via Proton)")
|
print(" 3) Or run: bash scripts/launch.sh (auto sets WINEDLLOVERRIDES and launches via Proton)")
|
||||||
# env check
|
# env check
|
||||||
print(f"\nENV WINEDLLOVERRIDES={os.environ.get('WINEDLLOVERRIDES','<not set>')}")
|
print(f"\nENV WINEDLLOVERRIDES={os.environ.get('WINEDLLOVERRIDES','<not set>')}")
|
||||||
print("Steam launch options are stored in localconfig.vdf — check Steam UI if not set")
|
print("Steam launch options are stored in localconfig.vdf — check Steam UI if not set (install.sh now auto-sets it for version.dll)")
|
||||||
print("\n[Hint] For Proton, set Steam → Devour → Properties → Launch Options: WINEDLLOVERRIDES=\"winhttp=n,b\" %command%")
|
print("\n[Hint] version.dll is sole unlocker — just launch Devour from Steam after install.sh. No manual WINEDLLOVERRIDES needed.")
|
||||||
print("Or run: python standalone/injector.py (auto-deploys + launches) or bash scripts/launch.sh")
|
print("Or run: python standalone/injector.py (auto-deploys + launches) or bash scripts/launch.sh")
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,8 @@ def find_built_dlls():
|
||||||
]
|
]
|
||||||
dlls = {}
|
dlls = {}
|
||||||
for r in roots:
|
for r in roots:
|
||||||
|
if (r / "version.dll").exists():
|
||||||
|
dlls["version"] = r / "version.dll"
|
||||||
if (r / "winhttp.dll").exists():
|
if (r / "winhttp.dll").exists():
|
||||||
dlls["winhttp"] = r / "winhttp.dll"
|
dlls["winhttp"] = r / "winhttp.dll"
|
||||||
if (r / "DevourUnlocker.dll").exists():
|
if (r / "DevourUnlocker.dll").exists():
|
||||||
|
|
@ -57,13 +59,13 @@ def ensure_mod_deployed(game_dir: pathlib.Path = None, verbose=True):
|
||||||
if not game_dir or not game_dir.exists():
|
if not game_dir or not game_dir.exists():
|
||||||
print(f"[!] Could not find Devour at {game_dir}")
|
print(f"[!] Could not find Devour at {game_dir}")
|
||||||
return False
|
return False
|
||||||
# Need winhttp.dll + DevourUnlocker.dll — build if missing
|
# Need version.dll (primary) — build if missing
|
||||||
dlls = find_built_dlls()
|
dlls = find_built_dlls()
|
||||||
# If no built DLLs, try to build or fetch
|
# If no built DLLs, try to build or fetch
|
||||||
if "winhttp" not in dlls:
|
if "version" not in dlls and "winhttp" not in dlls:
|
||||||
# Try to build via mingw if available
|
# Try to build via mingw if available
|
||||||
if verbose:
|
if verbose:
|
||||||
print("[*] No winhttp.dll found, attempting mingw cross-build...")
|
print("[*] No version.dll found, attempting mingw cross-build...")
|
||||||
try:
|
try:
|
||||||
# Use dedicated win_build dir to avoid clobbering linux build
|
# Use dedicated win_build dir to avoid clobbering linux build
|
||||||
subprocess.run(["cmake", "-B", "/tmp/devour_win_build", "-DCMAKE_BUILD_TYPE=Release", "-DCMAKE_SYSTEM_NAME=Windows",
|
subprocess.run(["cmake", "-B", "/tmp/devour_win_build", "-DCMAKE_BUILD_TYPE=Release", "-DCMAKE_SYSTEM_NAME=Windows",
|
||||||
|
|
@ -71,13 +73,13 @@ def ensure_mod_deployed(game_dir: pathlib.Path = None, verbose=True):
|
||||||
cwd=pathlib.Path(__file__).parent.parent, check=False, capture_output=True, timeout=60)
|
cwd=pathlib.Path(__file__).parent.parent, check=False, capture_output=True, timeout=60)
|
||||||
subprocess.run(["cmake", "--build", "/tmp/devour_win_build"], cwd=pathlib.Path(__file__).parent.parent, check=False, capture_output=True, timeout=180)
|
subprocess.run(["cmake", "--build", "/tmp/devour_win_build"], cwd=pathlib.Path(__file__).parent.parent, check=False, capture_output=True, timeout=180)
|
||||||
dlls = find_built_dlls()
|
dlls = find_built_dlls()
|
||||||
if "winhttp" in dlls and verbose:
|
if ("version" in dlls or "winhttp" in dlls) and verbose:
|
||||||
print(f"[*] Built {dlls['winhttp']}")
|
print(f"[*] Built {dlls.get('version', dlls.get('winhttp'))}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if verbose:
|
if verbose:
|
||||||
print(f"[!] Build failed: {e}")
|
print(f"[!] Build failed: {e}")
|
||||||
# Fallback: try to fetch prebuilt via install.sh (requires release)
|
# Fallback: try to fetch prebuilt via install.sh (requires release)
|
||||||
if "winhttp" not in dlls and verbose:
|
if "version" not in dlls and "winhttp" not in dlls and verbose:
|
||||||
print("[*] No local build — trying install.sh fetch from git.mithraic.cloud release...")
|
print("[*] No local build — trying install.sh fetch from git.mithraic.cloud release...")
|
||||||
try:
|
try:
|
||||||
script = pathlib.Path(__file__).parent.parent / "scripts/install.sh"
|
script = pathlib.Path(__file__).parent.parent / "scripts/install.sh"
|
||||||
|
|
@ -96,21 +98,29 @@ def ensure_mod_deployed(game_dir: pathlib.Path = None, verbose=True):
|
||||||
print(f"[+] Copied {json_src} -> {json_dst}")
|
print(f"[+] Copied {json_src} -> {json_dst}")
|
||||||
|
|
||||||
deployed = False
|
deployed = False
|
||||||
if "winhttp" in dlls:
|
# Deploy version.dll primary
|
||||||
target = game_dir / "winhttp.dll"
|
if "version" in dlls:
|
||||||
|
target = game_dir / "version.dll"
|
||||||
if not target.exists():
|
if not target.exists():
|
||||||
shutil.copy(dlls["winhttp"], target)
|
shutil.copy(dlls["version"], target)
|
||||||
if verbose:
|
if verbose:
|
||||||
print(f"[+] Deployed {dlls['winhttp']} -> {target}")
|
print(f"[+] Deployed {dlls['version']} -> {target}")
|
||||||
deployed = True
|
deployed = True
|
||||||
else:
|
else:
|
||||||
if verbose:
|
if verbose:
|
||||||
print(f"[*] winhttp.dll already at {target}")
|
print(f"[*] version.dll already at {target}")
|
||||||
deployed = True
|
deployed = True
|
||||||
else:
|
# Also deploy winhttp for compat if built
|
||||||
|
if "winhttp" in dlls:
|
||||||
|
target2 = game_dir / "winhttp.dll"
|
||||||
|
if not target2.exists():
|
||||||
|
shutil.copy(dlls["winhttp"], target2)
|
||||||
if verbose:
|
if verbose:
|
||||||
print(f"[!] winhttp.dll not built — run on Windows or build with mingw-w64. Standalone JSON-only will NOT unlock until DLL is present.")
|
print(f"[+] Deployed compat {dlls['winhttp']} -> {target2}")
|
||||||
print(f" Workaround: use --steam-stats method or run install.sh which fetches prebuilt release")
|
if not deployed:
|
||||||
|
if verbose:
|
||||||
|
print(f"[!] version.dll not built — run on Windows or build with mingw-w64. Standalone JSON-only will NOT unlock until DLL is present.")
|
||||||
|
print(f" Run: bash scripts/install.sh which fetches prebuilt release")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if "unlocker" in dlls:
|
if "unlocker" in dlls:
|
||||||
|
|
@ -141,13 +151,13 @@ def launch_with_mod(game_dir: pathlib.Path = None):
|
||||||
# Proton launch hint
|
# Proton launch hint
|
||||||
print("\n=== LAUNCH ===")
|
print("\n=== LAUNCH ===")
|
||||||
if os.name == "nt":
|
if os.name == "nt":
|
||||||
print(f"Launching {game_dir / 'DEVOUR.exe'}")
|
print(f"Launching {game_dir / 'DEVOUR.exe'} (version.dll auto-loaded)")
|
||||||
subprocess.Popen([str(game_dir / "DEVOUR.exe")], cwd=str(game_dir))
|
subprocess.Popen([str(game_dir / "DEVOUR.exe")], cwd=str(game_dir))
|
||||||
else:
|
else:
|
||||||
# Linux: set WINEDLLOVERRIDES and ask Steam to launch, or direct proton run
|
# Linux: version.dll is sole unlocker, installer auto-sets WINEDLLOVERRIDES silently
|
||||||
print(f"Game dir: {game_dir}")
|
print(f"Game dir: {game_dir}")
|
||||||
print(f"Ensure Steam launch options: WINEDLLOVERRIDES=\"winhttp=n,b\" %command%")
|
print(f"version.dll is primary unlocker — installed beside DEVOUR.exe, auto-loaded. No manual Steam Launch Options needed if installed via scripts/install.sh")
|
||||||
print(f"Then launch Devour from Steam. Or run: steam steam://rungameid/1274570")
|
print(f"Fallback via launch.sh: bash scripts/launch.sh")
|
||||||
# Try to launch via steam if available
|
# Try to launch via steam if available
|
||||||
try:
|
try:
|
||||||
subprocess.Popen(["steam", "steam://rungameid/1274570"])
|
subprocess.Popen(["steam", "steam://rungameid/1274570"])
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue