# PlayGo Scenarios Supported by SharpEmu: Complete PS4/5 Content Download Emulation

> Discover the 14 PlayGo scenarios SharpEmu emulates for PS4/PS5 content download. Experience PlayStation chunk-based game installation without PSN.

- Repository: [Berk/sharpemu](https://github.com/par274/sharpemu)
- Tags: deep-dive
- Published: 2026-07-13

---

**SharpEmu implements 14 PlayGo scenarios through the `libScePlayGo` system library, exposing Sony PlayStation 4/5 content-download functions via the static `PlayGoExports` class to emulate chunk-based game installation without requiring actual PlayStation Network infrastructure.**

SharpEmu is an open-source emulator for PlayStation 4 and 5 software that replicates the `libScePlayGo` system library to support games utilizing PlayGo content delivery. The **PlayGo scenarios supported by SharpEmu** cover the full lifecycle of chunk-based downloads, from initialization and handle management to progress queries and language masking. These scenarios are implemented as a stub backend in `SharpEmu.Libs.PlayGo.PlayGoExports`, allowing games to execute their download logic while the emulator provides synthetic metadata and state responses.

## Complete List of PlayGo Scenarios in SharpEmu

The emulator exposes all core PlayGo functionality through the `PlayGoExports` static class in [`src/SharpEmu.Libs/PlayGo/PlayGoExports.cs`](https://github.com/par274/sharpemu/blob/main/src/SharpEmu.Libs/PlayGo/PlayGoExports.cs). Each scenario maps directly to a Sony system call that games invoke to manage on-demand content installation.

### Session Lifecycle Management

- **scePlayGoInitialize**: Initializes the PlayGo subsystem and parses the game's [`play-go.xml`](https://github.com/par274/sharpemu/blob/main/play-go.xml) metadata via `LoadPlayGoMetadata`. This validates the chunk configuration and prepares the internal `_metadata` structure.
- **scePlayGoOpen**: Opens a PlayGo handle, returning `1` as the valid handle value to the caller. The emulator tracks a single global handle.
- **scePlayGoClose**: Closes the active PlayGo handle and resets session-specific state.
- **scePlayGoTerminate**: Shuts down the PlayGo subsystem entirely, clearing all internal metadata and configuration.

### Content Chunk Queries

- **scePlayGoGetChunkId**: Retrieves available chunk IDs from the parsed metadata stored in `_metadata.ChunkIds`.
- **scePlayGoGetLocus**: Reports the download status (locus) of each chunk, indicating whether content is local, on disc, or needs downloading.
- **scePlayGoGetToDoList**: Returns the list of chunks awaiting download.
- **scePlayGoPrefetch**: Ensures specified chunks are at a specific locus, simulating the prefetching behavior.

### Download Progress and Speed Control

- **scePlayGoGetEta**: Returns the estimated time of arrival for downloads (currently stubbed to return `0`).
- **scePlayGoGetProgress**: Queries the current download progress percentage.
- **scePlayGoGetInstallSpeed**: Retrieves the current installation speed setting.
- **scePlayGoSetInstallSpeed**: Modifies the installation speed (e.g., setting to full speed).

### Language and Localization

- **scePlayGoGetLanguageMask**: Retrieves the current language mask for content filtering.
- **scePlayGoSetLanguageMask**: Sets the language mask to filter which language-specific chunks should be prioritized.

## Architecture and Implementation Details

All PlayGo scenarios share a common implementation pattern in [`PlayGoExports.cs`](https://github.com/par274/sharpemu/blob/main/PlayGoExports.cs) designed to ensure thread safety and state consistency.

**Handle Validation**: Every function first invokes `ValidateHandle` to verify the caller is using the single valid handle (`PlayGoHandle == 1`). This mimics the real PlayGo API's handle-based access control.

**Thread-Safe State Management**: Static fields including `_metadata`, `_installSpeed`, and `_languageMask` are guarded by the `_stateGate` lock object. This ensures concurrent emulated threads accessing PlayGo functions receive consistent state without race conditions.

**Metadata Parsing**: During initialization, the emulator parses the game's [`play-go.xml`](https://github.com/par274/sharpemu/blob/main/play-go.xml) file to populate `_metadata.ChunkIds` and determine the `Available` flag. This metadata drives the responses to chunk query functions, determining which IDs the game can legitimately request.

**Stub Implementation**: Because SharpEmu provides a stub PlayGo backend, many functions return success codes while performing minimal work. For example, `scePlayGoGetEta` always returns `0` and `scePlayGoPrefetch` returns immediately without actual network operations. This design allows games to progress through their download logic without requiring a real PlayStation Network connection.

## Practical Example: Calling PlayGo Functions

When emulating a game, the runtime invokes these exports through the system ABI. Below is a C# example demonstrating a typical PlayGo workflow using `SharpEmuRuntime`:

```csharp
// Initialize PlayGo - parses play-go.xml and prepares the subsystem
int initResult = runtime.InvokeExport("scePlayGoInitialize", cpuContext);
Console.WriteLine($"Init result: {initResult}");

// Open a handle - returns 1 as the valid handle
int openResult = runtime.InvokeExport("scePlayGoOpen", cpuContext);
Console.WriteLine($"Open result: {openResult}");

// Query available chunk IDs
int chunkResult = runtime.InvokeExport("scePlayGoGetChunkId", cpuContext);
Console.WriteLine($"GetChunkId result: {chunkResult}");

// Check current download speed
int speedResult = runtime.InvokeExport("scePlayGoGetInstallSpeed", cpuContext);
Console.WriteLine($"Current speed: {speedResult}");

// Set install speed to full
int setSpeedResult = runtime.InvokeExport("scePlayGoSetInstallSpeed", cpuContext);

// Query download progress
int progressResult = runtime.InvokeExport("scePlayGoGetProgress", cpuContext);

// Close the handle when complete
int closeResult = runtime.InvokeExport("scePlayGoClose", cpuContext);

```

The `InvokeExport` method (implemented in `SharpEmu.Core.Runtime.SharpEmuRuntime`) maps these string names to the corresponding static methods in `PlayGoExports`, passing the `CpuContext` parameter for memory access. Each exported method is annotated with `SysAbiExportAttribute` to define its NID and library association.

## Summary

- SharpEmu supports **14 PlayGo scenarios** covering initialization, chunk queries, progress monitoring, and language configuration.
- All scenarios are implemented in `SharpEmu.Libs.PlayGo.PlayGoExports` as a stub backend that simulates PlayStation 4/5 content download behavior.
- The emulator uses a single handle (`PlayGoHandle == 1`) validated through `ValidateHandle` across all functions.
- Thread safety is enforced via the `_stateGate` lock protecting shared state fields.
- Games must provide a [`play-go.xml`](https://github.com/par274/sharpemu/blob/main/play-go.xml) file which the emulator parses during `scePlayGoInitialize` to define available chunks.

## Frequently Asked Questions

### What is PlayGo and why does SharpEmu need to support it?

PlayGo is Sony's system for progressive downloading of game content on PlayStation 4 and 5, allowing games to start before all data is installed. SharpEmu implements these scenarios to prevent games that rely on PlayGo APIs from crashing or stalling during boot sequences that check download status.

### Does SharpEmu perform actual downloads or is it just a stub?

SharpEmu provides a **stub implementation**. Functions like `scePlayGoPrefetch` and `scePlayGoGetEta` return success codes without performing network operations. The emulator assumes all content is locally available while maintaining the API contract that games expect.

### How does SharpEmu handle PlayGo metadata?

During `scePlayGoInitialize`, the emulator calls `LoadPlayGoMetadata` to parse the game's [`play-go.xml`](https://github.com/par274/sharpemu/blob/main/play-go.xml) file. This XML defines the chunk layout, which the emulator stores in `_metadata.ChunkIds` to service subsequent queries about available content.

### Are all PlayGo functions fully implemented?

While all 14 major scenarios are present, many are minimally implemented. Critical path functions like opening handles and querying chunk IDs return valid data parsed from the XML, while time-dependent functions like `scePlayGoGetEta` return static values. This balance allows games to boot without requiring a full PlayStation Network stack.