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

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 : PlayAnimation ne met pas à jour AnimationData.AnimToPlay).
  • Référence de départ : D:\Game\LifePlay_Backup_5.5\STG-WALK2\ (manifest.csv : Size 37275, MD5 5323C2B2027286098DC3C527FC1F39BD).

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.

  1. 13a14 : #include "Animation/AnimSingleNodeInstance.h" (geste § 2b).
  2. 31a33 : #include "HAL/PlatformProperties.h" (geste 1).
  3. 463a466,507 : WalkClip(bool) (l. 469) et SingleNodeAnim(const USkeletalMeshComponent*) (l. 502), dans l'espace anonyme (ouvert l. 47) (gestes 2 et § 2b).
  4. 689a734,735 : commentaire + RestoreAnim(); dans la branche bloquée de Tick (geste 5).
  5. 969c1015,1016 : commentaire + garde Walk (geste 3).
  6. 1050,1051c1097 : WalkClip(bMale) remplace LoadObject(ClipPath(...)) (geste 4).
  7. 1060c1106 : SavedSingleAnim = SingleNodeAnim(Mesh); (§ 2b).
  8. 1063c1109 : test « déjà sur le cycle » via SingleNodeAnim(Mesh) != WalkCycle (§ 2b).
  9. 1081a1128,1134 : contrôle « animation posée par le jeu » de RestoreAnim (geste 6), lecture par SingleNodeAnim. Aucun autre hunk. Le bloc WalkClip est 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;. Section public: : le dernier public: avant la ligne est l. 1148, le suivant public: l. 1558, aucun protected/private entre les deux (Grep des étiquettes d'accès) : public.
  • Classes\Animation\AnimSingleNodeInstance.h:78 : ENGINE_API virtual UAnimationAsset* GetAnimationAsset() const; dans le bloc public: (l. 47) ; classe UCLASS(... MinimalAPI), fonction ENGINE_API : liable depuis un module de jeu. Include Animation/AnimSingleNodeInstance.h : chemin sous Classes\, racine publique du module Engine (dépendance existante) : valide.
  • Private\Components\SkeletalMeshComponent.cpp:4278-4289 : PlayAnimation = SetAnimationMode(AnimationSingleNode) + SetAnimation + Play.
  • :4291-4309 : SetAnimation appelle GetSingleNodeInstance()->SetAnimationAsset(NewAnimToPlay, false).
  • Private\Animation\AnimSingleNodeInstance.cpp:26-31 : SetAnimationAsset écrit CurrentAsset = NewAsset ; l. 99-102 : GetAnimationAsset() const { return CurrentAsset; }. PlayAnimation met donc à jour ce que renvoie GetAnimationAsset. Réserve de fond : l. 47-60, CurrentAsset est 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); } : le Cast renvoie nul si l'instance est une instance d'Anim BP : SingleNodeAnim nulle en mode Anim BP (établi par lecture ; la classe de l'Anim BP n'est pas un UAnimSingleNodeInstance).

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 : bAnimCaptured faux → capture : mode, GetAnimClass(), SingleNodeAnim(Mesh) = nul (mode Anim BP). Test l. 1109 : mode ≠ SingleNode → PlayAnimation(WalkCycle, true) + un UE_LOG.
  • Image suivante : mode = SingleNode, SingleNodeAnim(Mesh) == WalkCycle (CurrentAsset posé par SetAnimationAsset) → pas de PlayAnimation, pas de journal ; seul SetPlayRate est 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 ; sinon PlayAnimation(SavedSingleAnim) si capturée ; sinon SetAnimationMode(Mode) ; puis SetPlayRate(1.f). Conforme.
  • Une scène a posé sa propre animation : mode SingleNode avec un autre clip, ou mode Anim BP (SingleNodeAnim nulle → !Playing vrai) → seule la vitesse est rendue à 1, retour sans écraser. Conforme.
  • Rien de capturé : !bAnimCaptured → retour immédiat (l. 1119-1122), aucun effet. Conforme. bAnimCaptured = false est posé avant les gardes (la capture est abandonnée dans tous les cas, comme annoncé au geste 6).
  • Détail : Playing est const 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 SetAnimationAsset annule CurrentAsset (squelette de l'asset nul ou maillage sans squelette, AnimSingleNodeInstance.cpp:47-60), SingleNodeAnim(Mesh) != WalkCycle resterait vrai et PlayAnimation serait relancé à chaque image. Situation d'asset invalide, non attendue ; à surveiller à l'essai (journal « Marche : animation » répété).
  • R3 (constat) : Source/LifePlay/LPShowCoupleSubsystem.cpp:127 lit encore Mesh->AnimationData.AnimToPlay (autre fonction, autre sous-système, hors fiche) ; même défaut possible si l'animation y est posée par PlayAnimation. Non évalué ici.
  • R4 : git status montre d'autres fichiers Source/LifePlay modifié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