LifePlay-Revival/Docs/Migration/etat/ST/STG/STG-MZ-VAL.md
edujiro5972 8084622450 LifePlay UE 5.8 : état de développement au 2026-10-19
Tickets : REP1-T4

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 22:57:42 +02:00

18 KiB

Fiche STG-MZ-VAL — Niveau N1 — Modèle prévu (agent lp-validator) | utilisé claude-sonnet-5-5 — Agent lp-validator — Skills sk-protocol, sk-recount, debug-verification, lp-validate

STG-MZ-VAL : validation statique de M-Z (hauteur du maillage au lever) et S-F5p (relevage dès la pose) (2026-10-14)

Verdict : PASS-STATIC (lecture seule ; ni UE, ni compilation, ni essai en jeu). Les écarts sont mineurs (§ 5) ; les risques sont en § 6.

1. Fiches amont relues

  • STG-MZ-IMPL.md (lu en entier, 93 lignes) ; STG-MZ.diff (lu en entier, 155 lignes) ; STG-COMMUN9-DIAG.md (§ 1-2 et § 4-6 : cause meshZ, cas d'essai) ; fiches\STG-COMMUN10-BUILD.md (existe ; cas 1 à 3 renvoyés par l'IMPL § 4).
  • VAL précédentes des mêmes fonctions citées par la fiche : STG-B2qb-VAL.md, STG-SF5m-VAL.md (existent dans le dossier ; leurs critères ne sont pas rejoués ici, seule la non-régression des gardes S-F5j/k/m/n est relue dans le code).
  • Instantané D:\Game\LifePlay_Backup_5.5\STG-MZ\ : manifest.csv (en-tête + 4 lignes) et Source\LifePlay\ relus.

2. Points à confirmer des IMPL amont

L'IMPL § 4 ne porte qu'un renvoi aux cas 1 à 3 de STG-COMMUN10-BUILD.md (essais en jeu) :

Point Statut
Cas 1 : flottement (chaise féminine, lever, pieds au sol, ligne M-Z : … -80.4 -> -90.0, PNJ) reporté (COMMUN-10, essai en jeu ; la valeur -90 du gabarit du CDO est estimée, § 3.3)
Cas 2 : rue (entrée depuis boutique et carte, relevage dans les 100 ms) reporté (COMMUN-10)
Cas 3 : non-régression (sexe, assis, KO3c, D6, C7-a) reporté (COMMUN-10) ; gardes lues dans le code : PASS-STATIC (§ 3.3, § 3.4)

3. Critères rejoués

3.1 MD5 (point 1) : PASS

Commande : md5sum sur les 4 fichiers actuels et sur l'instantané (Git Bash, depuis Source/LifePlay). Sortie brute :

LPDirectControlSubsystem.cpp act 5f9d7e00402688822687e7eb32979bd1 snap 4cf589b266ff61c8d61ae68b323fd381
LPDirectControlSubsystem.h   act 01d5ea3c82c2a547065c7bc391b9b430 snap a82ed5cffd97152b9237034bd7f49f4a
LPOutdoorRoomSubsystem.cpp   act dc68ed8af8a635e54aa003b84c565be9 snap 9dcf0a35a1418bcb52e1a6a5b7d0f58f
LPOutdoorRoomSubsystem.h     act 6a3edd7339dda483daef497372951188 snap 60fce1de305f4133738193d82cd05f05
  • Actuels = IMPL § 5 (5F9D7E00…, 01D5EA3C…, DC68ED8A…, 6A3EDD73…) : 4 sur 4.
  • Instantané = IMPL § 1 (préfixes 4CF589B2, A82ED5CF, 9DCF0A35, 60FCE1DE) et = manifest.csv (MD5 complets lus) : 4 sur 4.

3.2 Diff régénéré (point 2) : PASS

Commande : git diff --no-index --numstat <instantané>\<f> <f> par fichier. Sortie brute :

33	0	LPDirectControlSubsystem.cpp
2	0	LPDirectControlSubsystem.h
34	1	LPOutdoorRoomSubsystem.cpp
5	0	LPOutdoorRoomSubsystem.h

= numstat annoncé (33/0, 2/0, 34/1, 5/0). Empreinte des lignes ^[+-] (hors +++/---) du diff régénéré des 4 fichiers mis bout à bout : 5d42efa5a9856fdbd896909944a3bf32, identique à celle de STG-MZ.diff (grep -E '^[+-]' | grep -vE '^(\+\+\+|---)' | md5sum, même valeur). Diff lu en entier : 4 fichiers, uniquement les ajouts de l'IMPL § 2 (M-Z : MeshZScans, nettoyage, bSceneRunning, bloc de correction ; S-F5p : LastPositions, OutdoorScale, FastScanTime, FastScanSeconds, JumpDistance, fenêtre dans Tick, bJustPlaced). La seule ligne retirée est if (Scans < (bPlayer ? PlayerSunkScans : SunkScans)), remplacée par la version avec !bJustPlaced &&. Rien d'autre. git status --short Source : les 4 fichiers sont modifiés ; les autres changements de Source (LPDebugSubsystem, LifePlay.cpp, LPBonusReward*, LPCameraMode*, LPSaveRelaunch*) sont d'autres lots, hors de ce périmètre.

3.3 M-Z (point 3) : PASS-STATIC

Code : LPDirectControlSubsystem.cpp:1116-1124 (nettoyage, bSceneRunning), :1200-1223 (bloc M-Z).

Garde demandée Preuve Verdict
Jamais en animation de meuble !IsValid(Seat) (:1208), Seat = OccupyingFnt lu :1184-1185 PASS-STATIC
Jamais en scène de sexe bSceneRunning = ScenePlaying(GI) (SexOn, :466-470) ; capsule != NoCollision (les corps du sexe sont en NoCollision) PASS-STATIC
Jamais pendant une scène MenuWhy == TEXT("Scene_C") (:1124). MenuReason (:676-716) renvoie Scene_C seulement si la boîte a un contenu visible (ShowsContent) ; une boîte vide n'est pas comptée, comme voulu en C6-b. MenuWhy est rafraîchie toutes les 0,25 s (:866-872) avant FitPersonBounds (:875) PASS-STATIC
Debout depuis 1 s 2 balayages consécutifs (++Scans >= 2, :1212) ; balayage toutes les 0,5 s (BoundsDelay) PASS-STATIC
Gabarit relu par classe Person->GetClass()->GetDefaultObject<ACharacter>()->GetMesh()->GetRelativeLocation().Z (:1203-1206), aucune valeur codée en dur PASS-STATIC
Remise à zéro du compteur else { MeshZScans.Remove(Person); } (:1220-1223) dès qu'une condition manque, et après la correction (:1215) PASS-STATIC
X et Y conservés FVector(Relative.X, Relative.Y, TemplateZ) (:1214) PASS-STATIC
Effet sur la capsule nul : seul Body->SetRelativeLocation (le maillage) est écrit ; la capsule est lue (const UCapsuleComponent*) ; pas de balayage (bSweep à faux par défaut) PASS-STATIC

Le sous-objet du CDO porte-t-il la hauteur du Blueprint ? Estimé (raisonnement UE 5.8, non essayé) :

  • ACharacter::GetMesh() renvoie le membre Mesh (Character.h:487, inline … GetMesh() const { return Mesh; }).
  • Le CDO de Person_C (Default__Person_C) est construit par le constructeur natif d'ACharacter : Mesh pointe sur le sous-objet CharacterMesh0 de ce CDO. Les surcharges faites dans le Blueprint sur un composant natif hérité sont sérialisées dans ce sous-objet (c'est aussi l'archétype des instances, d'où meshZ -90 observé sur 1 424 + 318 + 55 relevés, DIAG § 1).
  • GetDefaultObject<T>() (Class.h:4624, const, public) renvoie le CDO existant ; check(IsA) vrai pour Person_C.
  • Donc la valeur lue est la hauteur relative surchargée par le Blueprint, à condition que cette surcharge soit bien dans le sous-objet (cas normal) et non dans un Construction Script ou un BeginPlay (alors le CDO garderait la valeur native, environ -88 pour le mannequin UE, et M-Z remettrait cette mauvaise valeur). Le cas d'essai 1 tranche : la ligne M-Z : … -> -90.0 (gabarit Person_C) doit afficher -90.0. Si elle affiche une autre valeur : arrêter M-Z.
  • Le plancher B2q-b1 existant ne lit pas le CDO ; aucune VAL antérieure ne couvre cette lecture.

Deux balayages : Scans est une référence FindOrAdd incrémentée sans insertion entre-temps. La correction a lieu au 2e balayage consécutif (1 s), une seule fois (compteur retiré), puis plus rien tant que l'écart ne revient pas.

Interaction avec B2q-a (bornes) : dans le même balayage, B2q-a calcule Pelvis/Center avant la correction (:1143-1182). Le décalage est d'environ 10 cm vers le bas (-80,4 vers -90) ; SetRelativeLocation met les bornes à jour, et le balayage suivant recalcule le facteur. Le test T-cull du même balayage (:1226) utilise le bassin d'avant : effet limité à un balayage, sans conséquence (journal d'alerte seulement). Estimé.

Interaction avec le sexe (-88, posé par le Blueprint) : pendant la scène, SexOn et NoCollision bloquent M-Z, donc la hauteur de placement n'est jamais touchée (cas 3 « sexe »). Une fois SexOn retombé et la collision rendue, un maillage resté à -88 est remis à -90 après 2 balayages, sauf si un meuble est encore occupé. Ce second cas est estimé (le Blueprint du sexe n'est pas dans le périmètre) ; voir R3.

Une Person s'assoit pendant la seconde d'attente : au balayage suivant OccupyingFnt est valide, IsValid(Seat) est vrai, on entre dans le else et le compteur est effacé ; rien n'est écrit, le meshZ de la place est gardé. Seul cas non couvert : OccupyingFnt posé après un balayage qui tombe pile entre la pose du maillage et celle de OccupyingFnt par le Blueprint (fenêtre inférieure à 0,5 s sur deux balayages consécutifs ; estimé improbable, voir R4).

3.4 S-F5p (point 4) : PASS-STATIC

Code : LPOutdoorRoomSubsystem.cpp:179-213 (fenêtre), :346-543 (LiftSunkPersons).

  • Détection de la nouvelle pièce : !Scale.Equals(OutdoorScale) (:182-188) ; OutdoorScale repart de ZeroVector à chaque retour en intérieur (:205), donc toute entrée en extérieur ouvre la fenêtre. Limite établie : deux rues d'échelles identiques à la suite, sans passage par l'intérieur, n'ouvrent pas la fenêtre (le Room est le même acteur, le critère ne regarde que l'échelle). Le critère ne suffit donc pas à lui seul ; cela dégrade seulement le délai, pas la sûreté : les personnes de la nouvelle rue sont absentes de LastPositions (ou ont sauté de plus de 50 cm) et sont bJustPlaced au balayage normal de 0,5 s. Sans fenêtre, l'enfoncement reste visible jusqu'à 0,5 s. Voir R1.
  • Fenêtre de 3 s : FastScanTime = 3.f à l'ouverture, bFast lu avant la décrémentation, FMath::Max(0.f, FastScanTime - DeltaTime) (:189-190) ; en fenêtre, appel à chaque tick (else if (bFast), :198), en plus du balayage de 0,5 s (qui seul appelle IgnoreOutdoorDecor).
  • bJustPlaced (:388-390) : vrai si absente de LastPositions (première vue, après Reset) ou saut de plus de 50 cm (JumpDistance) ; LastPositions.Add à chaque examen, après les filtres (cachée, sans collision, meuble, scène).
  • Gardes avant toute action : la garde de vitesse (Size2D() > 1.0, :391) et le seuil de 15 cm (SunkDepth) précèdent bJustPlaced dans le flux (continue en :398) ; PlayerBusy (:410) reste avant toute pose du joueur ; SexOn (:350), OccupyingFnt et UsedInScene (:378-381) inchangés. Le joueur sous un menu ou en marche n'est donc pas relevé.
  • Pas de boucle : après le relevage (SetActorLocation, :527), le bas de capsule est au-dessus du seuil (cible = sol + demi-hauteur + 1 ou 2 cm) ; le saut de ~80 cm donne bJustPlaced vrai au tick suivant, mais le test Bottom >= FloorTop - SunkDepth fait continue (:391-399) avant toute action. Aucune répétition.
  • Coût de la fenêtre rapide : par tick, un TActorIterator<ACharacter> et, par personne retenue, quelques FindPropertyByName (GetObjectProperty, UsedInScene) ; la boucle interne (voisins) et les balayages ne s'exécutent que pour une personne enfoncée, immobile et retenue. PlayerBusy (itération des widgets, :71) n'est appelée que pour un joueur enfoncé, immobile et ayant franchi le seuil. Pendant 3 s, aucune charge notable pour une scène normale (estimé). Voir R2 pour la personne introuvable (aucun point libre).
  • Compteur d'immobilité (Scans) : en fenêtre il est incrémenté à chaque tick, donc le seuil de 3 (PNJ) ou 4 (joueur) examens est atteint en 3 à 4 images au lieu de 1,5 à 2 s. Établi par lecture (:402-404). Effet voulu (relevage rapide) mais la garde d'immobilité temporelle de S-F5j/k devient très courte pendant ces 3 s ; la garde de vitesse reste la seule protection. Voir R2.

4. Compilabilité et contrôles de forme (points 5 et 6)

Commandes : lecture de Class.h, SceneComponent.h, Character.h, Vector.h, Map.h de D:\Game\Launcher\Engine\UE_5.8\Engine\Source\Runtime ; Grep des noms dans Source.

Point Preuve Verdict
UClass::GetDefaultObject<T>() Class.h:4623-4628 : template<class T> T* GetDefaultObject() const PASS-STATIC
GetMesh() sur const ACharacter* Character.h:487 : GetMesh() const ; sur Template (const) et TemplateBody const PASS-STATIC
GetRelativeLocation / SetRelativeLocation SceneComponent.h:1435 (const), :434 (FVector, bSweep=false, …) ; GetRelativeLocation().Z est un double PASS-STATIC
FString == TCHAR* (MenuWhy == TEXT("Scene_C")) même forme que ClassName == Menu déjà compilée (:705, :708) PASS-STATIC
TMap::FindOrAdd (référence) puis Remove int32& Scans n'est plus lue après MeshZScans.Remove(Person) ; le UE_LOG suivant n'utilise pas Scans ; conversion ACharacter* vers TWeakObjectPtr<AActor> comme MeasuredSeats.Add(Person, Seat) et SunkPersons.Find(Person) existants PASS-STATIC
FVector::Equals Vector.h:371 : Equals(const TVector<T>&, T Tolerance=UE_KINDA_SMALL_NUMBER) const ; Scale est un FVector PASS-STATIC
Nouveaux constexpr (FastScanSeconds, JumpDistance) Grep -w sur Source hors des 4 fichiers : 0 occurrence ; absents de l'instantané ; pas de collision en unity PASS-STATIC
Ombres C4458 : Scans, Capsule, Template, Relative, Scale, Previous, Known membres de LPDirectControlSubsystem.h / LPOutdoorRoomSubsystem.h : seuls MeshZScans, LastPositions, OutdoorScale, FastScanTime sont ajoutés, aucun n'a un de ces noms ; Capsule en :1006 est dans une autre fonction ; Known en :480 est dans un lambda d'une autre fonction, :1160 est dans la même boucle mais avant, et Known (:1160) est un const float* déclaré dans le corps de la boucle, tandis que M-Z n'en réutilise pas ; dans LiftSunkPersons, Scale (:432, :492) est déclaré dans des blocs sans Scale englobant ; dans Tick, Scale (:182) est unique PASS-STATIC
Includes Components/CapsuleComponent.h et Components/SkeletalMeshComponent.h présents (:21, :23), GameFramework/Character.h (:33) ; côté OutdoorRoom CapsuleComponent.h, Character.h présents (:7, :15) PASS-STATIC
Fins de ligne FileCheck.ps1 -Lot STG-MZ -OnlyChanged : brut ci-dessous PASS
Non-ASCII ajouté grep -P '^\+.*[^\x00-\x7F]' sur STG-MZ.diff : 0 ligne ; LPDirectControlSubsystem.cpp : 2 lignes non ASCII, 2 dans l'instantané (inchangé, :455) ; LPOutdoorRoomSubsystem.cpp : 0 / 0 PASS
IMPL LF (tr -cd '\r' : 0 CR), STG-MZ.diff LF (0 CR) ; en-tête complet (Fiche, Niveau, Modèle prévu et utilisé, Agent, Skills) ; grep -c 'C:.Users' : 0 PASS

Sortie brute FileCheck.ps1 -Lot STG-MZ -OnlyChanged :

Fins CRLF  LF CR BOM MD5                              Sauv   Contenu Alerte Fichier
CRLF 1771   0  0 -   5F9D7E00402688822687E7EB32979BD1 CRLF - modifie        Source\LifePlay\LPDirectControlSubsystem.cpp
CRLF  105   0  0 -   01D5EA3C82C2A547065C7BC391B9B430 CRLF - modifie        Source\LifePlay\LPDirectControlSubsystem.h
LF      0 543  0 -   DC68ED8AF8A635E54AA003B84C565BE9 LF -   modifie        Source\LifePlay\LPOutdoorRoomSubsystem.cpp
LF      0  87  0 -   6A3EDD7339DDA483DAEF497372951188 LF -   modifie        Source\LifePlay\LPOutdoorRoomSubsystem.h
fichiers=4 CRLF=2 LF=2 alertes=0 introuvables=0
exit 0

DirectControl en CRLF (LF seul = 0) et OutdoorRoom en LF (CRLF = 0), conformes à l'instantané.

5. Verdict

PASS-STATIC. Lu et recompté : MD5, numstat, empreinte du diff, gardes, compilabilité, fins de ligne. Non rejoué : compilation (au build COMMUN-10), LPTestStringCompat, tout essai en jeu.

Écarts à la fiche et à l'IMPL :

  1. L'IMPL ne suit pas le gabarit IMPL de lp-doc : section « Écarts à la SPEC » absente (aucune SPEC, il fallait écrire sans objet : <motif>) et sections dans un autre ordre (instantané en 1, MD5 en 5, retour arrière en 6). Mineur.
  2. Premier essai de FileCheck.ps1 avec des chemins en positionnel : échec de ma part (paramètre inconnu, code vide) ; rejoué avec -Lot STG-MZ -OnlyChanged, sortie ci-dessus. Aucun effet sur le verdict.
  3. Aucun fichier modifié par script ; aucun ajout hors périmètre dans les 4 fichiers.

6. Risques à signaler (aucun ne change le verdict)

  • R1 (S-F5p) : le critère « échelle différente » rate deux rues d'échelles identiques à la suite (pas de fenêtre rapide, relevage au balayage normal de 0,5 s). Option : compter aussi le changement d'acteur ou de position du Room. À décider par l'orchestrateur.
  • R2 (S-F5p) : pendant la fenêtre, le compteur d'immobilité est atteint en 3 à 4 images, et une personne sans point libre (S-F5m) relance ses essais de balayage à chaque tick pendant 3 s au plus. Coût et comportement estimés acceptables ; à surveiller au journal (nombre de lignes releve de et aucun point libre).
  • R3 (S-F5p et M-Z) : bJustPlaced vaut vrai pour une personne qui reprend l'examen après avoir été filtrée (meuble quitté, scène terminée, cachée puis visible) ou dont la position mémorisée date d'avant une scène de sexe (LastPositions n'est pas vidée sur SexOn, :350-353). Une personne encore basse à ce moment-là est relevée sans attendre les 3 examens, ce qui peut précéder une repose par unOccupyFnt. Estimé ; non vérifié.
  • R4 (M-Z) : si le Blueprint pose OccupyingFnt après le meshZ de la place, un balayage mal placé pourrait compter une fois ; il en faut deux de suite, donc très improbable. Une animation hors meuble qui règle volontairement un meshZ différent (sans OccupyingFnt, hors SexOn) serait aussi remise à -90.
  • R5 (M-Z) : la valeur du gabarit lue sur le CDO est supposée -90 (estimé). Contrôle : la première ligne M-Z du journal COMMUN-10 doit afficher gabarit Person_C et -> -90.0. Si la hauteur est réglée dans le graphe de construction et non dans le composant hérité, M-Z imposerait la mauvaise hauteur à toute personne dont le meshZ diffère.
  • R6 (M-Z) : les compteurs ne sont pas remis à zéro pour une Person qui sort des filtres de tête de boucle (cachée, bornes pas calculées, :1129-1151) ; un compteur à 1 peut rester en attente et la correction partir au premier balayage suivant (0,5 s au lieu de 1 s). Sans conséquence visible.
  • Non essayé : toute la partie dynamique (compilation COMMUN-10, rendu des pieds, journaux).

7. Points à confirmer par l'utilisateur

  • Cas 1 de COMMUN-10 : ligne M-Z … -80.4 -> -90.0 (gabarit Person_C) et pieds au sol après le lever (joueur et PNJ).
  • Cas 2 de COMMUN-10 : rue depuis boutique et depuis carte (OpenSpace), relevage dans la fenêtre rapide.
  • Cas 3 de COMMUN-10 : sexe (meshZ du couple intact), assis (meshZ de la place gardé), KO3c, D6, C7-a.
  • Décision sur R1 (critère de nouvelle pièce plus fin) avant ou après l'alpha.

Tours : 13 / 30