Skip to content

crossover_wine_architecture

runner edited this page Oct 5, 2026 · 15 revisions

Endfield_FineWine — Arknights: Endfield on Apple Silicon

Engineering Reference – crossover_wine_architecture

This page documents the technical architecture that enables Arknights: Endfield to run on Apple Silicon macOS through a custom‑patched CrossOver Wine build. It covers the core concepts, the novel Rosetta 2 fixes, the anti‑cheat (ACE) patches, the graphics translation pipeline, and the step‑by‑step deployment process. All commands, code snippets, and troubleshooting tips are included to help you reproduce the solution or extend it.


Table of Contents

  1. High‑Level Overview
  2. Core Architecture Components
  3. Rosetta 2 Signal‑Handling Fixes
  4. Anti‑Cheat (ACE) Patches
  5. Graphics Translation Pipeline
  6. Deploying the Patched Wine into CrossOver
  7. Bottle Configuration & Graphics Backend
  8. Launching the Game
  9. Troubleshooting Guide
  10. References & Further Reading

High‑Level Overview

Arknights: Endfield is a Unity IL2CPP game that uses ACE (Anti‑Cheat Expert), a kernel‑driver‑plus‑user‑mode anti‑cheat system. Stock CrossOver Wine cannot load the required Windows kernel driver, and the game’s VMProtect/TenProtect protector (EndfieldBase.dll) triggers an exception‑handling loop that prevents the game from launching.

The solution is a minimal, 64‑bit‑only patched Wine that:

  • Fixes two Rosetta 2 bugs that cause the protector’s exception loop to crash on macOS.
  • Ports the dw‑proton anti‑cheat patches (int3‑stub, ntoskrnl em‑backports, QPC timing) so ACE can initialise.
  • Swaps only three core Wine modules (ntdll.so, kernel32.dll, ntoskrnl.exe) into a copy of CrossOver, leaving all other libraries (D3DMetal, fonts, TLS, etc.) untouched.
  • Ensures the patched Wine can talk to Apple’s D3DMetal via the proper LC_RPATH and cxcompatdb configuration, so the game renders through Apple D3DMetal (the “D3DMetal” backend).

The result is a near‑native macOS gaming experience (≈60 FPS on Medium settings on an M4 Pro) while preserving the original game logic and anti‑cheat integrity.


Core Architecture Components

Component Role Location in CrossOver bundle
Patched Wine (wine64, wine32on64) Executes the game’s x86_64 code under Rosetta 2 on Apple Silicon. Contents/SharedSupport/CrossOver/bin/
ntdll.so (patched) Implements the two Rosetta 2 fixes (NOP‑skip, privileged‑instruction handling) and provides QPC‑based timing. Contents/SharedSupport/CrossOver/lib/wine/x86_64-unix/
kernel32.dll (patched) Spoofs KiUser*Dispatcher with a 4×int3 stub to defeat ACE’s tpshell probe. Contents/SharedSupport/CrossOver/lib/wine/x86_64-windows/
ntoskrnl.exe (patched) Supplies 17 emulated NT kernel functions required by ACE. Contents/SharedSupport/CrossOver/lib/wine/x86_64-windows/
D3DMetal / GPTK4 Translates DirectX 11 → Metal (Apple’s graphics API). Contents/SharedSupport/CrossOver/lib64/apple_gpt/
CrossOver app bundle Provides the runtime environment, SIP‑compatible signing, and the bottle configuration. /Applications/CrossOver.app/

Note: The patched Wine is 64‑bit only; 32‑bit support (win32on64) is not used for Endfield.


Rosetta 2 Signal‑Handling Fixes

Two bugs in Rosetta 2’s x86_64 → arm64 translation cause crashes when the VMProtect/TenProtect protector (EndfieldBase.dll) emits special instructions.

1. Plain NOP (0F 1F) Crash

  • Problem: VMProtect inserts millions of multi‑byte NOPs (0F 1F). Rosetta raises an EXCEPTION_ILLEGAL_INSTRUCTION for a plain NOP, causing a collided‑unwind loop and stack overflow.
  • Fix (in dlls/ntdll/unix/signal_x86_64.c): decode the NOP length (modrm + optional SIB + displacement) and advance RIP past it. The NOP has zero side effects, so skipping it is safe.

2. Privileged Instruction Mis‑classification (mov rbx, cr3)

  • Problem: ACE’s driver reads mov rbx, cr3 as an anti‑VM probe. On Linux this raises a General Protection Fault (#GP) → Wine reports EXCEPTION_PRIV_INSTRUCTION. Under Rosetta the same instruction raises an invalid‑opcode fault, so Wine reports EXCEPTION_ILLEGAL_INSTRUCTION and ACE aborts with “driver error 13”.
  • Fix (in segv_handler): before defaulting to EXCEPTION_ILLEGAL_INSTRUCTION, inspect the faulting opcode with Wine’s is_privileged_instr() and deliver EXCEPTION_PRIV_INSTRUCTION if the instruction is privileged.

Both fixes are general (affect any VMProtect/TenProtect‑protected game) and are upstreamed to CrossOver’s handle_cet_nop implementation.


Anti‑Cheat (ACE) Patches

The dw‑proton fork (Dawn Winery) provides the patches that make Endfield launch on Linux. They are applied to CrossOver’s Wine as follows:

Patch File Purpose
Int3‑stub (KiUserApcDispatcher / KiUserCallbackDispatcher) dlls/kernel32/module.c Returns a naked int3 (0xCC) stub instead of the real dispatcher address, defeating ACE’s tpshell probe. Guarded by #ifdef __x86_64__ and a process‑name gate (Endfield.exe or EM-Win64-Shipping.exe).
ntoskrnl.exe em‑backports dlls/ntoskrnl.exe/ (18 functions) Implements kernel calls ACE expects (KeAcquireGuardedMutex, PsGetProcessSessionId, MmGetPhysicalMemoryRanges, etc.).
QPC timing (NtDelayExecution) dlls/ntdll/unix/sync.c Replaces relative sleeps with high‑resolution QueryPerformanceCounter busy‑wait loops.
Wintrust bypass (historical) wintrust_main.c Skips signature checks for winex11.drv / winewayland.drv. Removed from current tree; macOS‑irrelevant.

These patches are not part of the upstream Wine source; they live in the dawn-winery/wine-dwproton submodule and must be applied to the CrossOver Wine tree.


Graphics Translation Pipeline

Endfield defaults to Vulkan, but the macOS‑compatible path is DirectX 11 → D3DMetal → Metal. The pipeline works as follows:

Endfield (DirectX 11) ──► CrossOver D3DMetal (GPTK) ──► Metal Framework ──► Apple Silicon GPU (Metal 3/4)
```python

- **Why DirectX 11?**  
  - DX12 → `vkd3d` fails to compile the game’s DXIL/SM6 shaders (white screen).  
  - Native Vulkan → MoltenVK works only with newer MoltenVK (1.4.2+); older builds cause black screens after swapchain recreation.  
  - DirectX 11 maps cleanly to **D3DMetal**, which is the only backend that reliably renders Endfield on macOS.

- **Backend selection** is controlled by the bottle’s `CX_GRAPHICS_BACKEND` key (`d3dmetal`, `dxmt`, `dxvk`, `wined3d`). The default for Endfield is `d3dmetal`.

- **Optional GPTK4 upgrade** (macOS 27+): installs **D3DMetal 4** (Metal 4) and enables **MetalFX** frame‑generation (spoofed as NVIDIA DLSS). To use it, point `GPTK_DIR` at the mounted GPTK DMG and re‑run `swap-into-crossover.sh`.

---

## Deploying the Patched Wine into CrossOver

The deployment is fully scripted; the steps are:

```bash

# 1. Build the patched Wine (64‑bit only)

./scripts/build-wine.sh all          # deps → fetch → configure → build (~20‑60 min)

# 2. Deploy the patched modules into a copy of CrossOver

./scripts/swap-into-crossover.sh     # copies CrossOver.app, swaps ntdll, kernel32, ntoskrnl, re‑signs

# 3. Verify the bundle is signed and quarantine‑free

codesign --verify --deep --strict CrossOver_Endfield_Patch.app
xattr -drs com.apple.quarantine CrossOver_Endfield_Patch.app
```bash

### Manual deployment (audit‑friendly)

```bash

# Copy the original CrossOver.app (must be 26.3)

APP="/Applications/CrossOver_Endfield_Patch.app"
ditto --noextattr --noqtn /Applications/CrossOver.app "$APP"
CXR="$APP/Contents/SharedSupport/CrossOver"

# Swap the three patched modules (backups are created automatically)

for f in x86_64-unix/ntdll.so x86_64-windows/kernel32.dll x86_64-windows/ntoskrnl.exe; do
  mv "$CXR/lib/wine/$f" "$CXR/lib/wine/$f.cxorig"
done
cp "$BUILD/wine-build64/dlls/ntdll/ntdll.so"                           "$CXR/lib/wine/x86_64-unix/ntdll.so"
cp "$BUILD/wine-build64/dlls/kernel32/x86_64-windows/kernel32.dll"   "$CXR/lib/wine/x86_64-windows/kernel32.dll"
cp "$BUILD/wine-build64/dlls/ntoskrnl.exe/x86_64-windows/ntoskrnl.exe" "$CXR/lib/wine/x86_64-windows/ntoskrnl.exe"

# Add the required rpath so cxcompatdb can find libgnutls.30.dylib

install_name_tool -add_rpath "@loader_path/../../../lib64" \
  "$CXR/lib/wine/x86_64-unix/ntdll.so"
codesign --force --sign - "$CXR/lib/wine/x86_64-unix/ntdll.so"

# Re‑seal the outer bundle (ad‑hoc signature)

xattr -drs com.apple.quarantine "$APP"
codesign --force --sign - --preserve-metadata=entitlements "$APP"
codesign --verify --deep --strict "$APP"
```bash

> **Tip:** The `swap-into-crossover.sh` script automates the above and also handles the optional GPTK4 payload if `GPTK_DIR` points at a mounted GPTK DMG.

---

## Bottle Configuration & Graphics Backend

The bottle’s `cxbottle.conf` contains the key:

```ini
CX_GRAPHICS_BACKEND = d3dmetal   # or dxmt, dxvk, wined3d
CX_ACTIVE_GRAPHICS_BACKEND = d3dmetal
WINEMSYNC = 0
```text

- **`d3dmetal`** – DirectX 11 → D3DMetal → Metal (recommended).  
- **`dxmt`** – DXMT (DX11 → Metal) – the backend under which ReShade is known to work on macOS.  
- **`dxvk`** – DXVK → Vulkan → MoltenVK (experimental).  
- **`wined3d`** – stock Wine D3D11 implementation (fallback).

You can change the backend at any time via CrossOver’s **Advanced Settings** → **Graphics** or by editing `cxbottle.conf` directly.

---

## Launching the Game

The recommended launch method uses the **Gryphline launcher** and forces DirectX 11:

```bash

# From the Gryphline launcher UI:

# - Select the "Arknights Endfield" bottle

# - Choose "Launch with DirectX 11" from the dropdown next to the Start button

```bash

If you prefer a command‑line launch, use `scripts/launch-endfield.sh` (adds `-force-d3d11` and handles wineserver cleanup). Example:

```bash
CXR="/Applications/CrossOver_Endfield_Patch.app/Contents/SharedSupport/CrossOver"
"$CXR/bin/wine" --bottle "Arknights Endfield" \
  --cx-app "C:/Program Files/GRYPHLINK/games/Arknights Endfield/Endfield.exe" \
  -force-d3d11
```bash

**Debug logging** (useful for troubleshooting) can be enabled with:

```bash
DEBUG=light ./scripts/launch-endfield.sh   # Wine errors only
DEBUG=1 ./scripts/launch-endfield.sh      # Full CrossOver log (heavy)
```bash

---

## Troubleshooting Guide

| Symptom | Likely Cause | Fix |
|---------|--------------|-----|
| **CrossOver.app is “damaged and can’t be opened”** | Bundle signature is broken after module swap. | Re‑run `swap-into-crossover.sh` (it re‑seals the bundle). If you edited files manually, run `codesign --force --sign - --preserve-metadata=entitlements /Applications/CrossOver_Endfield_Patch.app`. |
| **White / blank screen after a game update** | Game reset renderer to Vulkan/DX12; DX12 → `vkd3d` fails, Vulkan needs newer MoltenVK. | Launch with **DirectX 11** (`-force-d3d11` or launcher dropdown). Do **not** replace `d3d11.dll` with the `apple_gptk` copies – that breaks `unityplayer.dll` init (error 1114). |
| **ACE “driver error 13” returns** | Patched `ntdll.so`/`ntoskrnl.exe` not loading (wrong paths or missing rpath). | Verify the swap paths in `swap-into-crossover.sh`. Ensure `LC_RPATH` is set on `ntdll.so` (`@loader_path/../../../lib64`). |
| **High CPU usage / freeze with sound still playing** | Memory‑pressure freeze (RAM exhausted). | Close heavy background apps (browsers, Discord, Creative Cloud). Free memory before relaunch. |
| **Vulkan mode black screen after FPS/V‑Sync change** | Swapchain recreation bug in bundled MoltenVK (≤ 1.4.1). | Upgrade to **MoltenVK 1.4.2** (the script does this automatically) or launch in DirectX 11. |
| **Vulkan pipeline cache stale (odd bushes/grass)** | `vulkan_pso_cache.bin` compiled against old module build. | Delete the cache file: `rm "$HOME/Library/Application Support/CrossOver/Bottles/Arknights Endfield/drive_c/users/crossover/AppData/LocalLow/Gryphline/Endfield/vulkan_pso_cache.bin"` and relaunch. |
| **`unityplayer.dll` “missing or corrupt” (error 1114)** | Wrong graphics DLLs swapped (e.g., using `apple_gptk` DLLs directly). | Restore the stock `d3d11/d3d12/dxgi.dll` files from a clean CrossOver install; launch via the Gryphline launcher. |
| **High‑Resolution Mode white screen** | Known bug – leave High‑Resolution Mode **off**. |
| **Black screen on later launches** | Registry/settings cache not reset. | Use CrossOver → *Run Command* → `regedit` → delete `HKCU\Software\Gryphline\Endfield` and `…\sdk_data\…` keys, then log in again. |
| **GRYPHLINK not listed in bottle** | Launcher shortcuts not registered with CrossOver menus. | Re‑register: `./scripts/create-bottle.sh` (re‑applies settings) or run `cxmenu --bottle "Arknights Endfield" --install`. |
| **Game freezes with sound still playing** | Memory‑pressure freeze (see “High CPU usage” row). | Force‑quit, free memory, relaunch. |
| **Multiple copies of the game running** | Two processes fighting over the same files (`Player.log` errors). | Ensure only one instance runs; use `scripts/01-capture-failure.sh` to capture logs if needed. |

### Debug Logging

- **Light** (`DEBUG=light`): captures only Wine errors – cheap enough to keep on while playing.  
- **Full** (`DEBUG=1`): captures the entire CrossOver log – useful for deep failure analysis.  

Pass the desired debug channel via `--debugmsg` when invoking `wine` directly, e.g.:

```bash
"$CXR/bin/wine" --debugmsg "err+all" --bottle "Arknights Endfield" ...
```bash

---

## References & Further Reading

- **Installation & Build** – [installation.md](installation.md)  
- **Graphics & Performance** – [graphics-performance.md](graphics-performance.md)  
- **Troubleshooting** – [troubleshooting.md](troubleshooting.md)  
- **Performance on 16 GB Macs** – [14-performance-on-16gb-macs.md](14-performance-on-16gb-macs.md)  
- **Technical Deep Dive** – [04-building-crossover-wine.md](04-building-crossover-wine.md), [05-swapping-into-crossover.md](05-swapping-into-crossover.md), [06-graphics-and-gptk.md](06-graphics-and-gptk.md)  

---  

*All commands and code snippets are tested on an Apple M4 Pro (macOS 27.0, CrossOver 26.3) and are intended for use with a **licensed** copy of CrossOver, a **licensed** copy of Arknights: Endfield, and the patched Wine build described herein.*

Clone this wiki locally