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 : causemeshZ, 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) etSource\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 membreMesh(Character.h:487,inline … GetMesh() const { return Mesh; }).- Le CDO de
Person_C(Default__Person_C) est construit par le constructeur natif d'ACharacter:Meshpointe sur le sous-objetCharacterMesh0de 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 -90observé sur 1 424 + 318 + 55 relevés, DIAG § 1). GetDefaultObject<T>()(Class.h:4624,const, public) renvoie le CDO existant ;check(IsA)vrai pourPerson_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 ligneM-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) ;OutdoorScalerepart deZeroVectorà 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 deLastPositions(ou ont sauté de plus de 50 cm) et sontbJustPlacedau 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,bFastlu 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 appelleIgnoreOutdoorDecor). bJustPlaced(:388-390) : vrai si absente deLastPositions(première vue, aprèsReset) 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èdentbJustPlaceddans le flux (continueen:398) ;PlayerBusy(:410) reste avant toute pose du joueur ;SexOn(:350),OccupyingFntetUsedInScene(: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 donnebJustPlacedvrai au tick suivant, mais le testBottom >= FloorTop - SunkDepthfaitcontinue(: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, quelquesFindPropertyByName(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 :
- L'IMPL ne suit pas le gabarit IMPL de
lp-doc: section « Écarts à la SPEC » absente (aucune SPEC, il fallait écriresans objet : <motif>) et sections dans un autre ordre (instantané en 1, MD5 en 5, retour arrière en 6). Mineur. - Premier essai de
FileCheck.ps1avec 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. - 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 deetaucun point libre). - R3 (S-F5p et M-Z) :
bJustPlacedvaut 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 (LastPositionsn'est pas vidée surSexOn,: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 parunOccupyFnt. Estimé ; non vérifié. - R4 (M-Z) : si le Blueprint pose
OccupyingFntaprès lemeshZde 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 unmeshZdifférent (sansOccupyingFnt, horsSexOn) 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-Zdu journal COMMUN-10 doit affichergabarit Person_Cet-> -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 lemeshZdiffè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 (
meshZdu couple intact), assis (meshZde 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