Add Linux/Proton support
Elden Ring under Proton on Linux is the same Windows binary, so every AOB signature and memory offset is unchanged — only how the process gets found and read differs. Split main.go/i18n.go (previously Windows-only) into a portable process.go (signature scanning, pointer resolution, the poll loop) plus process_windows.go/process_linux.go behind a small boundary: findProcessID, openProcess, closeProcessHandle, readMemory, findModuleBase, productVersion, systemLang. Linux side: finds the process by walking /proc/*/maps for a mapping ending in eldenring.exe (Proton runs several helper processes, so matching by name alone isn't reliable), reads memory via /proc/<pid>/mem (stdlib only, no external deps), and has no productVersion equivalent (returns ok=false — this was always just a hint for which PlayerIns offset to try first; the real one is confirmed by a live memory read regardless). openProcess probes /proc/<pid>/mem up front so a ptrace_scope permission failure surfaces immediately with the exact `sudo setcap cap_sys_ptrace+ep <path>` fix, never suggesting the system-wide ptrace_scope=0 weakening or running as root. main.go and i18n.go are fully portable now, no build tags. Verified: Windows build/vet/test plus a real run (no regression from moving ~500 lines). Linux is cross-compile build/vet only in this session — not yet run against a real Proton process.
This commit is contained in:
1 parent
5a2c3272e9
commit
2ba312a833
7 files changed
+1128
-883
No files matched your search
@@ -1,5 +1,3 @@
|
||||
//go:build windows
|
||||
|
||||
// i18n.go: interface languages.
|
||||
//
|
||||
// Translations live in locales/*.json and get embedded into the binary.
|
||||
@@ -10,6 +8,11 @@
|
||||
// Console messages deliberately do NOT go through here: they're
|
||||
// diagnostics, and it helps if they're always in the same language so a
|
||||
// log pasted into an issue reads the same no matter where it came from.
|
||||
//
|
||||
// systemLang(), which this file calls to pick the default language, is
|
||||
// the one OS-specific piece — implemented in process_windows.go/
|
||||
// process_linux.go, not here, since this file's own job (embedding and
|
||||
// picking a dictionary) doesn't depend on the OS at all.
|
||||
package main
|
||||
|
||||
import (
|
||||
@@ -19,8 +22,6 @@ import (
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//go:embed locales/*.json
|
||||
@@ -64,24 +65,8 @@ func availableLangs() []string {
|
||||
return out
|
||||
}
|
||||
|
||||
var procGetUserDefaultLocaleName = kernel32.NewProc("GetUserDefaultLocaleName")
|
||||
|
||||
// systemLang returns Windows's language ("es-AR" -> "es").
|
||||
func systemLang() string {
|
||||
buf := make([]uint16, 85) // LOCALE_NAME_MAX_LENGTH
|
||||
r, _, _ := procGetUserDefaultLocaleName.Call(uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)))
|
||||
if r == 0 {
|
||||
return ""
|
||||
}
|
||||
name := syscall.UTF16ToString(buf[:r])
|
||||
if base, _, ok := strings.Cut(name, "-"); ok {
|
||||
return strings.ToLower(base)
|
||||
}
|
||||
return strings.ToLower(name)
|
||||
}
|
||||
|
||||
// resolveLang decides the final language. "auto" (or empty) uses
|
||||
// Windows's; if that language isn't translated, it falls back to English.
|
||||
// resolveLang decides the final language. "auto" (or empty) uses the
|
||||
// system's; if that language isn't translated, it falls back to English.
|
||||
func resolveLang(want string) string {
|
||||
want = strings.ToLower(strings.TrimSpace(want))
|
||||
if want == "" || want == "auto" {
|
||||
|
||||
Reference in new issue
Block a user