5 · Running it everywhere¶
The payoff: because the game is translated to portable C++ and the iOS environment is supplied by a swappable runtime backend, the same project builds and runs on platforms the 2012 binary could never have touched.
One source, many targets¶
Nothing about the game is rewritten per platform. The recompiler emits architecture-neutral C++; the runtime hides every host difference behind a backend chosen at link time. So porting to a new platform means writing one backend, not touching the game.
flowchart TB
CPP["Translated game (portable C++)<br/>+ runtime core"]
CPP --> M["macOS<br/><i>Cocoa · OpenGL · OpenAL</i>"]
CPP --> I["iOS / iPadOS<br/><i>UIKit · EAGL · OpenAL</i>"]
CPP --> A["Android<br/><i>NativeActivity · EGL · OpenSL</i>"]
CPP --> W["Web<br/><i>WebAssembly · WebGL2 · Web Audio</i>"]
What it took per platform¶
The point of the architecture is that this table is short — each platform is a backend, not a rewrite:
| Platform | CPU | Graphics | Audio | Networking | Owns main thread |
|---|---|---|---|---|---|
| macOS | arm64 / x86-64 | OpenGL | OpenAL | NSURLSession | the app |
| iOS / iPadOS | arm64 | OpenGL ES (EAGL) | OpenAL / AVAudioPlayer | NSURLSession | UIKit |
| Android | arm64 / armv7 | OpenGL ES (EGL) | OpenSL ES | HttpURLConnection (JNI) | the activity |
| Web | WebAssembly | WebGL2 | Web Audio | fetch |
the browser |
The web port, up close¶
The web build is the clearest proof the architecture works — and, perhaps surprisingly, it was one of the easier targets. From the runtime's point of view, a browser is just another host with the same shape as Android or iOS: the translated game and the runtime core don't change at all, and all we have to supply is a new platform backend. Three things needed attention:
- Graphics — almost free. The game renders with OpenGL ES 2.0, and WebGL2 is OpenGL ES compatible. The graphics backend forwards the game's GL calls straight to the browser's WebGL context, so there was very little to rewrite.
- Threads — reworked. The game is multi-threaded, but the browser doesn't do threads the way iOS does. We re-implemented the runtime's thread management on top of the browser's worker model (WebAssembly with shared memory), so every guest thread still gets a real thread of execution.
- Networking — TCP over WebSocket. The game speaks raw TCP, but a web page can't open a TCP socket. So the runtime's network layer tunnels the game's socket over a WebSocket: the exact same encrypted byte stream, just wrapped in WebSocket frames. Neither the game nor the server logic notices — only the transport underneath changes.
flowchart LR
G["Game's socket calls<br/>(raw TCP byte stream)"] --> NS["Runtime network layer"]
NS -->|native build| TCP["real TCP socket"] --> S1["C# server"]
NS -->|web build| WS["WebSocket frames"] --> S2["C# server<br/>(WebSocket endpoint)"]
The result: the original 2012 game, compiled to WebAssembly, rendering with WebGL2, logging in to the live C# server over a WebSocket and loading a real village — in an ordinary browser tab, with no plugin and no emulator.
Try it yourself — the web build is live at play.retro.atrasisclash.net.
The full picture¶
Putting all four layers together, here is the complete revived system:
flowchart TB
subgraph CLIENT["Client (any platform)"]
direction TB
GAME["Translated game<br/>(armv7re → C++)"]
RUN["Runtime<br/>(iOS environment + platform backend)"]
GAME --- RUN
end
subgraph SERVER["Server"]
direction TB
PROXY["Proxy / gateway<br/>(RC4, routing)"]
LOGIC["Game logic<br/>(cpp2cs-generated C#)"]
SVCS["Home · Alliance · Matchmaking · Chat"]
PROXY --- LOGIC
LOGIC --- SVCS
end
CLIENT <-->|"Clash of Clans 1.70 protocol<br/>RC4 over TCP / WebSocket"| SERVER
Screenshot gallery¶
-
In a browser tab — WebAssembly + WebGL2. -
On a modern iPhone — the 32-bit game, now native arm64. -
On Android — EGL + OpenSL ES. -
On the macOS desktop.
Recap¶
Four problems, four layers:
- A stripped binary became rebuildable source (reversing).
- ARMv7 machine code became portable C++ (the recompiler).
- iOS became a swappable runtime (the runtime).
- A backend it could no longer reach became a safe C# server (the server).
The result is a 2012 game that no original device can run, brought back as a native app on today's phones, desktops, and the open web — talking to a server that didn't exist a year ago but speaks a protocol from over a decade ago, perfectly.