decentraland / decentraland/creator-hub

Support Epic Games Store client detection and launch as fallback for decentraland:// protocol

Open
#1,301 0 comments 0 reactions 0 assignees View on GitHub
enhancement
Dominant language
TypeScript
Stars
7
Forks
14
Avg merge
2d 8h
Merged PRs (30d)
44

Description

## Summary

When Decentraland is installed via the Epic Games Store (EGS), the Creator Hub cannot detect it or launch previews. The `decentraland://` protocol handler is registered by the **Decentraland Launcher** (launcher-rust), which is not bundled with the EGS distribution. This means:

1. The Creator Hub's preview button fails with _"Failed to start preview. Check your scene code for errors"_ — a misleading message since the actual cause is client detection failure
2. dApps and the Content Hub also fail to launch via deeplink for the same reason
3. The EGS-installed client is completely invisible to the Creator Hub

### Screenshots from thread
The error modal shows: `Command "reg query HKEY_CLASSES_ROOT\\decentraland /ve" exited with code 1` — confirming the `decentraland://` protocol isn't registered for EGS installs.

## Root Cause

In `packages/creator-hub/main/src/modules/bin.ts`, the `dclDeepLink()` function checks for the `HKEY_CLASSES_ROOT\decentraland` registry key (Windows) or uses `open` (macOS). This only works when the Decentraland Launcher has registered the protocol. Epic Games Store installs don't include the launcher, so the protocol is never registered.

Additionally, in `packages/creator-hub/renderer/src/modules/store/snackbar/slice.ts`, the `editorActions.runScene.rejected` handler **always** shows the "Failed to start preview" snackbar, even for `CLIENT_NOT_INSTALLED` errors — which are already handled by the `InstallClient` modal in the EditorPage. This means users see both a misleading error toast AND the install modal.

## Proposed Solution

### Priority Detection Flow

Extend client detection with the following priority order:

1. **`decentraland://` protocol** → If resolvable, use it (current behavior, keep as top priority)
2. **Epic Games Store fallback** → If `decentraland://` fails, check for EGS installation + Decentraland installed via EGS → launch via `com.epicgames.launcher://` protocol
3. **Fallback** → Show InstallClient modal (current fallback behavior)

### Implementation Plan

**Repos involved:**
- `decentraland/creator-hub` — all changes are in this repo

#### 1. New module: `packages/creator-hub/main/src/modules/epic.ts`

Create an Epic Games detection/launch module:

```typescript
// Detection functions:
async function isEpicLauncherInstalled(): Promise
// Windows: reg query "HKEY_CLASSES_ROOT\com.epicgames.launcher"
// macOS: existsSync('/Applications/Epic Games Launcher.app')

async function findDecentralandEpicManifest(): Promise
// Windows: scan C:\ProgramData\Epic\EpicGamesLauncher\Data\Manifests\*.item
// (or derive path from HKLM\SOFTWARE\WOW6432Node\EpicGames\EpicGamesLauncher AppDataPath)
// macOS: scan ~/Library/Application Support/Epic/EpicGamesLauncher/Data/Manifests/*.item
// Match by CatalogNamespace, verify bIsIncompleteInstall === false && InstallLocation exists

async function launchViaEpic(catalogNamespace: string): Promise
// Open com.epicgames.launcher://apps/{namespace}?action=launch&silent=true
```

**Key constant needed:** The Decentraland EGS `CatalogNamespace` — this must be obtained from the team that publishes to EGS and hardcoded as a constant.

#### 2. Modify `dclDeepLink()` in `packages/creator-hub/main/src/modules/bin.ts`

Add EGS fallback when native protocol check fails:

```typescript
export async function dclDeepLink(deepLink: string) {
try {
if (process.platform === 'win32') {
await exec('reg query "HKEY_CLASSES_ROOT\\decentraland"');
}
const command = process.platform === 'win32' ? 'start' : 'open';
await exec(`${command} decentraland://"${deepLink}"`);
} catch (e) {
// NEW: Try Epic Games Store fallback
const epicInstalled = await isEpicLauncherInstalled();
if (epicInstalled) {
const manifest = await findDecentralandEpicManifest();
if (manifest) {
await launchViaEpic(manifest.CatalogNamespace);
return; // Successfully launched via EGS
}
}
throw new ClientError('CLIENT_NOT_INSTALLED', CLIENT_NOT_INSTALLED_ERROR);
}
}
```

**Note:** When launching via EGS, the preview server URL (realm parameter) needs to be passed to the game. Investigate whether `com.epicgames.launcher://` supports passing launch arguments to the game, or whether the preview server URL can be communicated via a temporary file or environment variable.

#### 3. Fix the misleading snackbar in `packages/creator-hub/renderer/src/modules/store/snackbar/slice.ts`

Suppress the "Failed to start preview" snackbar when the error is `CLIENT_NOT_INSTALLED` (since the EditorPage already handles this with the InstallClient modal):

```typescript
.addCase(editorActions.runScene.rejected, (state, payload) => {
// Don't show snackbar for CLIENT_NOT_INSTALLED — handled by InstallClient modal
if (payload.error.name === 'CLIENT_NOT_INSTALLED') return;

const { requestId } = payload.meta;
state.notifications = state.notifications.filter($ => $.id !== requestId);
state.notifications.push(
createGenericNotification('error', t('snackbar.generic.preview_scene_failed'), {
requestId,
duration: 0,
description: payload.error.message,
}),
);
})
```

#### 4. Modify `start()` in `packages/creator-hub/main/src/modules/cli.ts`

The `start()` function has **two paths** that produce `CLIENT_NOT_INSTALLED`:
- **Path A**: `dclDeepLink()` call when re-launching an existing preview (line ~218) — automatically benefits from the `dclDeepLink` changes
- **Path B**: `sdk-commands` CLI stdout contains the error string (line ~237) — this is the first-launch case where the CLI itself detects no client

For Path B, consider adding the same EGS fallback before throwing:

```typescript
if (resultLogs.includes(CLIENT_NOT_INSTALLED_ERROR)) {
// Try EGS fallback before giving up
const epicFallbackSucceeded = await tryEpicFallback(/* preview server URL */);
if (!epicFallbackSucceeded) {
throw new ClientError('CLIENT_NOT_INSTALLED', CLIENT_NOT_INSTALLED_ERROR);
}
}
```

### Files to Create/Modify

| File | Action | Description |
|------|--------|-------------|
| `packages/creator-hub/main/src/modules/epic.ts` | Create | EGS detection & launch module |
| `packages/creator-hub/main/src/modules/bin.ts` | Modify | Add EGS fallback to `dclDeepLink()` |
| `packages/creator-hub/main/src/modules/cli.ts` | Modify | Add EGS fallback to `start()` Path B |
| `packages/creator-hub/renderer/src/modules/store/snackbar/slice.ts` | Modify | Suppress snackbar for `CLIENT_NOT_INSTALLED` |
| `packages/creator-hub/main/tests/modules/epic.spec.ts` | Create | Unit tests for EGS detection |
| `packages/creator-hub/main/tests/modules/bin.spec.ts` | Modify | Add tests for EGS fallback in `dclDeepLink` |

### Configuration

| Item | Description |
|------|-------------|
| `DECENTRALAND_EGS_CATALOG_NAMESPACE` | Hardcoded constant — the CatalogNamespace from EGS for Decentraland. Must be obtained from the team that publishes to EGS. |

### Open Questions

1. **What is Decentraland's `CatalogNamespace` on EGS?** This is needed to detect the game in EGS manifests and to construct the launch URL. Someone with EGS access can find it in `C:\ProgramData\Epic\EpicGamesLauncher\Data\Manifests\*.item` on a machine with DCL installed via EGS.
2. **Can launch arguments be passed via `com.epicgames.launcher://` protocol?** The preview needs to pass the realm URL to the Explorer. If EGS protocol doesn't support extra args, alternatives include: writing params to a temp file, using a localhost HTTP handshake, or launching the executable directly from `InstallLocation` in the manifest.
3. **Does the EGS-installed Explorer binary support the same command-line arguments as the launcher-distributed one?** This affects whether the preview server URL can be passed directly.

### Testing Strategy

- **Unit tests**: Mock `exec` and `fs` to test all detection paths (Windows/macOS, EGS installed/not, game installed/not, corrupt manifests)
- **Manual testing**: Install DCL via EGS, uninstall the native launcher, verify Creator Hub preview works via EGS fallback
- **Edge cases**: EGS installed but DCL not, DCL partially installed (`bIsIncompleteInstall`), both native launcher and EGS installed (native should take priority)

Requested by Gabriel Díaz via Slack

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.