diff --git a/BepInEx/obj/DevourUnlocker.csproj.nuget.dgspec.json b/BepInEx/obj/DevourUnlocker.csproj.nuget.dgspec.json
new file mode 100644
index 0000000..fb55eef
--- /dev/null
+++ b/BepInEx/obj/DevourUnlocker.csproj.nuget.dgspec.json
@@ -0,0 +1,84 @@
+{
+ "format": 1,
+ "restore": {
+ "/home/mithral/Documents/Devour Unlocker FORKED/DevourUnlocker/BepInEx/DevourUnlocker.csproj": {}
+ },
+ "projects": {
+ "/home/mithral/Documents/Devour Unlocker FORKED/DevourUnlocker/BepInEx/DevourUnlocker.csproj": {
+ "version": "2.0.0",
+ "restore": {
+ "projectUniqueName": "/home/mithral/Documents/Devour Unlocker FORKED/DevourUnlocker/BepInEx/DevourUnlocker.csproj",
+ "projectName": "DevourUnlocker",
+ "projectPath": "/home/mithral/Documents/Devour Unlocker FORKED/DevourUnlocker/BepInEx/DevourUnlocker.csproj",
+ "packagesPath": "/home/mithral/.nuget/packages/",
+ "outputPath": "/home/mithral/Documents/Devour Unlocker FORKED/DevourUnlocker/BepInEx/obj/",
+ "projectStyle": "PackageReference",
+ "configFilePaths": [
+ "/home/mithral/.nuget/NuGet/NuGet.Config"
+ ],
+ "originalTargetFrameworks": [
+ "netstandard2.1"
+ ],
+ "sources": {
+ "https://api.nuget.org/v3/index.json": {}
+ },
+ "frameworks": {
+ "netstandard2.1": {
+ "targetAlias": "netstandard2.1",
+ "projectReferences": {}
+ }
+ },
+ "warningProperties": {
+ "warnAsError": [
+ "NU1605"
+ ]
+ },
+ "restoreAuditProperties": {
+ "enableAudit": "true",
+ "auditLevel": "low",
+ "auditMode": "direct"
+ },
+ "SdkAnalysisLevel": "10.0.100"
+ },
+ "frameworks": {
+ "netstandard2.1": {
+ "targetAlias": "netstandard2.1",
+ "dependencies": {
+ "BepInEx.Analyzers": {
+ "suppressParent": "All",
+ "target": "Package",
+ "version": "[1.*, )"
+ },
+ "BepInEx.Core": {
+ "target": "Package",
+ "version": "[6.0.0-be.688, )"
+ }
+ },
+ "imports": [
+ "net461",
+ "net462",
+ "net47",
+ "net471",
+ "net472",
+ "net48",
+ "net481"
+ ],
+ "assetTargetFallback": true,
+ "warn": true,
+ "downloadDependencies": [
+ {
+ "name": "NETStandard.Library.Ref",
+ "version": "[2.1.0, 2.1.0]"
+ }
+ ],
+ "frameworkReferences": {
+ "NETStandard.Library": {
+ "privateAssets": "all"
+ }
+ },
+ "runtimeIdentifierGraphPath": "/usr/share/dotnet/sdk/10.0.111/RuntimeIdentifierGraph.json"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/BepInEx/obj/DevourUnlocker.csproj.nuget.g.props b/BepInEx/obj/DevourUnlocker.csproj.nuget.g.props
new file mode 100644
index 0000000..ad6c82b
--- /dev/null
+++ b/BepInEx/obj/DevourUnlocker.csproj.nuget.g.props
@@ -0,0 +1,15 @@
+
+
+
+ False
+ NuGet
+ $(MSBuildThisFileDirectory)project.assets.json
+ /home/mithral/.nuget/packages/
+ /home/mithral/.nuget/packages/
+ PackageReference
+ 7.0.0
+
+
+
+
+
\ No newline at end of file
diff --git a/BepInEx/obj/DevourUnlocker.csproj.nuget.g.targets b/BepInEx/obj/DevourUnlocker.csproj.nuget.g.targets
new file mode 100644
index 0000000..3dc06ef
--- /dev/null
+++ b/BepInEx/obj/DevourUnlocker.csproj.nuget.g.targets
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/BepInEx/obj/project.assets.json b/BepInEx/obj/project.assets.json
new file mode 100644
index 0000000..0078f94
--- /dev/null
+++ b/BepInEx/obj/project.assets.json
@@ -0,0 +1,112 @@
+{
+ "version": 3,
+ "targets": {
+ ".NETStandard,Version=v2.1": {}
+ },
+ "libraries": {},
+ "projectFileDependencyGroups": {
+ ".NETStandard,Version=v2.1": [
+ "BepInEx.Analyzers >= 1.*",
+ "BepInEx.Core >= 6.0.0-be.688"
+ ]
+ },
+ "packageFolders": {
+ "/home/mithral/.nuget/packages/": {}
+ },
+ "project": {
+ "version": "2.0.0",
+ "restore": {
+ "projectUniqueName": "/home/mithral/Documents/Devour Unlocker FORKED/DevourUnlocker/BepInEx/DevourUnlocker.csproj",
+ "projectName": "DevourUnlocker",
+ "projectPath": "/home/mithral/Documents/Devour Unlocker FORKED/DevourUnlocker/BepInEx/DevourUnlocker.csproj",
+ "packagesPath": "/home/mithral/.nuget/packages/",
+ "outputPath": "/home/mithral/Documents/Devour Unlocker FORKED/DevourUnlocker/BepInEx/obj/",
+ "projectStyle": "PackageReference",
+ "configFilePaths": [
+ "/home/mithral/.nuget/NuGet/NuGet.Config"
+ ],
+ "originalTargetFrameworks": [
+ "netstandard2.1"
+ ],
+ "sources": {
+ "https://api.nuget.org/v3/index.json": {}
+ },
+ "frameworks": {
+ "netstandard2.1": {
+ "targetAlias": "netstandard2.1",
+ "projectReferences": {}
+ }
+ },
+ "warningProperties": {
+ "warnAsError": [
+ "NU1605"
+ ]
+ },
+ "restoreAuditProperties": {
+ "enableAudit": "true",
+ "auditLevel": "low",
+ "auditMode": "direct"
+ },
+ "SdkAnalysisLevel": "10.0.100"
+ },
+ "frameworks": {
+ "netstandard2.1": {
+ "targetAlias": "netstandard2.1",
+ "dependencies": {
+ "BepInEx.Analyzers": {
+ "suppressParent": "All",
+ "target": "Package",
+ "version": "[1.*, )"
+ },
+ "BepInEx.Core": {
+ "target": "Package",
+ "version": "[6.0.0-be.688, )"
+ }
+ },
+ "imports": [
+ "net461",
+ "net462",
+ "net47",
+ "net471",
+ "net472",
+ "net48",
+ "net481"
+ ],
+ "assetTargetFallback": true,
+ "warn": true,
+ "downloadDependencies": [
+ {
+ "name": "NETStandard.Library.Ref",
+ "version": "[2.1.0, 2.1.0]"
+ }
+ ],
+ "frameworkReferences": {
+ "NETStandard.Library": {
+ "privateAssets": "all"
+ }
+ },
+ "runtimeIdentifierGraphPath": "/usr/share/dotnet/sdk/10.0.111/RuntimeIdentifierGraph.json"
+ }
+ }
+ },
+ "logs": [
+ {
+ "code": "NU1101",
+ "level": "Error",
+ "message": "Unable to find package BepInEx.Analyzers. No packages exist with this id in source(s): nuget.org",
+ "libraryId": "BepInEx.Analyzers",
+ "targetGraphs": [
+ ".NETStandard,Version=v2.1"
+ ]
+ },
+ {
+ "code": "NU1101",
+ "level": "Error",
+ "message": "Unable to find package BepInEx.Core. No packages exist with this id in source(s): nuget.org",
+ "libraryId": "BepInEx.Core",
+ "targetGraphs": [
+ ".NETStandard,Version=v2.1"
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/BepInEx/obj/project.nuget.cache b/BepInEx/obj/project.nuget.cache
new file mode 100644
index 0000000..cfa7525
--- /dev/null
+++ b/BepInEx/obj/project.nuget.cache
@@ -0,0 +1,33 @@
+{
+ "version": 2,
+ "dgSpecHash": "77xgSA5MVEU=",
+ "success": false,
+ "projectFilePath": "/home/mithral/Documents/Devour Unlocker FORKED/DevourUnlocker/BepInEx/DevourUnlocker.csproj",
+ "expectedPackageFiles": [
+ "/home/mithral/.nuget/packages/netstandard.library.ref/2.1.0/netstandard.library.ref.2.1.0.nupkg.sha512"
+ ],
+ "logs": [
+ {
+ "code": "NU1101",
+ "level": "Error",
+ "message": "Unable to find package BepInEx.Analyzers. No packages exist with this id in source(s): nuget.org",
+ "projectPath": "/home/mithral/Documents/Devour Unlocker FORKED/DevourUnlocker/BepInEx/DevourUnlocker.csproj",
+ "filePath": "/home/mithral/Documents/Devour Unlocker FORKED/DevourUnlocker/BepInEx/DevourUnlocker.csproj",
+ "libraryId": "BepInEx.Analyzers",
+ "targetGraphs": [
+ ".NETStandard,Version=v2.1"
+ ]
+ },
+ {
+ "code": "NU1101",
+ "level": "Error",
+ "message": "Unable to find package BepInEx.Core. No packages exist with this id in source(s): nuget.org",
+ "projectPath": "/home/mithral/Documents/Devour Unlocker FORKED/DevourUnlocker/BepInEx/DevourUnlocker.csproj",
+ "filePath": "/home/mithral/Documents/Devour Unlocker FORKED/DevourUnlocker/BepInEx/DevourUnlocker.csproj",
+ "libraryId": "BepInEx.Core",
+ "targetGraphs": [
+ ".NETStandard,Version=v2.1"
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 009dd5e..9e6048e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -79,15 +79,16 @@ if(BUILD_WINHTTP_PROXY AND WIN32)
target_link_options(winhttp PRIVATE -static-libgcc -static-libstdc++ -Wl,-Bstatic -lwinpthread -Wl,-Bdynamic)
endif()
+ # version.dll is minimal — just to satisfy loader, unlock is via collectables.json (no IL2CPP hook, no crash)
add_library(version SHARED
src/platform/version_proxy.cpp
- src/main.cpp
+ src/main_version.cpp
)
- target_link_libraries(version PRIVATE devour_core)
+ target_link_libraries(version PRIVATE kernel32)
set_target_properties(version PROPERTIES OUTPUT_NAME "version" PREFIX "" SUFFIX ".dll")
target_compile_definitions(version PRIVATE VERSION_PROXY=1)
if(MINGW)
- target_link_options(version PRIVATE -static-libgcc -static-libstdc++ -Wl,-Bstatic -lwinpthread -Wl,-Bdynamic)
+ target_link_options(version PRIVATE -static-libgcc -static-libstdc++)
endif()
add_library(DevourUnlocker SHARED src/main.cpp)
diff --git a/scripts/install.sh b/scripts/install.sh
index 309ff62..77e5363 100755
--- a/scripts/install.sh
+++ b/scripts/install.sh
@@ -137,8 +137,33 @@ 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"
echo "[*] Installed to $GAME_DIR"
+# Auto-set Steam launch options for Proton (so user doesn't need to do it manually)
if [[ "$OS" == "linux" ]]; then
- echo "[*] Linux/Proton: version.dll is auto-loaded beside DEVOUR.exe (no WINEDLLOVERRIDES needed on native Windows, but on Proton set Steam → Devour → Properties → Launch Options: WINEDLLOVERRIDES=\"version=n,b\" %command% or just use scripts/launch.sh)"
+ # Try to set LaunchOptions in localconfig.vdf for 1274570 to include WINEDLLOVERRIDES
+ for lc in "$HOME/.local/share/Steam/userdata/"*/config/localconfig.vdf; do
+ if [[ -f "$lc" ]] && grep -q "1274570" "$lc"; then
+ # Backup
+ 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 "
+import pathlib, re
+p=pathlib.Path('$lc')
+t=p.read_text(errors='ignore')
+# If LaunchOptions already contains WINEDLLOVERRIDES, leave it
+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]:
+ # 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)
+ open('$lc','w').write(t)
+ print('[*] Auto-set Steam launch options for Devour to WINEDLLOVERRIDES=\"version=n,b\" %command%')
+ " 2>&1 | head -n 5
+ break
+ fi
+ 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 "[*] Or run: bash $(dirname "$0")/launch.sh (auto sets WINEDLLOVERRIDES and launches via Proton)"
else
echo "[*] Windows: version.dll beside DEVOUR.exe is auto-loaded — no launch option needed. Just launch Devour."
diff --git a/src/main.cpp b/src/main.cpp
index adbf3a2..afbf370 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -12,9 +12,8 @@ static void logMin(const char* m){
}
static DWORD WINAPI HookThread(LPVOID){
logMin("[DevourUnlocker] HookThread start (always-on)");
- // Wait for GameAssembly before hooking
for(int i=0;i<100;i++){ if(GetModuleHandleA("GameAssembly.dll")) break; Sleep(100); }
- Sleep(2000); // give IL2CPP time to init
+ Sleep(2000);
bool ok = devour::installPatches();
logMin(ok ? "[DevourUnlocker] HookThread: patches installed" : "[DevourUnlocker] HookThread: patches not yet, will retry via installPatches retry thread");
return 0;
diff --git a/src/main_version.cpp b/src/main_version.cpp
new file mode 100644
index 0000000..b3f3d91
--- /dev/null
+++ b/src/main_version.cpp
@@ -0,0 +1,14 @@
+#ifdef _WIN32
+#include
+BOOL APIENTRY DllMain(HMODULE hMod, DWORD reason, LPVOID) {
+ if (reason == DLL_PROCESS_ATTACH) {
+ DisableThreadLibraryCalls(hMod);
+ // Minimal version.dll — no hooks, just to satisfy loader
+ // Unlock is via collectables.json (patched by standalone) which is always-on
+ }
+ return TRUE;
+}
+#else
+#include
+__attribute__((constructor)) void devour_init() {}
+#endif
diff --git a/standalone/devour_unlocker.py b/standalone/devour_unlocker.py
index 0e5add3..93800f3 100755
--- a/standalone/devour_unlocker.py
+++ b/standalone/devour_unlocker.py
@@ -228,7 +228,7 @@ def cmd_diagnose(args):
for c in devour_paths():
if (c / "DEVOUR.exe").exists():
gd=c; break
- for dll in ["winhttp.dll","DevourUnlocker.dll","libgcc_s_seh-1.dll","libstdc++-6.dll"]:
+ for dll in ["version.dll","winhttp.dll","DevourUnlocker.dll","libgcc_s_seh-1.dll","libstdc++-6.dll"]:
if gd:
print(f"{dll} at {gd/dll} exists={(gd/dll).exists()}")
if (gd/dll).exists():