10 KiB
Fiche STG-WALK-VAL2 — Niveau N1 — Modèle prévu lp-validator | utilisé claude-sonnet-5-5 — Agent lp-validator — Skills sk-protocol, sk-recount, debug-verification, lp-validate
STG-WALK-VAL2 : validation statique de la passe 2 de la marche animée (2026-10-13)
Copie D:\Game\LifePlay-master 5.8, branche ue5.8. Lecture seule, sans build, sans UE, aucune commande git qui écrit.
Verdict : PASS-STATIC
1. Fiches amont relues
Docs\Migration\etat\ST\STG\STG-WALK-IMPL.md(entier : § 2, § 2b, § 3 = P1 à P7).Docs\Migration\etat\ST\STG\STG-WALK-VAL.md(passe 1, FAIL sur P5/P2 :PlayAnimationne met pas à jourAnimationData.AnimToPlay).- Référence de départ :
D:\Game\LifePlay_Backup_5.5\STG-WALK2\(manifest.csv:Size 37275, MD55323C2B2027286098DC3C527FC1F39BD).
2. Points à confirmer de l'IMPL
| Id | Point | Résultat | Preuve |
|---|---|---|---|
| P1 | Diff limité aux gestes du § 2 et § 2b | PASS-STATIC | § 4 : 9 hunks, tous dans les gestes 1 à 6 et § 2b |
| P2 | API et includes | PASS-STATIC | § 5 : GetSingleNodeInstance() const et GetAnimationAsset() const publics, include valide ; plus aucune lecture de AnimToPlay dans ce fichier |
| P3 | Garde éditeur inchangée | PASS-STATIC | l. 1016 IsGameTarget() || RequiresCookedData() ; IsGameTarget non modifié (hunk absent) ; VAL1 P3 (RequiresCookedData() = !HAS_EDITOR_DATA) non remise en cause |
| P4 | Aucune boucle de chargement | PASS-STATIC | WalkClip l. 469-498 : cache TWeakObjectPtr, bMissing[Slot], un seul UE_LOG par sexe ; WalkAnim ne relance plus PlayAnimation une fois SingleNodeAnim(Mesh) == WalkCycle (§ 6) |
| P5 | RestoreAnim ne touche pas une animation posée par le jeu |
PASS-STATIC | § 6 (lecture par l'instance single-node, qui est bien mise à jour par PlayAnimation) |
| P6 | KO3b, C1-Walk, 3a inchangés | PASS-STATIC | § 4 : aucun hunk dans LeaveSeat, UpdateSeatEscape, CapsuleInside, FirstPersonView, OnSeat, ScenePlaying ; le seul hunk de Tick est RestoreAnim() (l. 734-735) |
| P7 | Compilation | reporté (BUILD de COMMUN-4) | non mesurable ici |
3. Critères rejoués (commandes et sorties brutes)
MD5 : md5sum Source/LifePlay/LPDirectControlSubsystem.cpp Source/LifePlay/LPDirectControlSubsystem.h :
8a680f80111d742a924ff655fdb21b61 *Source/LifePlay/LPDirectControlSubsystem.cpp
3cdb498591dff98dd53fcfd65d7322d0 *Source/LifePlay/LPDirectControlSubsystem.h
Attendus 8A680F80… et 3CDB4985… : confirmés.
Fins de ligne : tr -cd '\r' < fichier | wc -c et wc -l : .cpp CR 1263 / LF 1263 ; .h CR 79 / LF 79. Tools\FileCheck.ps1 (appelé un fichier à la fois, depuis PowerShell, répertoire du projet) : .cpp fichiers=1 CRLF=1 alertes=0 introuvables=0 ; .h fichiers=1 CRLF=1 alertes=0 introuvables=0. CRLF homogène. (Un appel avec deux fichiers en arguments positionnels est refusé par le script : Impossible de trouver un paramètre positionnel ; un appel -File depuis Bash échoue sur $PSScriptRoot vide. Aucun des deux n'est un résultat sur les fichiers.)
.h : git diff --stat -- Source/LifePlay/LPDirectControlSubsystem.h = 2 insertions(+) par rapport à HEAD (ajouts de C1-Walk antérieurs) ; MD5 identique à l'attendu et à l'avant de la passe 1 (IMPL § 1). Pas de copie du .h dans l'instantané : seul le MD5 le prouve.
4. Diff lu en entier
Commande : diff --strip-trailing-cr D:/Game/LifePlay_Backup_5.5/STG-WALK2/Source/LifePlay/LPDirectControlSubsystem.cpp Source/LifePlay/LPDirectControlSubsystem.cpp (code 1). Sortie : 9 hunks.
13a14:#include "Animation/AnimSingleNodeInstance.h"(geste § 2b).31a33:#include "HAL/PlatformProperties.h"(geste 1).463a466,507:WalkClip(bool)(l. 469) etSingleNodeAnim(const USkeletalMeshComponent*)(l. 502), dans l'espace anonyme (ouvert l. 47) (gestes 2 et § 2b).689a734,735: commentaire +RestoreAnim();dans la branche bloquée deTick(geste 5).969c1015,1016: commentaire + gardeWalk(geste 3).1050,1051c1097:WalkClip(bMale)remplaceLoadObject(ClipPath(...))(geste 4).1060c1106:SavedSingleAnim = SingleNodeAnim(Mesh);(§ 2b).1063c1109: test « déjà sur le cycle » viaSingleNodeAnim(Mesh) != WalkCycle(§ 2b).1081a1128,1134: contrôle « animation posée par le jeu » deRestoreAnim(geste 6), lecture parSingleNodeAnim. Aucun autre hunk. Le blocWalkClipest identique à celui relu en VAL1 (hunk 2 de la passe 1) : aucune modification de la passe 2 hors § 2b.
Noms : Grep "AnimToPlay|SingleNodeAnim|WalkClip" sur Source\ : SingleNodeAnim 4 occurrences d'appel + 1 définition (l. 502, 1106, 1109, 1131), toutes dans LPDirectControlSubsystem.cpp ; WalkClip l. 469 et 1097, seul fichier ; AnimToPlay dans ce fichier : l. 500 seulement (commentaire). Aucune collision en build unifié dans Source/LifePlay pour les deux noms.
5. Moteur 5.8 (D:\Game\Launcher\Engine\UE_5.8\Engine\Source\Runtime\Engine\)
Classes\Components\SkeletalMeshComponent.h:1539:ENGINE_API class UAnimSingleNodeInstance * GetSingleNodeInstance() const;. Sectionpublic:: le dernierpublic:avant la ligne est l. 1148, le suivantpublic:l. 1558, aucunprotected/privateentre les deux (Grep des étiquettes d'accès) : public.Classes\Animation\AnimSingleNodeInstance.h:78:ENGINE_API virtual UAnimationAsset* GetAnimationAsset() const;dans le blocpublic:(l. 47) ; classeUCLASS(... MinimalAPI), fonctionENGINE_API: liable depuis un module de jeu. IncludeAnimation/AnimSingleNodeInstance.h: chemin sousClasses\, racine publique du module Engine (dépendance existante) : valide.Private\Components\SkeletalMeshComponent.cpp:4278-4289:PlayAnimation=SetAnimationMode(AnimationSingleNode)+SetAnimation+Play.:4291-4309:SetAnimationappelleGetSingleNodeInstance()->SetAnimationAsset(NewAnimToPlay, false).Private\Animation\AnimSingleNodeInstance.cpp:26-31:SetAnimationAssetécritCurrentAsset = NewAsset; l. 99-102 :GetAnimationAsset() const { return CurrentAsset; }.PlayAnimationmet donc à jour ce que renvoieGetAnimationAsset. Réserve de fond : l. 47-60,CurrentAssetest remis à nul si le maillage n'a pas de squelette ou si le squelette de l'asset est nul (voir réserve R2).SkeletalMeshComponent.cpp:4451-4454:GetSingleNodeInstance() const { return Cast<UAnimSingleNodeInstance>(AnimScriptInstance); }: leCastrenvoie nul si l'instance est une instance d'Anim BP :SingleNodeAnimnulle en mode Anim BP (établi par lecture ; la classe de l'Anim BP n'est pas unUAnimSingleNodeInstance).
6. P5 et P2, rejeu des comportements (lecture)
Code actuel : WalkAnim l. 1097-1114 ; RestoreAnim l. 1117-1152 ; SingleNodeAnim l. 502-506 (Mesh ? Mesh->GetSingleNodeInstance() : nullptr, puis GetAnimationAsset(), const-correct).
- Anim BP en cours, marche qui démarre :
bAnimCapturedfaux → capture : mode,GetAnimClass(),SingleNodeAnim(Mesh)= nul (mode Anim BP). Test l. 1109 : mode ≠ SingleNode →PlayAnimation(WalkCycle, true)+ unUE_LOG. - Image suivante : mode = SingleNode,
SingleNodeAnim(Mesh) == WalkCycle(CurrentAssetposé parSetAnimationAsset) → pas dePlayAnimation, pas de journal ; seulSetPlayRateest rappelé. Les images suivantes sont donc sans relance (sauf R2). - Arrêt (vitesse < 20) ou branche bloquée de
Tick, le maillage joue*_Walk_Loop:RestoreAnim:Playing= le cycle, mode SingleNode, nom finissant par_Walk_Loop→ le test l. 1132 est faux, on passe à la restauration : Anim BP (SetAnimInstanceClass+SetAnimationMode(AnimationBlueprint)) si le mode capturé l'était et la classe non nulle ; sinonPlayAnimation(SavedSingleAnim)si capturée ; sinonSetAnimationMode(Mode); puisSetPlayRate(1.f). Conforme. - Une scène a posé sa propre animation : mode SingleNode avec un autre clip, ou mode Anim BP (
SingleNodeAnimnulle →!Playingvrai) → seule la vitesse est rendue à 1, retour sans écraser. Conforme. - Rien de capturé :
!bAnimCaptured→ retour immédiat (l. 1119-1122), aucun effet. Conforme.bAnimCaptured = falseest posé avant les gardes (la capture est abandonnée dans tous les cas, comme annoncé au geste 6). - Détail :
Playingestconst UAnimationAsset*;GetName()est const : valide.
KO3b, C1-Walk, 3a : voir P6 ci-dessus (aucun hunk dans leurs fonctions).
7. Verdict
PASS-STATIC. P1 à P6 : PASS-STATIC ; P7 : reporté (BUILD de COMMUN-4). Établi : MD5 des deux fichiers, CRLF homogène, diff entier (9 hunks), API et visibilité dans les sources 5.8, mise à jour de CurrentAsset par PlayAnimation, nullité en mode Anim BP, absence de lecture de AnimToPlay dans le fichier. Estimé : bon comportement en jeu (déduit de la lecture). Non mesuré : compilation, essai en jeu (§ 4 de l'IMPL), existence des clips cuits.
Réserves :
- R1 : ni compilation ni essai en jeu ; P7 et l'essai § 4 de l'IMPL restent à faire (COMMUN-4, après la duplication des clips).
- R2 (hors périmètre, faible) : si
SetAnimationAssetannuleCurrentAsset(squelette de l'asset nul ou maillage sans squelette,AnimSingleNodeInstance.cpp:47-60),SingleNodeAnim(Mesh) != WalkCycleresterait vrai etPlayAnimationserait relancé à chaque image. Situation d'asset invalide, non attendue ; à surveiller à l'essai (journal « Marche : animation » répété). - R3 (constat) :
Source/LifePlay/LPShowCoupleSubsystem.cpp:127lit encoreMesh->AnimationData.AnimToPlay(autre fonction, autre sous-système, hors fiche) ; même défaut possible si l'animation y est posée parPlayAnimation. Non évalué ici. - R4 :
git statusmontre d'autres fichiersSource/LifePlaymodifiés ou nouveaux (LPDebugSubsystem,LPOutdoorRoomSubsystem,LPCameraModeSubsystem) : autres lots, hors périmètre de cette VAL, non lus.
8. Points à confirmer par l'utilisateur
- BUILD de COMMUN-4 (P7) : compilation de
LPDirectControlSubsystem.cpp. - Après duplication des clips (fiche à part, UE-GO) : essai § 4 de l'IMPL (jambes qui marchent, pose de repos à l'arrêt, scène ouverte en marchant, changement de sexe).
- Décision sur R3 (
LPShowCoupleSubsystem.cpp:127) : hors lot, à l'orchestrateur.
Fichiers à commiter
Docs/Migration/etat/ST/STG/STG-WALK-VAL2.md (A). Aucun autre fichier écrit.
Tours : 10 / 25