Skip to content

Commit 356a398

Browse files
alantangok125hz
authored andcommitted
Compatibility: detect IL2CPP beside a selected nested executable (#540)
The automatic “Pause threads fully” setting detects Unity IL2CPP by looking for GameAssembly.dll beside the entry’s path. A Steam entry points at its install folder, so a direct launch of `bin/game.exe` misses `bin/GameAssembly.dll` and can leave real suspension disabled.
1 parent d0cd68c commit 356a398

3 files changed

Lines changed: 88 additions & 2 deletions

File tree

‎app/Madeira/LibraryBCD.swift‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,21 @@ enum BCDLaunch {
114114
return nil
115115
}
116116

117-
/// A Unity IL2CPP build keeps GameAssembly.dll next to its exe. A Steam entry's
118-
/// path is its install folder; another entry's is the exe.
117+
/// A Unity IL2CPP build keeps GameAssembly.dll next to its exe. A direct Steam
118+
/// launch can select an exe below its install folder; Dock keeps the root check.
119119
static func isUnityIL2CPP(_ entry: LibraryEntry) -> Bool {
120120
guard let url = LibraryEntry.hostURL(ofWindowsPath: entry.windowsPath) else { return false }
121121
var isDir: ObjCBool = false
122122
let fm = FileManager.default
123123
let folder = fm.fileExists(atPath: url.path, isDirectory: &isDir) && isDir.boolValue ? url : url.deletingLastPathComponent()
124+
if let launched = LibraryEntry.hostURL(ofWindowsPath: entry.launchWindowsPath) {
125+
let program = launched.resolvingSymlinksInPath().standardizedFileURL
126+
let root = folder.resolvingSymlinksInPath().standardizedFileURL
127+
if program.path.hasPrefix(root.path + "/"),
128+
fm.fileExists(atPath: program.deletingLastPathComponent().appendingPathComponent("GameAssembly.dll").path) {
129+
return true
130+
}
131+
}
124132
return fm.fileExists(atPath: folder.appendingPathComponent("GameAssembly.dll").path)
125133
}
126134
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#!/usr/bin/env python3
2+
# SPDX-License-Identifier: GPL-3.0-or-later
3+
# Madeira Converter Exception: see LICENSE-EXCEPTION.md
4+
"""Compile the production IL2CPP detector and launch-path mapping on temporary games."""
5+
from pathlib import Path
6+
import subprocess
7+
import tempfile
8+
9+
root = Path(__file__).resolve().parents[2]
10+
bcd = (root / 'app/Madeira/LibraryBCD.swift').read_text()
11+
library = (root / 'app/Madeira/Library.swift').read_text()
12+
13+
14+
def block(source, header):
15+
start = source.index(header)
16+
opening = source.index('{', start)
17+
depth, end = 1, opening + 1
18+
while depth:
19+
depth += (source[end] == '{') - (source[end] == '}')
20+
end += 1
21+
return source[start:end]
22+
23+
24+
swift = '''import Foundation
25+
struct LibraryEntry {
26+
var relativePath: String
27+
var steamAppID: Int? = nil
28+
var steamStart: String? = nil
29+
var steamProgram: String? = nil
30+
var epicAppName: String? = nil
31+
var epicAntiCheatOff: Bool? = nil
32+
static let epicAntiCheatOffProgram: [String: String] = [:]
33+
static let hostDrive = URL(fileURLWithPath: CommandLine.arguments[1], isDirectory: true)
34+
'''
35+
for header in [' var windowsPath:', ' var startsSteamGameDirectly:',
36+
' var launchRelativePath:', ' var launchWindowsPath:',
37+
' static func hostURL(ofWindowsPath']:
38+
swift += block(library, header) + '\n'
39+
swift += '}\nenum BCDLaunch {\n' + block(bcd, ' static func isUnityIL2CPP(') + '\n}\n'
40+
swift += r'''
41+
let fm = FileManager.default
42+
let drive = LibraryEntry.hostDrive
43+
func create(_ path: String) throws {
44+
let file = drive.appendingPathComponent(path)
45+
try fm.createDirectory(at: file.deletingLastPathComponent(), withIntermediateDirectories: true)
46+
try Data().write(to: file)
47+
}
48+
for path in ["Nested/bin/game.exe", "Nested/bin/GameAssembly.dll", "Root/game.exe",
49+
"Root/GameAssembly.dll", "Plain/game.exe", "Other/game.exe", "Other/GameAssembly.dll"] {
50+
try create(path)
51+
}
52+
try fm.createSymbolicLink(at: drive.appendingPathComponent("Plain/escape"),
53+
withDestinationURL: drive.appendingPathComponent("Other"))
54+
var failed = 0
55+
func expect(_ value: Bool, _ label: String) {
56+
print((value ? "PASS: " : "FAIL: ") + label)
57+
if !value { failed += 1 }
58+
}
59+
let directSteam = LibraryEntry(relativePath: "Nested", steamAppID: 1, steamStart: "game", steamProgram: "bin/game.exe")
60+
expect(BCDLaunch.isUnityIL2CPP(directSteam), "known nested Steam executable is detected")
61+
expect(BCDLaunch.isUnityIL2CPP(LibraryEntry(relativePath: "Nested/bin/game.exe")), "local nested executable is detected")
62+
expect(BCDLaunch.isUnityIL2CPP(LibraryEntry(relativePath: "Root", steamAppID: 2)), "root-level Steam DLL is still detected")
63+
expect(BCDLaunch.isUnityIL2CPP(LibraryEntry(relativePath: "Root/game.exe")), "local root-level DLL is still detected")
64+
expect(!BCDLaunch.isUnityIL2CPP(LibraryEntry(relativePath: "Plain/game.exe")), "non-IL2CPP game is not detected")
65+
expect(!BCDLaunch.isUnityIL2CPP(LibraryEntry(relativePath: "Plain", steamAppID: 3, steamStart: "game", steamProgram: "../Other/game.exe")), "parent traversal cannot select another game's assembly")
66+
expect(!BCDLaunch.isUnityIL2CPP(LibraryEntry(relativePath: "Plain", steamAppID: 3, steamStart: "game", steamProgram: "escape/game.exe")), "launch symlink cannot select another game's assembly")
67+
expect(!BCDLaunch.isUnityIL2CPP(LibraryEntry(relativePath: "../Other/game.exe")), "invalid entry path is rejected")
68+
expect(!BCDLaunch.isUnityIL2CPP(LibraryEntry(relativePath: "Nested", steamAppID: 1)), "unknown Dock program does not scan arbitrary subdirectories")
69+
expect(!BCDLaunch.isUnityIL2CPP(LibraryEntry(relativePath: "Nested", steamAppID: 1, steamProgram: "bin/game.exe")), "a dormant direct-start choice does not change a Dock launch")
70+
exit(failed == 0 ? 0 : 1)
71+
'''
72+
with tempfile.TemporaryDirectory(prefix='madeira-il2cpp-detection-') as tmp:
73+
directory = Path(tmp)
74+
program = directory / 'detect.swift'
75+
program.write_text(swift)
76+
subprocess.run(['swift', str(program), str(directory / 'drive_c')], check=True)
77+
print('check-il2cpp-detection: PASS')

‎tests/host/check-real-suspend-game.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ def block(source, header):
6565
defer { defaults.removePersistentDomain(forName: suite) }
6666
struct LibraryEntry {
6767
var windowsPath: String
68+
var launchWindowsPath: String { windowsPath }
6869
var desktop: Bool? = nil
6970
static func hostURL(ofWindowsPath path: String) -> URL? { URL(fileURLWithPath: path) }
7071
}

0 commit comments

Comments
 (0)