Repository navigation
test_coverage
runner edited this page Oct 16, 2026
·
9 revisions
Arknights: Endfield on Apple Silicon — A set of patches to CrossOver's (LGPL) Wine, plus scripts and documentation to build and deploy them. This project enables Arknights: Endfield to run on Apple Silicon Macs through a custom-patched CrossOver Wine build.
- Project Overview
- Development Environment Setup
- Project Structure & Architecture
- Build Process
- Deployment & Installation
- Testing Procedures
- CI/CD Pipeline
- Coding Standards & Guidelines
- Code Review Procedures
- Debugging & Troubleshooting
- Contribution Guidelines
- Development Tools & Links
- License & Legal
Endfield_FineWine is a compatibility layer that allows Arknights: Endfield to run on Apple Silicon macOS through a custom-patched CrossOver Wine. It consists of:
- Patches to CrossOver's Wine (LGPL-2.1-or-later)
- Build and deployment scripts (Bash, Python)
- Documentation covering the engineering behind the fix
- It does not contain or redistribute CrossOver, Wine, Apple's Game Porting Toolkit (GPTK), or the game
- It does not bypass anti-cheat; it adjusts the CrossOver environment to allow Endfield's ACE anti-cheat services to run uninterrupted
- It is not affiliated with Gryphline/Hypergryph, Tencent, CodeWeavers, or Apple
⚠️ These patches for CrossOver are provided as-is. While the patches allow the Endfield anti-cheat to operate on macOS like it does on Windows, using this tool is your choice, and you take on the risks associated with that.
- Own the game; this is compatibility work (same category as Valve's Proton on Linux)
- No in-game advantage, no modified game logic, no DRM circumvention
- Running the game in an unsupported configuration may violate its Terms of Service; that risk is yours (see LICENSE)
| Component | Requirement |
|---|---|
| Mac | Apple Silicon (M-series) — Intel is not supported |
| macOS | 15 (Sequoia) or newer — tested on 27.0 / 26.5 |
| Cooling | Actively cooled Mac required (MacBook Pro, Mac Studio, Mac mini). MacBook Air is OFF-LIMITS (no active cooling) |
| RAM | 16 GB minimum; 24 GB+ recommended |
| Dependency | Version | Purpose |
|---|---|---|
| Rosetta 2 | Required | softwareupdate --install-rosetta --agree-to-license |
| CrossOver | 26.3 | Licensed install from codeweavers.com |
| Xcode CLT | Latest | xcode-select --install |
| Homebrew | Latest |
brew.sh — Apple Silicon (/opt/homebrew) |
| Disk space | ~5 GB | For the build tree |
| Build time | ~10–60 min | ~10 min on 10-core M4; 1.5–2.5 h cold on 3-vCPU CI runner |
git clone <your-fork-url> Endfield_FineWine
cd Endfield_FineWine
```bash
### Initial Environment Verification
```bash
# Verify Rosetta 2 is installed
softwareupdate --install-rosetta --agree-to-license
# Verify CrossOver version
/Applications/CrossOver.app/Contents/SharedSupport/CrossOver/bin/wine --version
# Verify architecture (must be x86_64 under Rosetta)
file /Applications/CrossOver.app/Contents/SharedSupport/CrossOver/bin/wineserver
# Verify Homebrew is available
brew --version
```text
---
## 3. Project Structure & Architecture
### Repository Layout
```yaml
Endfield_FineWine/
├── .github/
│ ├── scripts/
│ │ ├── generate-wiki.py
│ │ ├── generate-release-notes.py
│ │ └── ...
│ └── workflows/
│ ├── build.yml
│ ├── nightly.yml
│ └── update-wiki.yml
├── patches/
│ ├── README.md
│ ├── stage1-macos/ # Novel Rosetta 2 signal-handling fixes
│ ├── stage2-dwproton/ # dw-proton anti-cheat port
│ │ └── ace-core/ # ACE-CORE driver regression fixes
│ └── moltenvk/ # Patched MoltenVK
├── scripts/
│ ├── build-wine.sh
│ ├── swap-into-crossover.sh
│ ├── create-bottle.sh
│ ├── launch-endfield.sh
│ ├── make-launcher-app.sh
│ ├── 01-capture-failure.sh
│ ├── build-moltenvk.sh
│ ├── package.sh
│ └── apply-modules.sh
├── tests/
│ └── test-msync-waitall.py
├── patcher-app/ # FineWine Patcher.app (SwiftPM GUI)
├── docs/
│ ├── installation.md
│ ├── troubleshooting.md
│ ├── performance.md
│ ├── technical.md
│ ├── graphics-performance.md
│ └── project-information/
└── LICENSE
```text
### Patch Architecture
The project uses a **surgical module swap** approach. Instead of replacing the entire CrossOver application, only three core Wine modules are swapped into a copy of CrossOver:
| Module | Location in CrossOver | Responsibility |
|--------|----------------------|----------------|
| `ntdll.so` | `lib/wine/x86_64-unix/ntdll.so` | Rosetta 2 signal fixes, NOP skip, QPC timing |
| `kernel32.dll` | `lib/wine/x86_64-windows/kernel32.dll` | `KiUser*Dispatcher` int3 spoof |
| `ntoskrnl.exe` | `lib/wine/x86_64-windows/ntoskrnl.exe` | 17 backported NT kernel functions |
#### Patch Sets
| Patch Set | Origin | Purpose |
|-----------|--------|---------|
| `stage1-macos/` | Novel (this project) | Two Rosetta 2 signal-handling fixes in `signal_x86_64.c` |
| `stage2-dwproton/` | dw-proton / Dawn Winery | 17 `ntoskrnl.exe` backports, int3 spoof, QPC timing |
| `ace-core/` | mary-ext / dw-proton | ACE-CORE driver regression fixes (return-address bits, `lsass.exe` stub) |
### The Two Novel Rosetta 2 Fixes
Both fixes reside in `dlls/ntdll/unix/signal_x86_64.c`:
1. **Multi-byte NOP (`0F 1F`) skip:** VMProtect emits `0F 1F` NOPs pervasively. Rosetta 2 erroneously raises illegal-instruction faults on them. The fix decodes the instruction length and advances `RIP` past the NOP.
2. **Privileged instruction (`mov cr3`) classification:** ACE's driver reads `CR3` as an anti-VM probe. Rosetta generates an invalid-opcode fault instead of `#GP`. The fix inspects the opcode with `is_privileged_instr()` and delivers `EXCEPTION_PRIV_INSTRUCTION` matching Linux behavior.
### Graphics Translation Pipeline
```python
Endfield Engine (DirectX 11, via -force-d3d11)
│
▼
DXMT (CrossOver's D3D11-to-Metal translation layer)
│ (Thin, direct DX11 → Metal API mapping)
▼
Metal Framework / Apple Silicon GPU
```json
**Recommended configuration (October 2026):**
| Setting | Value |
|---------|-------|
| CrossOver Backend | `dxmt` (`CX_GRAPHICS_BACKEND=dxmt`) |
| Launch Flag | `-force-d3d11` |
| GPTK Patch | v4 (highly recommended) |
| Upscaling | TAAU or AMD FSR3 on stock DXMT; DLSS via MetalFX with NGX fix |
---
## 4. Build Process
### Build Script: `scripts/build-wine.sh`
The build is intentionally **minimal** (64-bit-only, no bundled fonts/TLS/graphics libs). Only 3 core modules are swapped into CrossOver, which provides everything else.
#### One-Shot Build
```bash
./scripts/build-wine.sh all
# deps -> fetch -> apply -> configure -> build (~20-60 min)
```bash
#### Step-by-Step Build
```bash
# 1. Install Homebrew dependencies
./scripts/build-wine.sh deps
# bison (≥3.0), mingw-w64, meson, pkg-config, ...
# 2. Download CrossOver 26.3 Wine source (~142 MB)
./scripts/build-wine.sh fetch
# 3. Apply all 24 patches
./scripts/build-wine.sh apply
# 4. Configure (64-bit-only, under arch -x86_64)
./scripts/build-wine.sh configure
# 5. Build
./scripts/build-wine.sh build
# make -j
```python
### Important Build Notes
- **No `cx-llvm` / `win32on64` needed.** Endfield is 64-bit only, so this builds a 64-bit-only Wine with the standard toolchain.
- **Build runs under `arch -x86_64`** (Rosetta host). The dw-proton int3 hack is `#ifdef __x86_64__`-guarded and compiles in this configuration.
- **bison version:** Homebrew's `bison` must be ≥ 3.0 and ahead of macOS system bison (2.3) on PATH.
- **Build artifacts** land in `build/wine-build64/`.
### LC_RPATH Fix
After building, `ntdll.so` needs CrossOver's `lib64` rpath so `cxcompatdb.so` can load `libgnutls.30.dylib`:
```bash
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"
```bash
Without this, `cxcompatdb.so` silently fails to load, falling back to WineD3D and producing error `80004005` (DirectX device creation failure).
---
## 5. Deployment & Installation
### Scripted Deployment (Recommended)
```bash
./scripts/swap-into-crossover.sh
```bash
This:
1. Copies `/Applications/CrossOver.app` into a staging folder
2. Swaps in the patched modules (plus GPTK4's D3DMetal if `GPTK_DIR` is set)
3. Re-seals the bundle with an ad-hoc signature
4. Verifies the bundle
5. Moves it to `/Applications/CrossOver_Endfield_Patch.app`
6. Creates a double-clickable `Arknights Endfield.app` launcher
### Manual Deployment
See `docs/installation.md` for the full manual procedure involving `