14 KiB
Fiche MAPDL1-E1 — 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-E1 : états des villes et menu (C1 à C5 de MAPDL1-SPEC-05 v3), en C++, sans Blueprint
Décision de l'utilisateur, citée par Big Boss : « 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 :
- aucun build, aucun commandlet, aucun éditeur. La compilation est l'étape E2, sous jeton ;
- aucun commit ;
- rien sous
Mods\; - aucun Blueprint modifié.
Le téléchargement HTTP (C6) n'est pas dans cette fiche : c'est E5.
Références à lire d'abord :
MAPDL1-SPEC-05.md(v1, § 1-2),MAPDL1-SPEC-05-v3.md(§ 1),MAPDL1-E0-INV.md;MAPDL1-L1-CART-02.mdetMAPDL1-L4-CART-01.md(menu, lignesCity_C, calcul « Installed ») ;- modèle de code :
Source/LifePlay/LPModInfoSubsystem.h/.cpp,TickModManager. Il trouve unUScrollBoxparTObjectIterator, lit des variables de Blueprint parFindPropertyByNameet modifie les lignes.
0. Avant toute écriture
- Instantané, depuis pwsh, un chemin par appel :
.\Tools\Snapshot.ps1 -Lot MAPDL1-E1 -Path <chemin>pour chacun des fichiers du § 1 ;- les fichiers neufs sont notés absents.
- Relever les MD5 (
Get-FileHash -Algorithm MD5) des fichiers modifiés, et des fichiers de ville de STM1 non commités. Ces derniers ne doivent pas changer :Source/LifePlay/LPCityWaterSubsystem.*,LPCityWaterMask.h,LPCityNamesSubsystem.*,LPCityHouses.h,LPCityLandmarks.h,LPAssetRegistryHelpers.*.
git status --shortsur les fichiers du § 1 : aucune modification en cours attendue, sinon arrêt et rapport.
1. Fichiers (et seulement ceux-là)
| Fichier | État | Contenu |
|---|---|---|
Plugins/ModdingExtra/Source/ModdingExtra/Public/ModdingExtraBPLibrary.h |
M | crochet du § 2.1 |
Plugins/ModdingExtra/Source/ModdingExtra/Private/ModdingExtraBPLibrary.cpp |
M | crochet du § 2.1 |
Source/LifePlay/LifePlay.Build.cs |
M | PrivateDependencyModuleNames : ajouter "ModdingExtra" et "Json", avec un commentaire « Lot MAPDL1 (SPEC-05) » |
Source/LifePlay/LPCityMapsSubsystem.h et .cpp |
A | § 2.2 à 2.5 |
Content/Data/LPCityMaps.json |
A | § 2.6 |
Config/DefaultGame.ini |
M | une ligne après la l. 74 (+DirectoriesToAlwaysStageAsNonUFS=(Path="Modules")) : +DirectoriesToAlwaysStageAsUFS=(Path="Data"), pour livrer le JSON dans le pak |
Tools/IndexCartes.ps1 |
A | § 2.7 |
Conventions :
- code dans le style des fichiers voisins (commentaires en français sans accents,
// Lot MAPDL1 (MAPDL1-SPEC-05) :) ; Tools\*.ps1en ASCII et LF ;- pas de
python -c, pas de heredoc ; - outil Edit pour modifier (jamais
sedni-replace).
2. Contenu
2.1 Crochet dans ModdingExtra (C2)
Dans ModdingExtraBPLibrary.h, hors de la classe, ajouter :
/** Lot MAPDL1 (MAPDL1-SPEC-05) : filtre facultatif de la liste rendue par GetAllFilesFromFolder, pose par le module du jeu
* (ULPCityMapsSubsystem). Arguments : dossier demande et extension tels que recus, liste a modifier. Sans filtre : inchange. */
using FModdingExtraFileListFilter = TFunction<void(const FString& /*RootFolder*/, const FString& /*Ext*/, TArray<FString>& /*Files*/)>;
MODDINGEXTRA_API void ModdingExtraSetFileListFilter(FModdingExtraFileListFilter Filter);
Dans le .cpp :
- une variable statique de fichier
FModdingExtraFileListFilter GLPFileListFilter;et la définition deModdingExtraSetFileListFilter; - dans
GetAllFilesFromFolder, garder une copie deExttel que reçu au début (la fonction le transforme en*.uasset) ; - juste avant
return true;(l. 224 actuelle) :if (GLPFileListFilter) { GLPFileListFilter(RootFolderFullPath, ExtRecu, Files); }.
Rien d'autre ne change. Le plugin ne dépend toujours pas du jeu.
2.2 ULPCityMapsSubsystem : index et états (C1)
UCLASS() class LIFEPLAY_API ULPCityMapsSubsystem : public UGameInstanceSubsystem
Index. Dans Initialize, lire le premier fichier présent parmi :
- (a)
FPaths::ProjectSavedDir()/LPCityMaps.json: surcharge locale, pour les essais (MAPDL1-ESSAI-FJF4) ; - (b)
FPaths::ProjectContentDir()/Data/LPCityMaps.json: copie livrée.
Lecture par FFileHelper::LoadFileToString puis FJsonSerializer.
- Champs (format 2, SPEC v3 § 1) :
base[],licences{},villes[]avecville,pack,version,jeu_min,jeu_max,zip,octets,sha256,urls[],page,licences[],source. - Journal :
[LPCity] CARTES index <chemin> : base <n>, villes <n>(catégorieLogLPCity, celle deLPAssetRegistryHelpers.cpp). - Index absent ou illisible : avertissement, et aucune ville téléchargeable. Les villes « base » prennent alors pour valeur par défaut
CentralLondonet00BathCC.
État d'une ville V, nom d'asset du jeu, calculé à la demande et mis en cache. Les packs sont montés au démarrage, et le cache de ResolveCityPath n'est jamais invalidé, ce qui est voulu :
InstalledsiVest dansbase, ou si, pour les deux chemins/Game/Heavy/StreetMap/V.Vet/Game/Heavy/StreetMap/Static/V.V,ULPAssetRegistryHelpers::ResolveCityPath(p) != p;- sinon
Downloadablesi une entréeville == V(casse ignorée) a au moins une URL, unsha256de 64 caractères hexadécimaux, etjeu_min <= version du jeu <= jeu_max. La version du jeu estProjectVersion(FLPModGuard::GetGameVersion()) ; comparaison par composantes séparées par des points, numérique quand les deux composantes sont des nombres, sinon textuelle ; - sinon
Unavailable.
API (UENUM(BlueprintType) ELPCityMapState { Installed, Downloadable, Unavailable }) :
GetCityState(const FString& Ville);GetDownloadBytes(Ville);GetDownloadUrls(Ville)(C++).
Une ligne de journal par ville au premier calcul : [LPCity] ETAT <V> : <etat>.
Pose du crochet dans Initialize : ModdingExtraSetFileListFilter(...) avec un TWeakObjectPtr sur le sous-système. Le retirer dans Deinitialize (filtre vide). Le filtre n'agit que si :
- le dossier, une fois normalisé (
\devient/, sans/au début ni à la fin), vautHeavy/StreetMap(casse ignorée) ; - et l'extension reçue est
uassetou.uasset.
Il retire alors de Files toutes les entrées dont le nom de fichier sans extension est une ville dont l'état n'est pas Installed. Les entrées des villes installées ne sont pas touchées : le comptage d'origine du Blueprint UI/City, qui exige 2 entrées pour « Installed », doit rester intact. Journal, une fois par appel : [LPCity] LISTE Heavy/StreetMap : <n> entrees, <m> retirees.
E0 a établi que GetAllFilesFromFolder est appelé par 6 Blueprints (GI, Room, Builder, CharGen, StatMenu, CityMenu), mais que seul CityMenu porte le littéral Heavy/StreetMap. Le filtre ne touche que ce dossier.
2.3 Menu des villes (C3)
Un ticker FTSTicker de 0 s, comme TickModManager, actif tant que le sous-système existe. À chaque passage :
- Trouver un
UScrollBoxnomméCityScrollBox, dont l'objet extérieur est de classeCityMenu_Cet qui est à l'écran (IsVisible()etGetCachedWidget().IsValid()). - Pour chaque enfant de classe
City_C, lire :- la variable
City(FStructProperty), et dans cette structure le champ dont le nom commence parStreetMapName(FNameProperty; les champs d'une structure Blueprint ont un suffixe). Le nom de ville est la partie après le dernier.du chemin, ou après le dernier/s'il n'y a pas de.; - les variables
InstalledText(UTextBlock) etCityButton(UButton).
- la variable
- Selon l'état :
Installed: ne rien toucher (texte et clic d'origine) ;Downloadable:InstalledText->SetText("Download (%d MB)"), arrondi au Mo supérieur ;SetColorAndOpacitybleu(0.2, 0.6, 1.0);- relais de clic (point 5) ;
Unavailable:InstalledText->SetText("Not available"), gris(0.5, 0.5, 0.5);CityButton->SetIsEnabled(false);- opacité de la ligne à 0,6.
- Réappliquer à chaque passage, car le Blueprint écrit
InstalledTextaprès unDelay 0.2(MAPDL1-L4-CART-01).
- Tri, une fois par instance de liste, et de nouveau si le nombre d'enfants change :
- tri stable en trois groupes :
Installed, puisDownloadable, puisUnavailable; l'ordre d'origine est gardé dans chaque groupe ; - retrait de tous les enfants, puis réinsertion dans le nouvel ordre ;
- relever le
Padding, l'alignement horizontal et l'alignement vertical de chaqueUScrollBoxSlotavant le retrait, et les remettre après. GI.Citiesn'est pas modifié.- Journal, une fois par instance :
[LPCity] MENU tri : <i> installees, <d> telechargeables, <u> indisponibles.
- tri stable en trois groupes :
- Relais de clic des lignes
Downloadable:- un petit
UCLASS() ULPCityRowClick : UObject(même fichier) avecFString Ville, unTWeakObjectPtrvers le sous-système etUFUNCTION() void OnClicked();. Lié parCityButton->OnClicked.AddUniqueDynamic; - le sous-système garde ces objets (
UPROPERTY() TArray<TObjectPtr<ULPCityRowClick>>) et les vide quand la liste change d'instance ; - dans cette fiche,
OnClickedouvreurls[0](oupagesi elle n'est pas vide) parFPlatformProcess::LaunchURL. C'est le recours (c), en attendant la fenêtre de C6 en E5. Journal :[LPCity] CLIC <V> : navigateur <url>.
- un petit
2.4 Bandeau des parties sauvegardées (C4)
Dans Initialize, s'abonner à ULPAssetRegistryHelpers::OnCityMapResolved() (LPAssetRegistryHelpers.h:19, deux paramètres : demandé, résolu). Si :
- le demandé est
/Game/Heavy/StreetMap/V.V(pasStatic/) ; - le résolu est égal au demandé (aucun pack) ;
- l'état de
Vn'est pasInstalled.
Alors afficher pendant 10 s, par GEngine->GameViewport->AddViewportWidgetContent (Slate, ordre Z élevé, en haut au centre), le texte :
Map not installed - download it from the city menusi l'état estDownloadable;Map not availablesinon.
Une seule fois par ville et par session. Journal : [LPCity] BANDEAU <V> : <texte>. Se désabonner dans Deinitialize.
2.5 Ce qu'il ne faut pas faire
- Ne pas modifier
ResolveCityPath,LPCityWaterSubsystem,LPCityNamesSubsystem, ni aucun fichier de STM1. - Ne pas toucher
GI.Cities, les sauvegardes,Content/Heavy. - Aucun texte de jeu en dur hors de ceux du § 2.3 et du § 2.4.
2.6 Content/Data/LPCityMaps.json livré
Format 2 :
"base": ["CentralLondon", "00BathCC"];"licences":osm:titre« Map data (c) OpenStreetMap contributors, ODbL 1.0 »,fichier« Licenses/OpenStreetMap_Geodata_License.txt » ;lifeplay_ancienne:titre= le texte validé (S5-5) deMAPDL1-SPEC-05-v2.md§ 4, mot pour mot,fichier« Licenses/Vinfamy_License.txt » ;
"villes": []: aucun hébergeur n'est choisi (H1, H2). Une liste d'essai se pose dansSaved/LPCityMaps.json.
UTF-8 sans BOM, LF.
2.7 Tools/IndexCartes.ps1 (C5)
Il écrit un LPCityMaps.json format 2. Paramètres :
-Villes A,Bou-Toutes: toutes les archiveslpm_city_*-*-for-LifePlay-<jeu>.zipde<Publication>\Mods, en prenant la plus haute version par pack ;-Hebergeur Forgejo|GitHub|Modele, avec :- Forgejo :
-ForgejoHote(défautforgejo.edujiro5972.fr),-Owner,-Repo,-Tag, d'oùhttps://<hote>/<owner>/<repo>/releases/download/<tag>/<zip>; - GitHub :
-Owner,-Repo,-Tag, d'oùhttps://github.com/<owner>/<repo>/releases/download/<tag>/<zip>; - Modele :
-Modele "https://…/{zip}";
- Forgejo :
-Miroir(facultatif) : un second modèle{zip}, ajouté en 2e URL ;-JeuMax(défaut2026.12.99) ;-Sortie(défaut<Racine>\Saved\LPCityMaps.json; écrireContent\Data\LPCityMaps.jsonexige-Livre) ;-ABlanc: affiche le JSON, n'écrit rien.
Pour chaque pack :
ville: le nom d'asset, tiré deModSources\<pack>\Content\StreetMap\<V>.uasset;version:VersionNamedu.upluginsource ;zip,octets,sha256calculés sur l'archive ;jeu_min: la version du jeu tirée du nom de l'archive ;licences:["osm","lifeplay_ancienne"];source: la ligne- file … SHA-256 …du CREDITS source.
Racines lues par Get-LPProjet et Get-LPRacine. Codes : 0 écrit ; 2 usage, archive ou source manquante. ASCII et LF ; en-tête .SYNOPSIS.
Essai à faire (sans réseau), avec des valeurs fictives : -Villes Manila -Hebergeur Forgejo -Owner exemple -Repo exemple -Tag cartes-test-1 -ABlanc. Recopier la sortie.
3. Contrôles hors moteur à faire
git diff --statdes fichiers M, et liste des fichiers A.- MD5 avant et après de chaque fichier du § 1, et MD5 des fichiers de STM1 inchangés.
- Fins de ligne : les fichiers
.cpp,.het.csgardent leur convention, vérifiée pargit ls-files --eolpour les fichiers suivis (LF attendu). - Analyse syntaxique PowerShell de
IndexCartes.ps1([System.Management.Automation.Language.Parser]::ParseFile) : 0 erreur ; essai à blanc du § 2.7. python -I -X utf8 -cest interdit ; pour valider le JSON, lancerTest-Jsonsous pwsh.
4. Livrable
Docs\Migration\etat\REL\MAPDL1\MAPDL1-E1-IMPL.md :
- en-tête sk-protocol, avec le modèle réellement utilisé ;
- fichiers, MD5 avant et après, diff résumé ;
- choix faits là où la fiche laisse une latitude ;
- points non sûrs, à vérifier à la compilation (E2) ;
- sorties des contrôles du § 3 ;
- compte rendu.
Budget : 60 tours. En cas de blocage (API introuvable, compilation impossible à anticiper), arrêt et rapport : on ne contourne pas.