Enterprise Architecture for the PlayStation 2: Inside jpd002/PlayServices
How a solo developer used clever AWS hacks and a C++ to C# pipeline to build a modern cloud-save engine for a two-decade-old console.
- PlayServices transforms a local emulator into a cloud-native platform using a hybrid C++, C#, and TypeScript architecture.
- The system bypasses S3 limitations by using a reverse-integer naming hack to instantly retrieve the latest game saves.
- Pre-signed AWS URLs eliminate server bandwidth costs by allowing the client to upload heavy save files directly to the cloud.
- Patreon serves as an unconventional Identity Provider to gate premium cloud infrastructure to active project supporters.
Cheating the Alphabet in AWS S3
Amazon S3 is excellent at storing files. S3 is remarkably bad at functioning like a time-series database. When a user boots up a game, the emulator needs to instantly fetch their most recent cloud save. S3 has no native query to get the latest file without fetching the entire bucket contents and sorting them locally.
The solution in GameDataService.cs is a masterclass in exploiting platform quirks. The developer forces S3 to do the sorting by naming files using a reverse index. By subtracting the save version number from the maximum possible integer, the newest file mathematically becomes the first file alphabetically.
string s3Key = $"{userId}/{gameId}/{uint.MaxValue - saveVersion}.ps2";
// Version 10: 4294967285.ps2
// Version 11: 4294967284.ps2 (Appears first in alphabetical sort)
This allows the service to perform a simple list request with a limit of one. The most recent save is always returned instantly. Beyond sorting, the server issues pre-signed URLs to the client. The emulator uploads its 8MB memory card files directly to S3. The C# backend never touches the binary data, reducing server bandwidth costs to absolute zero.
| Metric | Traditional Flow | PlayServices Flow |
|---|---|---|
| Bandwidth Cost | High (Server proxies all files) | $0.00 (Client talks to S3) |
| Server Load | Heavy I/O processing | Lightweight token generation |
| Client Flow | Client -> Server -> Database | Client -> Server (auth) -> S3 (data) |
| Bottleneck Risk | Server network interface | None (Distributed via AWS) |
A Triple-Play Architecture
Building a cloud ecosystem for an emulator requires bridging radically different computing domains. The PlayServices repository manages this by splitting the workload across three distinct languages and environments.
The native client uses high-performance C++ to interface with local SQLite databases, tracking game serials like SLUS-20002. The backend is a scalable C# ASP.NET Core application orchestrating the cloud logic. Finally, a TypeScript and React web frontend gives users a modern dashboard to manage their synchronized data.
The Serverless Build Tracker
The infrastructure also functions as a deployment pipeline. The BuildsController.cs file bridges the GitHub repository with the end-user. When thousands of emulator clients check for updates simultaneously, hitting the GitHub API directly would result in immediate rate-limiting.
To solve this, the developer implemented a 60-second TTL cache in DynamoDB. The server only queries GitHub if the cached commit metadata is older than a minute. This shields the upstream API while providing near real-time update notifications to users globally.
Patreon as an Identity Provider
Authentication is strictly required to keep cloud saves private. Instead of defaulting to Google or GitHub OAuth, the developer made a highly practical business decision. PlayServices uses Patreon's API as its primary Identity Provider.
The backend maps Patreon OAuth tokens to internal GUIDs. This effectively gates premium cloud infrastructure to active project supporters. It ensures the solo developer can afford the AWS hosting costs while maintaining strict data isolation between users.