Repository navigation
patch_and_script_reference
Complete reference for all patches and scripts in the Endfield_FineWine project. This document serves as the technical index for the compatibility layer that enables Arknights: Endfield to run on Apple Silicon macOS via CrossOver Wine.
- Patch Inventory
- Script Reference
- Patch Application Order
- Script Execution Flow
- Related Documentation
All patches are stored under patches/ and applied to CrossOver's Wine 11.0 source tree during the build process. The patch set totals ~394 lines across 8 modified files.
Location:
patches/stage1-macos/
Target:dlls/ntdll/unix/signal_x86_64.c
Purpose: Fix two Rosetta 2 translation bugs that break VMProtect/TenProtect and ACE anti-cheat on Apple Silicon.
| Patch File | Function | Lines Changed | Description |
|---|---|---|---|
0001-rosetta-nop-skip.patch |
handle_cet_nop() |
~45 | Adds case 0x1F to decode and skip multi-byte 0F 1F NOP instructions that Rosetta incorrectly faults on. VMProtect emits 23,000+ of these per launch. |
0002-rosetta-priv-instr.patch |
segv_handler() (TRAP_x86_PRIVINFLT) |
~30 | On Rosetta path, calls is_privileged_instr() to detect mov reg, cr3 and delivers EXCEPTION_PRIV_INSTRUCTION (matching Linux) instead of EXCEPTION_ILLEGAL_INSTRUCTION. Fixes ACE "driver error 13". |
Technical Details: Both fixes live in Wine's x86_64 Unix signal handler (signal_x86_64.c). They sit alongside CrossOver's existing handle_cet_nop (for 0F 1E RDSSP NOPs) and emulate_xgetbv hacks.
📖 Deep dive: 12-stage1-protector-fault.md — root cause analysis and prior art (WineHQ Bug 45083).
Location:
patches/stage2-dwproton/
Origin: Dawn Winery / dw-proton release11.0-7(commitb816be489)
Purpose: Port the Linux-proven ACE anti-cheat compatibility patches to CrossOver's Wine tree.
Files:
dlls/ntoskrnl.exe/{ntoskrnl.c, ntoskrnl.exe.spec, _private.h, sync.c}
Author: Etaash Mathamsetty (based onwine-ntoskrnlproject)
| # | Function | Type | Purpose |
|---|---|---|---|
| 1 | KeAcquireGuardedMutex |
Implement | Guarded mutex acquisition for kernel synchronization |
| 2 | KeReleaseGuardedMutex |
Implement | Guarded mutex release |
| 3 | PsGetProcessSessionId |
Implement | Process session ID query (ACE checks this) |
| 4 | PsGetProcessCreateTimeQuadPart |
Implement | Process creation time |
| 5 | PsGetThreadProcess |
Implement | Thread → process mapping |
| 6 | KeRegisterBugCheckCallback |
Stub | Bug check callback registration |
| 7 | KeRegisterBugCheckReasonCallback |
Stub | Bug check reason callback |
| 8 | KeDeregisterBugCheckReasonCallback |
Stub | Deregister bug check callback |
| 9 | MmGetVirtualForPhysical |
Semi-stub | Physical → virtual address translation |
| 10 | PsGetProcessImageFileName |
Implement | Exact blocker from WineHQ Bug 59411 |
| 11 | SeLocateProcessImageName |
Implement | Locate process image name |
| 12 | PsReferencePrimaryToken |
Implement | Primary token reference |
| 13 | PsGetContextThread |
Implement | Thread context (no arch guard) |
| 14 |
create_process_object fix |
Fix | Process object creation fix in ntoskrnl.c
|
| 15 |
SeLocateProcessImageName follow-up |
Fix | Additional fix |
| 16 | KeCapturePersistentThreadState |
Stub | Persistent thread state capture |
| 17 | MmGetPhysicalMemoryRanges |
Implement | Physical memory ranges |
| 18 | PsGetProcessPeb |
Implement | Process PEB pointer |
⚠️ Note: Thecreate_process_objectfix (0014) is the only process-creation patch and most likely to conflict with CrossOver's tree.
File:
dlls/kernel32/module.c
Authors: Ziia Shi (spoof), NelloKudo (gate)
# ifdef __x86_64__
static BOOL needs_int3_hack(void) {
// Matches Endfield.exe OR EM-Win64-Shipping.exe
// Force-enable: PROTON_ENABLE_INT3_HACK=1
}
static void __attribute__((naked)) int3_stub(void) {
asm("int3\n\tint3\n\tint3\n\tint3\n\t");
}
// In get_proc_address():
if (needs_int3_hack() &&
(strcmp(function,"KiUserApcDispatcher")==0 ||
strcmp(function,"KiUserCallbackDispatcher")==0)) {
return (FARPROC)&int3_stub;
}
# endif
```python
**Mechanism:** ACE's tpshell protector resolves `KiUserApcDispatcher`/`KiUserCallbackDispatcher` via `GetProcAddress` to hook them. Returning a 4×`int3` (`0xCC`) stub defeats the probe. **Guarded by `#ifdef __x86_64__`** — only compiles in x86_64 Wine (Rosetta path).
#### C. `NtDelayExecution` QPC Timing Loop
> **File:** `dlls/ntdll/unix/sync.c`
> **Author:** Etaash Mathamsetty
```c
else if (timeout->QuadPart < 0) { // relative wait
timeout_t when = -timeout->QuadPart, diff;
LARGE_INTEGER now;
NtQueryPerformanceCounter(&now, NULL);
when += now.QuadPart;
for (;;) {
NtQueryPerformanceCounter(&now, NULL);
diff = (when - now.QuadPart + 9) / 10; // QPC 100ns → µs
if (diff <= 0) break;
struct timeval tv = { diff / 1000000, diff % 1000000 };
if (select(0, NULL, NULL, NULL, &tv) != -1) break;
}
}
```sql
**Purpose:** ACE performs timing-sensitive checks. Replaces `NtQuerySystemTime`-based sleep with high-resolution QPC busy-wait to avoid anti-cheat timeouts.
#### D. Auxiliary Patches (Ported but Not ACE-Critical)
| Patch | File | Purpose |
|-------|------|---------|
| `wdfldr.sys` stubs (3 patches) | `dlls/wdfldr/` | WDF loader stubs for driver framework |
| `KeGetCurrentIrql` stub | `dlls/ntoskrnl.exe/` | IRQL query stub |
| `NtUserEnableMouseInPointer` fix | `dlls/win32u/` | Mouse-in-pointer fix |
| `VersionService.exe` timing hack | `dlls/kernelbase/` | Process-gated delay (like int3 gate) |
| `winex11` overlay skip | `dlls/winex11/` | **X11-only, macOS-irrelevant** |
| `ntdll` stop unwinding on AV | `dlls/ntdll/` | Access violation unwind fix |
> 📖 **Full inventory with verbatim code:** [02-dwproton-ace-patches.md](02-dwproton-ace-patches.md)
---
### MoltenVK Patches (Experimental Vulkan)
> **Location:** `patches/moltenvk/`
> **Origin:** Ported from [mary-ext/crossover-wine-endfield](https://github.com/mary-ext/crossover-wine-endfield)
> **Purpose:** Fix Vulkan renderer issues (swapchain recreation, GPU hangs, TAAU artifacts) when running Endfield with `-force-vulkan`.
| Patch | Fixes |
|-------|-------|
| Swapchain recreation black screen | MoltenVK 1.4.2+ fixes this; patch backports to CrossOver's bundled version |
| Snowy Forest GPU hang (WindowServer kill) | Prevents macOS from killing WindowServer on GPU timeout |
| TAAU/FSR3 artifacts near Recycling Stations | Rendering correctness |
| Pipeline cache staleness | Requires manual `vulkan_pso_cache.bin` deletion after MoltenVK upgrade |
**Usage:** Build with `scripts/build-moltenvk.sh` (needs full Xcode), install via `scripts/package.sh` + `scripts/apply-modules.sh`. Launch with `GFXARGS=-force-vulkan scripts/launch-endfield.sh`.
> 📖 **Details:** [graphics-performance.md#experimental-the-vulkan-renderer](graphics-performance.md#experimental-the-vulkan-renderer) | [troubleshooting.md#in-game-graphics](troubleshooting.md#in-game-graphics)
---
## Script Reference
All scripts live in [`scripts/`](../scripts/) and are executable Bash scripts. Run from the repository root.
### Build Scripts
#### `build-wine.sh` — Main Build Orchestrator
```bash
./scripts/build-wine.sh <stage>
```bash
| Stage | Description | Duration (M4 Pro) |
|-------|-------------|-------------------|
| `deps` | Install Homebrew dependencies (bison, mingw-w64, meson, pkg-config, etc.) | ~2 min |
| `fetch` | Download CrossOver 26.3 Wine source (~142 MB), git-init it | ~1 min |
| `apply` | Apply all 24 patches (verified clean apply) | ~30 sec |
| `configure` | Configure 64-bit-only build under `arch -x86_64` | ~2 min |
| `build` | Compile with `make -j$(sysctl -n hw.ncpu)` | ~10–20 min |
| `all` | Run all stages sequentially (default) | ~15–25 min |
**Environment Variables:**
```bash
export CROSSOVER_VERSION=26.3 # Must match installed CrossOver
export WINE_SRC_DIR=build/wine-src # Source directory
export BUILD_DIR=build/wine-build64 # Build output
```bash
**Key Implementation Details:**
- Builds **64-bit-only Wine** (no `win32on64`, no `cx-llvm` needed — Endfield is 64-bit only)
- Runs under `arch -x86_64` (Rosetta host) to produce x86_64 binaries
- Minimal configuration: `--disable-tests --without-alsa --without-capi --without-dbus ... --without-x`
- Output: `build/wine-build64/dlls/ntdll/ntdll.so`, `dlls/kernel32/.../kernel32.dll`, `dlls/ntoskrnl.exe/.../ntoskrnl.exe`
> 📖 **Full build docs:** [04-building-crossover-wine.md](04-building-crossover-wine.md) | [scripts/README.md](../scripts/README.md)
#### `build-moltenvk.sh` — MoltenVK Build (Experimental)
```bash
./scripts/build-moltenvk.sh
```bash
- Requires **full Xcode** (not just CLT) for Metal shader compilation
- Builds patched MoltenVK from `patches/moltenvk/`
- Output staged for `package.sh` + `apply-modules.sh`
---
### Deployment Scripts
#### `swap-into-crossover.sh` — Deploy Patched Modules into CrossOver
```bash
./scripts/swap-into-crossover.sh [options]
```bash
**What it does:**
1. Copies `/Applications/CrossOver.app` → staging area (`$TMPDIR/CrossOver_patched.app`)
2. Backs up original modules as `.cxorig`
3. Copies 3 patched modules:
- `ntdll.so` → `lib/wine/x86_64-unix/ntdll.so`
- `kernel32.dll` → `lib/wine/x86_64-windows/kernel32.dll`
- `ntoskrnl.exe` → `lib/wine/x86_64-windows/ntoskrnl.exe`
4. **Injects rpath** into `ntdll.so`: `install_name_tool -add_rpath "@loader_path/../../../lib64"`
5. **Ad-hoc re-signs** swapped modules + outer bundle (preserves CodeWeavers entitlements)
6. Verifies signature: `codesign --verify --deep --strict`
7. Moves to `/Applications/CrossOver_Endfield_Patch.app`
**Options:**
```bash
GPTK_DIR="/Volumes/GPTK/redist/lib/external" ./scripts/swap-into-crossover.sh # Install GPTK4 D3DMetal
SKIP_GPTK=1 ./scripts/swap-into-crossover.sh # Skip GPTK, use bundled 3.0
```bash
**Critical:** The rpath injection is mandatory — without it, `cxcompatdb.so` fails to load `libgnutls.30.dylib`, D3DMetal backend never activates, and DX11 device creation fails with `80004005`.
> 📖 **Verified recipe & code-signing deep dive:** [05-swapping-into-crossover.md#verified-recipe-2026-09-crossover-2620--macos-270--m4](05-swapping-into-crossover.md#verified-recipe-2026-09-crossover-2620--macos-270--m4)
#### `create-bottle.sh` — Create/Update Game Bottle
```bash
./scripts/create-bottle.sh # Create new "Arknights Endfield" bottle
UPDATE=1 ./scripts/create-bottle.sh # Update existing bottle settings
```bash
**Bottle Configuration (written to `cxbottle.conf`):**
| Setting | Key | Value |
|---------|-----|-------|
| Windows Version | — | Windows 11 64-bit |
| Graphics Backend | `CX_GRAPHICS_BACKEND` | `d3dmetal` |
| DLSS (MetalFX) | `D3DM_ENABLE_METALFX` | `1` |
| MSync | `WINEMSYNC` | `1` |
| High Resolution Mode | — | **Disabled** (causes white screen