From 95541b62215bbfbdfd334db1965738c3316c03f7 Mon Sep 17 00:00:00 2001 From: neckfire Date: Wed, 15 Jul 2026 13:54:36 +0200 Subject: [PATCH] docs: rewrite README around our build/CI + client switch tool Replace the upstream Windows/local-run README with a dev-focused one: how the client redirection works (loader+agent+backend.txt), repo structure, building and running the API in a container, the TLS cert SAN gotcha, the Gitea CI/CD branch model (preprod:preprod / main:latest), the Prospect.Client.Config switch+cert tool, and an up-to-date feature status. Co-Authored-By: Claude Opus 4.8 --- README.md | 403 +++++++++++++++++++++++++++++------------------------- 1 file changed, 215 insertions(+), 188 deletions(-) diff --git a/README.md b/README.md index 989053d..549f94c 100644 --- a/README.md +++ b/README.md @@ -1,222 +1,249 @@ -# Prospect - -Also known as "The Cycle: Frontier". - -## Table of Contents - -- [Features](#features) -- [Running locally](#running-locally) - - [1. Prerequisites](#1-prerequisites) - - [1.1 How to download Season 2 client from SteamDB using Steam console](#11-how-to-download-season-2-client-from-steamdb-using-steam-console) - - [2. Unpack `Prospect.Server.Api`](#2-unpack-prospectserverapi) - - [3. Generate and import SSL certificate](#3-generate-and-import-ssl-certificate) - - [4. Extract `LoaderPack` to the game](#4-extract-loaderpack-to-the-game) - - [5. Run the server](#5-run-the-server) - - [6. Run the game](#6-run-the-game) -- [Troubleshooting and FAQ](#troubleshooting-and-faq) - - [How to remove the certificate?](#how-to-remove-the-certificate) - - [`generate_ssl.exe` is flagged as a virus](#generate_sslexe-is-flagged-as-a-virus) - - [Body parts are missing with Season 3 client](#body-parts-are-missing-with-season-3-client) - - [Prospect.Server.Api does not start](#prospectserverapi-does-not-start) - - [Login Failed. Error code: 3](#login-failed-error-code-3) - - [Login Failed. Error code: 5](#login-failed-error-code-5) -- [Development](#development) +# The Cycle: Frontier — serveur privé (émulateur Prospect) + +Émulateur des services en ligne de **The Cycle: Frontier** (jeu retiré de Steam en +septembre 2022), permettant de rejouer en solo sur un serveur auto-hébergé. +Fork de [`deiteris/Prospect`](https://github.com/deiteris/Prospect), figé sur le +**Build 8 / client Saison 2**, buildé depuis les sources et déployé en conteneur via +une CI Gitea. + +> **Ce n'est pas du multijoueur.** Le raid tourne **côté client** (station solo) : chacun +> joue sa propre instance. Le serveur partage la progression, les comptes et les boutiques, +> pas la partie. Le vrai multi (squad en raid, voix de proximité) suppose un serveur de jeu +> Unreal dédié — voir [Hors-périmètre & R&D](#hors-périmètre--rd). + +--- + +## Sommaire + +- [Comment ça marche](#comment-ça-marche) +- [Structure du dépôt](#structure-du-dépôt) +- [Build & lancement du serveur](#build--lancement-du-serveur) +- [Certificat TLS](#certificat-tls) +- [CI/CD](#cicd) +- [Config du client (switch de serveur + certificat)](#config-du-client-switch-de-serveur--certificat) +- [État des fonctionnalités](#état-des-fonctionnalités) +- [Hors-périmètre & R&D](#hors-périmètre--rd) +- [Crédits & licence](#crédits--licence) + +--- + +## Comment ça marche + +Le client officiel parle à PlayFab. On l'intercepte côté client et on le redirige vers +notre serveur, qui réimplémente juste ce qu'il faut de PlayFab (auth Steam, CloudScript, +UserData/TitleData, matchmaking solo). + +```mermaid +flowchart LR + subgraph client [Poste de jeu] + L[Prospect.Client.Loader
injecte l'agent] --> A[Prospect.Agent
hooke l'URL PlayFab] + A -- lit --> B[backend.txt] + A --> G[Jeu (TCF)] + end + G -- HTTPS / SignalR --> API[Prospect.Server.Api
émulateur PlayFab] + API --> M[(MongoDB)] +``` + +- **`Prospect.Client.Loader`** lance le jeu en injectant l'agent. +- **`Prospect.Agent`** hooke l'URL de l'API PlayFab et la remplace par le contenu de + **`backend.txt`** (placé dans `Prospect/Binaries/Win64`). Absent → fallback + `https://127.0.0.1:8443`. +- **`Prospect.Server.Api`** émule PlayFab (auth Steam → JWT, CloudScript, données joueur) + et pousse le temps-réel via **SignalR**. Les données vivent dans **MongoDB**. + +Toute la redirection du client tient donc dans **une seule valeur** (`backend.txt`) — gérée +par l'outil [`Prospect.Client.Config`](#config-du-client-switch-de-serveur--certificat). + +--- + +## Structure du dépôt + +| Projet | Rôle | +|---|---| +| **`Prospect.Server.Api`** | Cœur : émulateur PlayFab (ASP.NET 8). Controllers Client/CloudScript/Multiplayer, services Auth/UserData/TitleData/Database(Mongo)/Qos, hub SignalR. | +| **`Prospect.Steam`** | Validation du ticket Steam (auth). | +| **`Prospect.Client.Loader`** | Loader C++ : lance le jeu et injecte l'agent. | +| **`Prospect.Agent`** | Agent C++ injecté : hooke l'URL PlayFab → `backend.txt`. | +| **`Prospect.Client.Config`** | Utilitaire multi-OS : écrit `backend.txt`, importe le certificat, lance le jeu. Voir son [README](src/Prospect.Client.Config/README.md). | +| **`Prospect.Server.Game`** | Serveur de jeu dédié (squelette, **R&D**). | +| **`Prospect.Unreal[.Generator/.Tests]`** | Réimplémentation C# du netcode Unreal (**R&D** serveur dédié). | +| `utils/` | `generate_ssl.py` — génération du certificat auto-signé. | -## Features +Build config **`Season 2 Release`** obligatoire pour l'API (le code sélectionne la saison +via `#if SEASON_2_RELEASE` / `SEASON_3_RELEASE` → sinon `#error Unsupported build type`). -* [x] Basic login with Steam -* [x] EULA acceptance -* [x] Tutorial -* [x] Single-player station (Season 2 and Season 3): - * [x] Onboarding - * [ ] Matchmaking and deployment - * [x] Solo - * [ ] Squad - * [ ] Items insurance - * [ ] Free loadouts (Season 3) - * [x] Inventory and loadout - * [ ] Loadout presets (Season 3) - * [x] Quests - * [x] Faction progression - * [ ] Season pass - * [ ] Aurum Shops - * [ ] Daily shop - * [ ] Weekly shop - * [ ] Shop rotation - * [x] Daily login - * [x] Character appearance and emotes - * [x] Item Shops - * [x] Crafting station - * [x] Quarters - * [x] Player balance - * [ ] Social features - * [ ] Proximity voice - * [x] Vivox login - * [x] Vivox create and join channel - * [ ] Proximity voice works -* [x] Game mechanics - * [x] Can deploy through terminal - * [x] Can deploy with loadout - * [x] Can evac - * [x] Can do quests (except PvP) - * [x] Can gain/lose loot - * [x] Can use Alien Forge -* [x] Map content - * [x] Bright Sands - * [x] Crescent Falls - * [x] Tharis Island +--- -## Running locally +## Build & lancement du serveur -> [!NOTE] -> If you've already done all steps previously, you can skip to Step 7. +Le serveur tourne en conteneur. L'image est buildée depuis les sources par le +[`Dockerfile`](Dockerfile) (multi-stage SDK .NET 8 → runtime aspnet 8, publish en +`Season 2 Release`). -### 1. Prerequisites +### Build de l'image + +```bash +docker build -t the-cycle . +``` + +### Lancement + +Il faut une **instance MongoDB** joignable et un **certificat TLS** monté (voir section +suivante). Variables d'environnement : + +| Variable | Rôle | +|---|---| +| `DatabaseSettings__ConnectionString` | URI de connexion MongoDB. | +| `DatabaseSettings__DatabaseName` | Base à utiliser (ex. `ProspectDb`). | +| `AuthTokenSettings__Secret` | Secret de signature des JWT émis par le serveur. | +| `PlayFabSettings__SignalRURL` | URL SignalR **telle que le client doit l'atteindre** (voir gotcha ci-dessous). | +| `Kestrel__Certificates__Default__Path` | Chemin du `.pfx` dans le conteneur. | +| `Kestrel__Endpoints__Https__Url` | ex. `https://0.0.0.0:8443`. | +| `SteamWebApiKey` | *(optionnel)* clé Steam Web API pour récupérer les pseudos ; inerte si absente. | -> [!WARNING] -> The latest Steam version of The Cycle: Frontier currently does not work with Windows 11 24H2! +```bash +docker run -d --name the-cycle-api \ + -e DatabaseSettings__ConnectionString="mongodb://user:pass@HOST:27017/?authSource=ProspectDb" \ + -e DatabaseSettings__DatabaseName="ProspectDb" \ + -e AuthTokenSettings__Secret="" \ + -e PlayFabSettings__SignalRURL="https://:8443/signalr/?hub=pubsub" \ + -e Kestrel__Endpoints__Https__Url="https://0.0.0.0:8443" \ + -e Kestrel__Certificates__Default__Path="/certs/certificate.pfx" \ + -v "$PWD/certs:/certs:ro" \ + -p 8443:8443 \ + the-cycle +``` + +> ⚠️ **`PlayFabSettings__SignalRURL` = l'URL que le CLIENT doit joindre**, pas `127.0.0.1`. +> Le serveur y renvoie le client pour l'event de matchmaking ; s'il pointe sur `127.0.0.1`, +> le déploiement en raid **timeout**. Mets le hostname/IP public du serveur. + +### Dev local (.NET) + +```bash +dotnet build src/Prospect.Server.Api/Prospect.Server.Api.csproj -c "Season 2 Release" +dotnet run --project src/Prospect.Server.Api -c "Season 2 Release" +``` + +--- + +## Certificat TLS + +La connexion est en HTTPS et le client valide le certificat → il doit être **auto-signé et +fait confiance** côté client. Générer le `.pfx` avec `utils/generate_ssl.py`. + +> ⚠️ **Le SAN doit contenir `DNS:` ET `IP:`**, en plus des hostnames. +> Le HTTP du jeu (libcurl) accepte l'IP en SAN IP, mais le WebSocket (libwebsockets) valide +> l'IP contre les SAN **DNS** → sans `DNS:`, la connexion SignalR échoue +> (`Hostname mismatch err=62`). Inclure aussi `2EA46.playfabapi.com`, `localhost`, +> `127.0.0.1` et tous les hostnames publics utilisés dans `backend.txt`. + +Côté client, l'import du certificat est automatisé par +[`Prospect.Client.Config`](#config-du-client-switch-de-serveur--certificat). -> [!IMPORTANT] -> You must have The Cycle: Frontier from Steam in your Steam library to be able to download it. -> Otherwise, the download will fail with an error message about missing license. +--- -Before you start, you'll need the following software downloaded and installed: +## CI/CD -1. [MongoDB Community Edition](https://fastdl.mongodb.org/windows/mongodb-windows-x86_64-8.0.4-signed.msi). +[`.gitea/workflows/build.yml`](.gitea/workflows/build.yml) — sur push `main` / `preprod` +(ou `workflow_dispatch`) : -1. [`Prospect.Server.Api` and `LoaderPack`](https://github.com/deiteris/Prospect/releases) from the Releases section: +1. build de l'image depuis le `Dockerfile` ; +2. push sur le registry `git.nfteam.ovh/neckfire/the-cycle` ; +3. notification du résultat (ntfy). - - For Season 3 (the latest Steam game client), use Build 6. +**Modèle de branches :** - - For Season 2 game client, use the latest version. +| Branche | Tag image | Usage | +|---|---|---| +| `preprod` | `:preprod` (+ `:preprod-`) | banc de test — valider un build avant de merger | +| `main` | `:latest` (+ `:`) | production | -1. The Cycle: Frontier game client: +Workflow type : coder → push `preprod` → tester sur le serveur preprod → **PR `preprod → main`** +→ la CI republie `:latest`. Le déploiement applique la nouvelle image +(`docker compose pull && docker compose up -d`). - - The latest version from [Steam](https://steamcommunity.com/app/868270). +> `Prospect.Client.Config` (outil client, cross-OS) n'est **pas** buildé par cette CI — +> voir sa section publication. - - Season 2 client version `4623363103423775682` from SteamDB. See [download instructions below](#11-how-to-download-season-2-client-from-steamdb-using-steam-console). +--- -#### 1.1 How to download Season 2 client from SteamDB using Steam console +## Config du client (switch de serveur + certificat) -> [!WARNING] -> This will overwrite the existing client if you try to download a different manifest! +L'outil **`Prospect.Client.Config`** (binaire `ProspectServerSwitcher`, multi-OS +Linux/Proton + Windows) fait tout le boulot côté client : -1. With Steam running, press `Win+R` and enter `steam://nav/console`. A Steam console will open. +- écrit `backend.txt` (presets **prod** / **preprod** ou URL libre) ; +- récupère le certificat **en direct depuis le serveur ciblé** (TLS) et le rend fiable : + - **Windows** : import dans *Autorités de certification racines de confiance* (utilisateur) ; + - **Linux/Proton** : import direct dans le préfixe Wine du jeu via `wine reg import` + (car `wine certutil` est cassé sous Proton) ; +- lance le jeu. -1. Open [The Cycle: Frontier SteamDB manifests](https://steamdb.info/depot/868271/manifests/). +```bash +# menu interactif +ProspectServerSwitcher -1. Make sure you have **Copy format** set to **Steam console**. +# scriptable +ProspectServerSwitcher --folder "<...>/Prospect/Binaries/Win64" --set preprod +ProspectServerSwitcher --set https://mon-serveur:8443 +``` -1. Press `CTRL+F` and enter `4623363103423775682` to find the manifest for Season 2 version 2.7.2 client. +Détails complets, gotchas Proton (préfixe non-Steam) et commandes de publication des +binaires autonomes : **[src/Prospect.Client.Config/README.md](src/Prospect.Client.Config/README.md)**. + +> Installation complète pas-à-pas pour un nouveau joueur (télécharger le client S2, le +> LoaderPack, importer le certificat) : **[FRIENDS-INSTALL.md](FRIENDS-INSTALL.md)**. -1. Click the ![Copy](./_assets/steamdb_copy.PNG) icon to copy the download command. +--- -1. Paste the command in the Steam console and press `Enter`. +## État des fonctionnalités -1. The depot will begin downloading. You should receive a notification and the destination folder when the download is complete. +**Fonctionne :** -### 2. Unpack `Prospect.Server.Api` +- [x] Login Steam, EULA, tutoriel +- [x] Station solo (S2/S3) : onboarding, matchmaking & déploiement **solo** +- [x] Inventaire & loadout, stash, vente, réparation +- [x] Contrats / quêtes — y compris les objectifs **kills** et **de zone** (auto-crédités : + pas de serveur dédié pour remonter les events runtime du raid client-hosted) +- [x] Progression des factions +- [x] Season pass : claim + gain d'XP de saison (niveau Fortuna) +- [x] Boutiques d'items (Korolev / ICA / Osiris / QuickShop / CraftingStation) +- [x] Aurum Shop (cosmétiques) + rotation daily/weekly +- [x] Craft, Quarters, solde joueur, connexion quotidienne +- [x] Apparence & emotes +- [x] Assurance : débit de la prime au déploiement + payout à la mort +- [x] Stats de carrière (valeurs à 0 — non traçables sans serveur de jeu) +- [x] Présence des amis (en ligne / en raid) +- [x] Pseudos réels via Steam Web API (le client n'envoie que le SteamID) +- [x] Cartes : Bright Sands, Crescent Falls, Tharis Island -Use your favorite ZIP archiver and unzip the `Prospect.Server.Api.zip` downloaded from this repository. +**Non implémenté / hors-périmètre :** -### 3. Generate and import SSL certificate +- [ ] Squad / multi dans le **même** raid — nécessite un serveur de jeu dédié +- [ ] Voix de proximité (login/join Vivox = placeholders) +- [ ] Free loadouts & presets (Saison 3 uniquement) +- [ ] Achat de cosmétiques (endpoint d'achat vanity distinct, non câblé) +- [ ] Catalogue des récompenses Fortuna (DataTable côté client, dans des paks chiffrés) +- [ ] Défis quotidiens Fortuna -> [!IMPORTANT] -> Do not share the generated certificate! Generated certificate includes a private key that may be used to generate other certificates and compromise your security. +--- -A connection to the server is served over a secured connection. The server uses self-signed certificate that must be added to trusted authorities in order for the game -to successfully communicate with the local server. Do the following: +## Hors-périmètre & R&D -1. Open the folder with `Prospect.Server.Api`. +Un **serveur de jeu Unreal dédié** (`Prospect.Server.Game` + `Prospect.Unreal`, branche +`game-server`) est en cours de reverse-engineering pour, à terme, permettre le vrai multi. +État : handshake stateless UE, séquençage et décodage des bunches **franchis**, canal de +contrôle ouvert, `NMT_Hello` parsé. **Bloqué** sur le chiffrement **DTLS-PSK** du client +(clé dérivée du `user_id`), derrière un exe packé (BattlEye) → la dérivation n'est pas +extractible statiquement. Détails dans `NETCODE-RND.md` (branche `game-server`). -1. Double-click `generate_ssl.exe`. `certificate.pfx` will appear in the same folder. +Le « lobby squad » via l'API seule n'est **pas faisable** : l'invitation d'amis est gérée +100 % côté client Steam. -1. Double-click `certificate.pfx`. The Certificate Import Wizard will open: +--- - 1. Select **Current User** under Store Location and click **Next**. +## Crédits & licence - 1. Leave **File to Import** unchanged and click **Next**. - - 1. Leave **Password** empty and click **Next**. - - 1. Select **Place all certificates in the following store** > **Browse...**. Choose **Trusted Root Certification Authorities** and click **OK**. Click **Next**. - - 1. Click **Finish**. A **Security Warning** popup may appear, make sure it specifies `2EA46.playfabapi.com` certification authority and click **Yes**. - -### 4. Extract `LoaderPack` to the game - -1. Open the folder with The Cycle: Frontier and navigate to **Prospect** > **Binaries** > **Win64**. - -1. Open the `LoaderPack` archive. - -1. Drag and drop the contents of the `LoaderPack` archive to the game. - -1. Create a shortcut for the `Prospect.Client.Loader` that you will use later to launch the game. - -### 5. Run the server - -Now you are all set! Open the folder with `Prospect.Server.Api` and run `Prospect.Server.Api.exe`. It will open a console if it runs successfully. - -> [!IMPORTANT] -> Do not close the console when you run the game. - -### 6. Run the game - -Once the server is running, make sure that Steam is running and open The Cycle: Frontier using the shortcut you've created before. - -## Troubleshooting and FAQ - -### How to remove the certificate? - -If you've installed the certificate for the **Current User**: - -1. Open **Start** and enter `certmgr.msc`. - -1. Expand **Trusted Root Certification Authorities** and select **Certificates**. - -1. Find `2EA46.playfabapi.com`, right-click it > **Delete**. - -If you've installed the certificate for the **Local Machine**, repeat the same steps but instead open `certlm.msc`. - -### `generate_ssl.exe` is flagged as a virus - -`generate_ssl.exe` is a Python application packed with PyInstaller and some anti-viruses may flag it as a virus. -This application is a simple certificate generator and you can find its source code in `utils/generate_ssl.py`. - -### Body parts are missing with Season 3 client - -Currently, the server loads body part IDs for Season 2 by default, so this is expected. You can fix this by going to station and changing your character appearance. This will store the updated body part IDs for your character. - -### Prospect.Server.Api does not start - -Make sure you have [.NET Runtime 8.0](https://aka.ms/dotnet-core-applaunch?missing_runtime=true&arch=x64&rid=win-x64&os=win10&apphost_version=8.0.11) and [ASP.NET Core 8.0](https://aka.ms/dotnet-core-applaunch?framework=Microsoft.AspNetCore.App&framework_version=8.0.0&arch=x64&rid=win-x64&os=win10) installed. - -### Login Failed. Error code: 3 - -Make sure that: - -* You have Steam running. -* You have created and **saved** the `steam_appid` file as described in step 6. -* The `steam_appid` file type is "TXT File". - -### Login Failed. Error code: 5 - -Make sure that `Prospect.Server.Api` server is running. - -If the server is running, press `Alt+Tab` to a game console that opens when you start the game and check for the following: - -* `libcurl error 7 (Couldn't connect to server)` - indicates that the `Prospect.Server.Api` is not running. - ![](./_assets/connection_refused_error.png) - -* `InvalidAPIEndpoint` - indicates that you are running the game using the original shortcut and not using `Prospect.Client.Loader`. - ![](./_assets/invalid_api_endpoint.PNG) - -* `libcurl error 60 (Peer certificate cannot be authenticated with given CA certificates)` - indicates that the certificate was not installed correctly. Make sure that the certificate is present in `certmgr.msc` and there is only one certificate. Try removing the certificate and importing it again by following step 4. - ![](./_assets/certificate_error.PNG) - -* `HTTP code: 500` - usually indicates that MongoDB is not running. Make sure that MongoDB is installed and and that `MongoDB Server` is running in `services.msc`. - ![](./_assets/mongodb_error.PNG) - -## Development - -TBD +Fork de [`deiteris/Prospect`](https://github.com/deiteris/Prospect) (lui-même issu du +projet Prospect original). Voir [`LICENSE`](LICENSE). Usage privé.