13 KiB
Fiche STG-SF4v — Niveau N1 — Modèle prévu lp-validator | utilisé Sonnet 5.5 (claude-sonnet-5-5) — Agent lp-validator — Skills lp-validate, sk-protocol, sk-recount, ue-cpp-build
STG-SF4v-VAL : validation statique du correctif S-F4 (plancher Room.Box en extérieur) (2026-10-13)
Verdict global : PASS-STATIC (lecture seule, aucune compilation, aucun lancement ; le build reste à faire dans COMMUN-2).
1. Fiches amont relues
Docs/Migration/etat/ST/STG/STG-M1-ANALYSE.md§ 2 et § 4 (lignes 13-14, 27-34, 53-54) : motif et attendu.Docs/Migration/etat/post-v1/PawnDyn/PawnDyn_LPDumpComponents_20261004-223842.txtl. 116-130 :Box(BoxComponent)parent=StaticMeshComponent0,BoxExtent = (400, 400, 64),AreaClass = NavArea_Obstacle,ObjectType=ECC_Vehicle; racineStaticMeshComponent0RelativeScale3D = (8, 8, 0.2),Mobility = Static. LaBoxn'imprime niRelativeLocationniRelativeScale3DniMobility(valeurs par défaut du dump : estimé 0 / 1 / non Static ; la mobilité réelle n'est pas établie, d'où le traitement du cas Static par le code).Docs/Migration/etat/ST/STG/STG-TACHES.mdl. 25 (ligne STG-M1a, correctif S-F4 proposé).- Aucune fiche IMPL, ni fichier
STG-SF4-IMPL.md, ni ficheSTG-SF4*.mddans le dossier STG (GlobSTG-*) : seul le patchSTG-SF4.patchtient lieu de livraison amont. Aucun « point à confirmer » d'IMPL à reprendre (voir § 2). - Instantané d'origine
D:\Game\LifePlay_Backup_5.5\STG\manifest.csv: .cpp MD51340EE4F64FC10E84F829AEBCEE44161, .h66F21A879542DA505C744AE7C424A762.
2. Points à confirmer des IMPL
sans objet : aucune IMPL amont pour S-F4 (Glob STG-* du dossier STG : pas de livrable IMPL pour SF4). Les points propres à cette VAL sont aux § 3 et § 6.
3. Critères rejoués (commande → résultat)
a. Diff, périmètre
git status --short -- Source→ 4 fichiers modifiés :LPDebugSubsystem.cpp,LPDebugSubsystem.h,LPOutdoorRoomSubsystem.cpp,LPOutdoorRoomSubsystem.h.LPDebugSubsystem.*ne relève pas de S-F4 : ils sont déjà dans le manifeste d'instantané STG (date 13:41:41, avant S-F4 à 17:11) ; leur diff est hors périmètre de cette fiche et non relu ligne à ligne (git diff --stat: cpp +249, h 2+/1-). Verdict a : CONFORME pour S-F4 (les deux fichiers attendus portent le correctif ; deux fichiers voisins modifiés relèvent d'un autre travail du lot STG, à rattacher à son ticket par l'orchestrateur).diff <(git diff -- LPOutdoorRoomSubsystem.cpp LPOutdoorRoomSubsystem.h) STG-SF4.patch→PATCH_IDENTIQUE: le patch livré est exactement le diff de l'arbre de travail.git diff --numstat→.cpp 77 ajouts / 2 suppressions,.h 15 / 0.- MD5 (
md5sum) : .cppdd8646f808aaab150e5ea1a330f870ea, .hca18ac44c1e682490b689a81dfec0bd2= valeurs de la fiche.
b. API UE 5.8 (racine D:\Game\Launcher\Engine\UE_5.8\Engine\Source\Runtime)
| API | Source | Verdict |
|---|---|---|
UBoxComponent::SetBoxExtent(FVector, bool=true) |
Engine/Classes/Components/BoxComponent.h:39 ; corps Engine/Private/Components/BoxComponent.cpp:28-40 (met à jour bornes, rendu, corps, forme physique) |
OK |
GetUnscaledBoxExtent() const → FVector |
BoxComponent.h:47, inline l. 80-83 (renvoie BoxExtent) |
OK |
GetComponentScale() (monde) |
Engine/Classes/Components/SceneComponent.h:1084-1087 |
OK |
GetRelativeScale3D(), GetRelativeLocation() |
SceneComponent.h:1521, :1435 (const, par valeur) |
OK |
SetRelativeLocation(FVector, bool bSweep=false, …) |
SceneComponent.h:434 |
OK |
SetMobility(EComponentMobility::Type) |
SceneComponent.h:1296 (ENGINE_API virtual, publique) ; corps Private/Components/SceneComponent.cpp:3098-3116 (ré-enregistre le composant ; si Movable, passe les enfants en Movable) |
OK |
Membre Mobility public |
SceneComponent.h:303, déclaré après public: l. 291 ; UPROPERTY(... Replicated) TEnumAsByte<EComponentMobility::Type> ; commentaire l. 302 « Only safe to set in constructor » |
OK (lecture publique) ; voir risque R1 |
EComponentMobility (enum Type : int) |
Engine/Classes/Engine/EngineTypes.h:4028-4030 ; le .h inclut Engine/EngineTypes.h (diff l. 139) |
OK |
UE_KINDA_SMALL_NUMBER |
Core/Public/Math/UnrealMathUtility.h:131 (1.e-4f) ; comparé à un double : promotion sans perte gênante |
OK |
FMath::IsNearlyEqual(double, double, double) |
UnrealMathUtility.h:393 ; appel IsNearlyEqual(Floor->GetRelativeScale3D().Z, 1.0) : double/double, pas d'ambiguïté (LWC) |
OK |
TEnumAsByte<EComponentMobility::Type> en membre d'UCLASS sans UPROPERTY |
même type que le membre moteur l. 303 ; membre brut dans une classe UObject (comme FVector FloorExtent et FTSTicker::FDelegateHandle déjà présent) : légal, ni GC ni sérialisation concernés. Initialiseur = EComponentMobility::Movable : conversion implicite enum → TEnumAsByte valide |
OK |
TWeakObjectPtr<UBoxComponent> : IsValid(), Get(), Reset(), affectation depuis UBoxComponent* |
usage identique à HiddenCeiling existant ; class UBoxComponent; déclarée (.h) et Components/BoxComponent.h inclus (.cpp l. 5) |
OK |
| Verdict b : CONFORME (compilation non faite : établi par lecture des en-têtes, pas par UBT). |
c. Logique
- Dessus inchangé —
.cpp:124-125: demi-hauteurE→T, Z relatifZ→Z + E − T. Dessus relatif avantZ + E, après(Z + E − T) + T = Z + E. Valable car l'échelle relative Z de la Box est 1 (garde l. 105) : l'unité de la position relative et de l'extent est alors la même (échelle du parent). Hypothèse : pas de rotation relative de la Box (non gardée ; dump : aucune rotation affichée). Cohérent avec M1-ANALYSE l. 53-54. CONFORME. - Épaisseur cible —
T = E × 0,2 / ScaleZ(l. 110) ; avecE = 64,ScaleZ = 0,01:T = 1280; épaisseur monde2 × 1280 × 0,01 = 25,6 cm=2 × 64 × 0,2(intérieur, M1-ANALYSE l. 29). Le journal (l. 127-128) affiche2·T·ScaleZ= 25,6. Dessous descend de2 × (1280 − 64) × 0,01 = 24,3 cm. CONFORME. - Restauration exacte —
RestoreFloor(l. 131-144) :SetBoxExtent(FloorExtent),SetRelativeLocation(FloorLocation)(valeurs copiées avant modification, l. 115-117), mobilité remise si différente. Appelée : (i) retour en intérieur (UpdateFloor, l. 91-97) ; (ii) changement de Room ou de composant (Tick, l. 56-59, comparaisonThickenedFloor.Get() != Floor) ; (iii)Deinitialize(l. 39, aprèsRemoveTicker). Ordre dansRestoreFloor: extent puis position puis mobilité ;Reset()toujours (l. 143). CONFORME. Limite : les enfants de la Box passés en Movable parSetMobility(Movable)ne sont pas remis en Static (dump : la Box n'a pas d'enfant listé) ; non restauré aussi si le composant est détruit avant (weak → rien à faire, correct). - Aucune action en intérieur —
bOutdoorfaux :UpdateFloorne restaure que siThickenedFloor == Floor, sinonreturn(l. 91-97) ; aucune écriture sur la Box. Et à l'échelle 0,2 la gardeTargetZ <= Extent.Z(l. 111) retournerait de toute façon. CONFORME. - WallT inchangé — original (
git show HEAD, diff l. 35-45) :if (!Root || !Ceiling) return true;puisbOutdooret le bloc plafond. Après :if (!Root) return true;;bOutdoor; plancher traité ;if (!Ceiling) return true;; bloc plafond identique (l. 74-85, ni ligne ni condition modifiée dans le diff). Cas : Root nul → retour comme avant ; Root non nul et Ceiling nul → retour comme avant (après traitement du plancher) ; les deux non nuls → même suite. Le rendu du plafond précédemment masqué (l. 49-54) est antérieur et inchangé. CONFORME. - Pointeurs nuls —
Room:IsValid(Room)avantFloor(l. 55) ;Floornon nul testé avantUpdateFloor(l. 65) ;Roottesté (l. 60) avantGetRelativeScale3D;ThickenedFloor.Get()testé dansRestoreFloor(l. 133) ;Floor->dansUpdateFloor: appelant garantit non nul.GetObjectPropertytolèreContainernul. Cast :Cast<UBoxComponent>sur la valeur de la propriétéBox(nul si autre type). Aucune lecture nulle trouvée. CONFORME.
d. Includes, module, EOL, chemins
- Includes :
Components/BoxComponent.h(.cpp l. 5),Engine/EngineTypes.h(.h l. 139), déclaration avancéeUBoxComponent(.h l. 143) ;LifePlay.hpourLogLifePlaydéjà présent. AucunUE_VERSION_OLDER_THANajouté (pas besoin de garde de version). Source/LifePlay/LifePlay.Build.cs:17:PublicDependencyModuleNames … "Core", "CoreUObject", "Engine", …:Engineprésent. Aucune modification de Build.cs nécessaire.- EOL :
git ls-files --eol→i/lf w/lfpour les deux ;tr -cd '\r' < fichier | wc -c→CR=0pour .cpp et .h (compte partr, pas pargrep -c $'\r'). - Chemins : Grep
C:\\Users|<nom du compte>sur les deux fichiers → 0 occurrence. Verdict d : CONFORME.
e. Risques nommés (non corrigés, pas de changement de verdict)
- R1 Mobilité à l'exécution :
SetMobilityré-enregistre le composant (FComponentReregisterContext,SceneComponent.cpp:3102) pendant le jeu, détruit/recrée l'état physique du plancher (un instant sans plancher), et le moteur documenteMobility« seulement sûr en constructeur » (SceneComponent.h:302). Le chemin n'est emprunté que si la Box n'est pas déjà Movable (mobilité réelle de la Box du Blueprint non établie par le dump).SetMobility(Movable)passe aussi les enfants en Movable, sans retour. Deuxième ré-enregistrement à la restauration. - R2 Navmesh : la Box porte
NavArea_Obstacle(dump l. 118-120).SetBoxExtent+SetRelativeLocationchangent ses bornes et marquent le navmesh sale à chaque épaississement et à chaque restauration (rebuild local de tuiles si navigation dynamique) ; en extérieur la Box passe de 1,28 cm à 25,6 cm d'épaisseur, 24 cm plus bas, ce qui peut aussi toucher le décor placé sous la pièce (non vérifié). - R3 Appel à chaque image :
Tickdu ticker central (déjà le cas). Ajout : unFindPropertyByNamepourBoxpar image (coût du même ordre queRoom/WallT) ;UpdateFloorsort tôt si le plancher est déjà épaissi ; si la garde d'échelle relative échoue (≠ 1), l'appel recalcule et retourne à chaque image, sans journal (pas de répétition de log). Le journal n'est écrit qu'aux deux transitions. - R4 Rotation relative de la Box non gardée (hypothèse du calcul « dessus inchangé ») ; sans effet tant que le Blueprint ne tourne pas la Box.
- R5 Valeurs non lues à l'exécution :
ScaleZ= échelle monde Z de la Box ; si un Blueprint modifieBoxaprès le premier épaississement (autreSetBoxExtent), la restauration écrase cette valeur par l'extent d'origine.
4. Diff lu en entier
- Fichiers : 2 (
Source/LifePlay/LPOutdoorRoomSubsystem.cpp,.h) ; compte : cpp +77/−2, h +15/−0 (git diff --numstat). PatchSTG-SF4.patch= diff réel (diff vide entre les deux). Rien d'autre dans le diff que : includes, constantesFloorPropertyName/IndoorScaleZ,RestoreFloordansDeinitialize, restructuration du retour anticipé deTick,UpdateFloor,RestoreFloor, commentaire d'en-tête .h, trois membres (ThickenedFloor,FloorExtent,FloorLocation,FloorMobility: quatre membres) et deux méthodes privées. Aucun ajout non annoncé. Content/,Config/: non examinés au-delà degit statusinitial (Person.uasset, Room.uasset modifiés dans l'arbre, hors périmètre S-F4 ; le diff S-F4 n'y touche pas).
5. Verdict
PASS-STATIC. Contrôles a, b, c (1 à 6), d conformes. Risques R1 à R5 listés, aucun n'est une erreur certaine. Rien n'a été compilé ni lancé : la compilation (C2xxx éventuels), le comportement en jeu (plancher retrouvé en street, floorHit > 0, navmesh, absence d'effet en intérieur) restent à prouver dans COMMUN-2.
6. Points à confirmer par l'utilisateur
- Mobilité réelle de
Room.Boxdans le Blueprint (Static ou Movable) : le journal « Piece exterieure … plancher Box epaissi » ne le dit pas ; releverMobilityviaLPDumpComponentsou trace en COMMUN-2 pour savoir si R1 est exercé. - COMMUN-2 : compilation
LifePlayEditor(0 erreur) puisLPTestStringCompat(3120 cas,compat != herite(UE4) : 0), puis session street : lignes de journal « plancher Box epaissi a 25.6 cm (demi-hauteur 64.0 -> 1280.0) » et « Plancher Box rendu … 64.0 » au retour en intérieur. - Rattacher les modifications de
LPDebugSubsystem.cpp/.h(hors S-F4) à leur ticket ; elles n'ont pas été validées ici. - Vérifier à l'œil que le dessous de la Box (24 cm plus bas) ne traverse pas le décor ou le sol visible en street (R2).
Fichiers à commiter
- A
Docs/Migration/etat/ST/STG/STG-SF4-VAL.md(dépôt du jeu, copie 5.8, branche ue5.8). Aucune autre écriture : niSource/, niContent/, niConfig/.
Tours : 9 / 30
Constats
- Le piège d'écriture : redirection
> "$S/…"refusée par le crochet pour cet agent ; contourné par substitution de processusdiff <(git diff …) fichier(lecture seule).