LifePlay-Revival/Docs/Migration/etat/REL/MAPDL1/MAPDL1-E5-FICHE.md
2026-10-22 21:10:39 +02:00

11 KiB

Fiche MAPDL1-E5 — Niveau N3 — Modèle prévu sonnet (agent lp-impl ; escalade lp-impl-max) — Agent lp-impl — Skills sk-protocol, lp-city, lp-lot, ue-cpp-build

MAPDL1-E5 : téléchargement et installation des packs dans le jeu (C6 de MAPDL1-SPEC-05 v3)

GO de Big Boss. Ce lot fait partie de la réalisation approuvée par l'utilisateur, citée : « Oui : SPEC-05 v3 approuvée (S5-1 à S5-5, D10 = téléchargement HTTP dans le jeu avec navigateur en recours, D11 = un zip par pack). Lance la réalisation avec les modèles réduits ; l'hébergeur et le domaine, je les choisis plus tard. »

Hors moteur :

  • aucune compilation (E2 bis, sous jeton, plus tard), aucun commandlet, aucun éditeur ;
  • aucun appel réseau réel ;
  • aucun commit, aucun Blueprint ;
  • rien sous Mods\.

À lire d'abord :

  • MAPDL1-SPEC-05-v3.md (§ 1 à 4) et MAPDL1-SPEC-05-v2.md (§ 2 : fenêtre, licence, accord, deux boutons) ;
  • MAPDL1-E1-IMPL.md et MAPDL1-E3-VAL.md ;
  • le code d'E1 : Source/LifePlay/LPCityMapsSubsystem.h/.cpp ;
  • le modèle de fenêtre : Source/LifePlay/LPModInfoSubsystem.cpp:375-422 (ShowWarning, AddViewportWidgetContent).

0. Avant toute écriture

  • Instantané .\Tools\Snapshot.ps1 -Lot MAPDL1-E5 -Path <chemin>, depuis pwsh, un chemin par appel, pour chaque fichier du § 1.
  • MD5 avant et après de tous ces fichiers, et MD5 des fichiers de ville de STM1 (LPCityWater*, LPCityNames*, LPCityHouses.h, LPCityLandmarks.h, LPAssetRegistryHelpers.*) : ils doivent rester inchangés.
  • git status --short sur les fichiers du § 1.

1. Fichiers (et seulement ceux-là)

Fichier État Contenu
Source/LifePlay/LPCityMapsDownload.h/.cpp A téléchargement, contrôle et pose (§ 2.2 à 2.5), sans dépendance à l'UI
Source/LifePlay/LPCityMapsWindow.h/.cpp A fenêtre Slate (§ 2.1), sur le modèle de LPModInfoSubsystem::ShowWarning
Source/LifePlay/LPCityMapsSubsystem.h/.cpp M le clic d'une ligne téléchargeable ouvre la fenêtre au lieu du navigateur ; nouvel état RestartRequired (§ 2.6)
Source/LifePlay/LifePlay.Build.cs M PrivateDependencyModuleNames : "HTTP", "OpenSSL", "libzip" (commentaire « Lot MAPDL1 (E5) »)
Content/Data/Licenses/OpenStreetMap_Geodata_License.txt et Content/Data/Licenses/Vinfamy_License.txt A copies à l'octet de Licenses/… (MD5 identiques), pour qu'elles soient livrées dans le pak (le dossier Licenses/ ne l'est pas dans la build)
Content/Data/LPCityMaps.json M licences.*.fichier devient Data/Licenses/<nom> ; rien d'autre ne change

Conventions : style des fichiers voisins (commentaires en français sans accents), outil Edit pour modifier, Write pour les fichiers neufs, LF.

2. Contenu

2.1 Fenêtre « City map: » (Slate, en anglais, ordre Z élevé, fermable)

  • Informations : ville, version, taille en Mo, hôte de urls[0] (seulement le nom d'hôte), provenance (source), et « Active after the next game launch ».
  • Licence : les titre des licences de l'entrée. Le bouton « Read the full licence » affiche dans la fenêtre, avec défilement, le texte de FPaths::ProjectContentDir()/<fichier>. Fichier absent : « Licence text not found: ».
  • Case « I have read and accept the licence of this map », non cochée. Les deux boutons d'action restent désactivés tant qu'elle n'est pas cochée.
  • Boutons : « Download only », « Full install », « Cancel ».
  • Progression : barre, octets reçus / octets totaux, débit, « Cancel » qui interrompt. Le .part est gardé pour une reprise.
  • Messages :
    • erreur en clair (« Download failed: … », « SHA-256 mismatch », « Install failed: … ») ;
    • réussite « Downloaded: » avec un bouton « Open folder » (FPlatformProcess::ExploreFolder) ;
    • réussite « Installed. Restart the game to play . ».
  • Recours quand toutes les URL ont échoué : bouton « Open in browser » (page, sinon urls[0], par FPlatformProcess::LaunchURL), puis surveillance du dossier Téléchargements (§ 2.5), plus un bouton « Choose file… » (§ 2.5).
  • Une seule fenêtre à la fois ; un seul téléchargement à la fois.

2.2 Téléchargement HTTP (FHttpModule, IHttpRequest)

Point Règle
Fichier partiel FPaths::ProjectSavedDir()/Downloads/<pack>/<zip>.part. Écriture en flux par SetResponseBodyReceiveStream (IHttpRequest.h:271), sur un FArchive ouvert en ajout (IFileManager::CreateFileWriter, drapeau d'ajout)
Reprise .part présent de taille t > 0 : SetHeader("Range", "bytes=t-") (IHttpRequest.h:297). Réponse 206 avec un Content-Range qui commence à t : on continue. Réponse 200 : le .part est déplacé dans Saved/Downloads/_rejet/ (horodaté) et le téléchargement repart de zéro, dans un fichier neuf
Progression OnRequestProgress64 (IHttpRequest.h:366)
Délais SetActivityTimeout(30) (IHttpRequest.h:328) ; aucun délai total
Essais 3 par URL, avec 2, 4 puis 8 s d'attente (ticker FTSTicker, sans bloquer le fil de jeu), puis l'URL suivante. Statut hors 200 et 206, ou taille finale différente d'octets : essai suivant
Redirections à vérifier dans les sources du moteur 5.8 : quel client HTTP sert Win64 (Curl, ou WinHttp ; voir Engine/Source/Runtime/Online/HTTP/HTTP.Build.cs et …/Private/Windows/) et s'il suit les redirections (Curl : CURLOPT_FOLLOWLOCATION posé à 1, …/Private/Curl/CurlHttp.cpp:183). Citer fichier:ligne dans l'IMPL. Le journal donne l'URL finale si l'API la fournit (GetEffectiveURL ou équivalent, à vérifier)
Sûreté URL https:// seulement (déjà filtrées par l'index) ; en-tête User-Agent: LifePlay-CityMaps/1.0 ; aucune donnée du joueur envoyée
Journal [LPCity] DOWNLOAD <ville> : <url> statut <n> octets <recus>/<total> (reprise a <t>), et … : echec <raison>

2.3 Contrôle SHA-256 (OpenSSL, par morceaux)

  • Module OpenSSL du moteur (Engine/Source/ThirdParty/OpenSSL, 1.1.1t ; E0 Q4). #include "openssl/evp.h" entre THIRD_PARTY_INCLUDES_START et THIRD_PARTY_INCLUDES_END, puis EVP_MD_CTX_new, EVP_DigestInit_ex(ctx, EVP_sha256(), nullptr), EVP_DigestUpdate par blocs de 1 Mio lus avec IFileManager::CreateFileReader, EVP_DigestFinal_ex et EVP_MD_CTX_free.
  • Le calcul se fait hors du fil de jeu (Async(EAsyncExecution::ThreadPool, …)), avec un retour sur le fil de jeu (AsyncTask(ENamedThreads::GameThread, …)).
  • Comparaison sans tenir compte de la casse avec sha256 de l'index.
  • En cas d'écart : le fichier est déplacé dans Saved/Downloads/_rejet/ et le jeu passe à l'URL suivante.
  • Journal : [LPCity] SHA256 <ville> : <valeur> conforme|ECART.

2.4 « Download only » et « Full install »

  • Download only : quand le téléchargement est complet et conforme, <zip>.part est renommé en Saved/Downloads/<zip>. La ville reste « téléchargeable ».
  • Un Saved/Downloads/<zip> déjà présent, de la bonne taille et au bon SHA-256 (recontrôlé), sert directement : aucun nouveau téléchargement.
  • Full install : la même chose, puis la pose :
    1. refus dans l'éditeur (GIsEditor) : « Full install is only available in the packaged game ». La copie de travail ne doit jamais recevoir de pack dans Mods\ ;
    2. ouverture du zip par libzip (zip_open en lecture seule) et contrôle des membres :
      • chaque nom commence par LifePlay/Mods/<pack>/ ou LifePlay/Content/Modules/<pack>/, ou vaut README.txt (ignoré) ;
      • aucun .., aucun \, aucun chemin absolu, aucun autre préfixe ;
      • le membre LifePlay/Mods/<pack>/<pack>.uplugin est présent ;
      • sinon : refus, et rien n'est posé ;
    3. extraction dans Saved/Downloads/<pack>/_pose/ (dossier neuf), puis destinations : FPaths::ProjectDir() + le chemin du membre sans le préfixe LifePlay/ ;
    4. une installation existante de ce pack (Mods/<pack> ou Content/Modules/<pack>) est d'abord déplacée dans Saved/Downloads/_ancien/<pack>-<horodatage>/ ;
    5. Content/Modules/<pack> est posé en premier, Mods/<pack> en dernier, par IFileManager::Move ;
    6. retour en arrière si une étape échoue : les déplacements déjà faits sont défaits dans l'ordre inverse, puis l'ancienne installation est remise. Rien n'est jamais supprimé (_pose/ reste, et sert de trace) ;
    7. journal [LPCity] INSTALL <ville> : <n> fichiers poses (Modules puis Mods), ou … : echec <raison>, retour arriere <ok|ECHEC>.

2.5 Recours (c), quand toutes les URL échouent

  • « Open in browser » : page, sinon urls[0].
  • Surveillance du dossier Téléchargements de Windows, tant que la fenêtre est ouverte, toutes les 2 s :
    • le dossier se trouve par SHGetKnownFolderPath(FOLDERID_Downloads) (sous PLATFORM_WINDOWS, avec Windows/AllowWindowsPlatformTypes.h) ;
    • un fichier .zip de taille exactement octets, au SHA-256 conforme, est copié (le fichier du joueur reste) vers Saved/Downloads/<zip> ;
    • ensuite, comme 2.4 (« Download only » ou « Full install » selon le bouton choisi).
  • « Choose file… » : sélecteur de fichier Win32 (GetOpenFileNameW, commdlg.h, sous PLATFORM_WINDOWS) ; même contrôle, puis même suite. Si son usage en Shipping pose un problème de liaison, laisser le bouton désactivé avec un commentaire, et le signaler dans l'IMPL.

2.6 Changements dans LPCityMapsSubsystem

  • ELPCityMapState reçoit RestartRequired, après Unavailable (l'ordre des valeurs existantes ne change pas).
  • Une ville passe à RestartRequired après une pose réussie dans cette session. Dans le menu : texte « Restart required », couleur (0.6, 0.6, 1.0), clic sans effet. Pour le tri, elle compte avec les téléchargeables.
  • ULPCityRowClick::OnClicked ouvre la fenêtre (§ 2.1) au lieu de OpenCityPage, qui reste pour le recours.
  • Deinitialize : annule le téléchargement en cours, garde le .part et ferme la fenêtre.

3. Contrôles hors moteur

  1. git diff --stat et liste des fichiers ajoutés ; MD5 avant et après ; MD5 des fichiers de STM1 inchangés.
  2. Fins de ligne : git ls-files --eol des fichiers modifiés ; 0 CR et pas de BOM dans les fichiers neufs.
  3. Copies de licence : MD5 identiques à Licenses/….
  4. Test-Json de LPCityMaps.json.
  5. Lecture critique du code par toi : chemins de pose, retour en arrière, aucun Delete (Grep Delete), aucun appel réseau dans un chemin d'éditeur au démarrage.

4. Livrable

Docs\Migration\etat\REL\MAPDL1\MAPDL1-E5-IMPL.md :

  • en-tête sk-protocol, avec le modèle réellement utilisé ;
  • fichiers, MD5, diff résumé ;
  • API vérifiées avec fichier:ligne (HTTP, redirections, OpenSSL, libzip, Win32) ;
  • choix faits ;
  • points à vérifier à la compilation et en jeu ;
  • compte rendu.

Budget : 70 tours. En cas de blocage : arrêt et rapport, sans contourner.