LifePlay-Revival/Docs/Migration/etat/ST/STG/STG-SF4-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

13 KiB
Raw Blame History

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.txt l. 116-130 : Box (BoxComponent) parent=StaticMeshComponent0, BoxExtent = (400, 400, 64), AreaClass = NavArea_Obstacle, ObjectType=ECC_Vehicle ; racine StaticMeshComponent0 RelativeScale3D = (8, 8, 0.2), Mobility = Static. La Box n'imprime ni RelativeLocation ni RelativeScale3D ni Mobility (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.md l. 25 (ligne STG-M1a, correctif S-F4 proposé).
  • Aucune fiche IMPL, ni fichier STG-SF4-IMPL.md, ni fiche STG-SF4*.md dans le dossier STG (Glob STG-*) : seul le patch STG-SF4.patch tient 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 MD5 1340EE4F64FC10E84F829AEBCEE44161, .h 66F21A879542DA505C744AE7C424A762.

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) : .cpp dd8646f808aaab150e5ea1a330f870ea, .h ca18ac44c1e682490b689a81dfec0bd2 = 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

  1. Dessus inchangé — .cpp:124-125 : demi-hauteur E → T, Z relatif Z → Z + E − T. Dessus relatif avant Z + 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.
  2. Épaisseur cible — T = E × 0,2 / ScaleZ (l. 110) ; avec E = 64, ScaleZ = 0,01 : T = 1280 ; épaisseur monde 2 × 1280 × 0,01 = 25,6 cm = 2 × 64 × 0,2 (intérieur, M1-ANALYSE l. 29). Le journal (l. 127-128) affiche 2·T·ScaleZ = 25,6. Dessous descend de 2 × (1280 − 64) × 0,01 = 24,3 cm. CONFORME.
  3. 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, comparaison ThickenedFloor.Get() != Floor) ; (iii) Deinitialize (l. 39, après RemoveTicker). Ordre dans RestoreFloor : extent puis position puis mobilité ; Reset() toujours (l. 143). CONFORME. Limite : les enfants de la Box passés en Movable par SetMobility(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).
  4. Aucune action en intérieur — bOutdoor faux : UpdateFloor ne restaure que si ThickenedFloor == Floor, sinon return (l. 91-97) ; aucune écriture sur la Box. Et à l'échelle 0,2 la garde TargetZ <= Extent.Z (l. 111) retournerait de toute façon. CONFORME.
  5. WallT inchangé — original (git show HEAD, diff l. 35-45) : if (!Root || !Ceiling) return true; puis bOutdoor et 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.
  6. Pointeurs nuls — Room : IsValid(Room) avant Floor (l. 55) ; Floor non nul testé avant UpdateFloor (l. 65) ; Root testé (l. 60) avant GetRelativeScale3D ; ThickenedFloor.Get() testé dans RestoreFloor (l. 133) ; Floor-> dans UpdateFloor : appelant garantit non nul. GetObjectProperty tolère Container nul. 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ée UBoxComponent (.h l. 143) ; LifePlay.h pour LogLifePlay déjà présent. Aucun UE_VERSION_OLDER_THAN ajouté (pas besoin de garde de version).
  • Source/LifePlay/LifePlay.Build.cs:17 : PublicDependencyModuleNames … "Core", "CoreUObject", "Engine", … : Engine présent. Aucune modification de Build.cs nécessaire.
  • EOL : git ls-files --eol → i/lf w/lf pour les deux ; tr -cd '\r' < fichier | wc -c → CR=0 pour .cpp et .h (compte par tr, pas par grep -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 : SetMobility ré-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 documente Mobility « 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 + SetRelativeLocation changent 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 : Tick du ticker central (déjà le cas). Ajout : un FindPropertyByName pour Box par image (coût du même ordre que Room/WallT) ; UpdateFloor sort 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 modifie Box après le premier épaississement (autre SetBoxExtent), 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). Patch STG-SF4.patch = diff réel (diff vide entre les deux). Rien d'autre dans le diff que : includes, constantes FloorPropertyName / IndoorScaleZ, RestoreFloor dans Deinitialize, restructuration du retour anticipé de Tick, 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à de git status initial (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.Box dans le Blueprint (Static ou Movable) : le journal « Piece exterieure … plancher Box epaissi » ne le dit pas ; relever Mobility via LPDumpComponents ou trace en COMMUN-2 pour savoir si R1 est exercé.
  • COMMUN-2 : compilation LifePlayEditor (0 erreur) puis LPTestStringCompat (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 : ni Source/, ni Content/, ni Config/.

Tours : 9 / 30

Constats

  • Le piège d'écriture : redirection > "$S/…" refusée par le crochet pour cet agent ; contourné par substitution de processus diff <(git diff …) fichier (lecture seule).