LifePlay-Revival/Docs/Migration/etat/U58/U7b/U7b-T4-IMPL.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

26 KiB
Raw Blame History

Fiche U7b-T4 — Niveau N1 (rédaction N3) — Modèle prévu lp-impl | utilisé claude-opus-5-5 — Agent lp-impl — Skills sk-protocol (préchargés aussi : ue-cpp-build, lp-build, lp-ue-compat)

U7b-T4 : tournée Mesure hors écran (T1, option A) et garde-fou de RetargetPack sous UE ≥ 5.6 (T2 reporté)

Date : 2026-10-09. Addon = worktree D:\Game\LifePlay-Sandbox-5.8, branche ue5.8, HEAD d1efdd1 (tag U7b-avant). Rien n'a été commité. Je n'ai lancé ni le jeu, ni l'éditeur, ni le pipeline. Les essais statiques du § 6 tournent hors moteur : un faux module unreal et un faux UnrealEditor.exe, tous deux dans le bloc-notes de session. Le checkout 5.5 D:\Game\LifePlay-Sandbox est intact (git status --short : 0 ligne).

0. Résumé

Point État Preuve
(a) -RenderOffScreen est passé à la seule tournée Mesure du pilote fait § 3 (chaîne d'appel) et § 6.2 (cas 4 : la ligne reçue se termine par -RenderOffScreen)
(a) usage interactif inchangé établi, à l'octet près, sur la ligne de commande reçue par l'exécutable § 4 et § 6.2 (cas 1/2/5/6 identiques)
(b) refus sous UE ≥ 5.6, avant toute suppression ou création fait § 5 : appel RP:436, première suppression RP:265 atteinte par RP:451 ; essai § 6.1 : 0 appel d'asset
(b) BuildMod / AnimPipeline voient un échec établi par le code + essai statique de la regex § 5.2 et § 6.3
Correctif de portage T2 (diff § 5 de la CART) non appliqué, conformément à la fiche grep -c "run_batch_retarget|add_retarget_op" RetargetPack.py = 0

1. Fichiers, instantané, fins de ligne

Fichier (addon 5.8) Instantané U7b-addon (MD5 avant) MD5 après Fins de ligne / encodage avant → après git diff --stat
Tools\anim\AnimPipeline.ps1 6BC085152D53C3A15DDDFABF9505F0E0 (fait par l'orchestrateur) adc7a19ebfa1cb0b93b382e7f40ee526 LF 568 → LF 573, sans BOM, 4 octets non ASCII inchangés 7 +, 2 −
Tools\anim\RetargetPack.py 3C6491C6FF0DCCF4D44462FADC02C0ED (fait par l'orchestrateur) 182c60f3e8e0693ff9f6dcefc98790f9 LF 463 → LF 486, ASCII 23 +
Tools\debug\LifePlay_interaction_sandbox.bat EF13A3929D5E9A7332BFA2BA9FCE8984, ajouté par moi avant modification (commande de la fiche, sortie sauvegarde : ... 1 entree(s) ajoutee(s)) 7ec8d6350e2cbd36bedf2ccbef50fbd1 CRLF 10 → CRLF 15, ASCII, sans LF nu 6 +, 1 −
  • Manifeste : D:\Game\LifePlay_Backup_5.5\U7b-addon\manifest.csv, 3 entrées. Le MD5 du .bat sauvegardé est égal à celui de git show HEAD:Tools/debug/LifePlay_interaction_sandbox.bat (md5sum : ef13a392…).
  • Comptes produits par Python sur les octets (d.count(b"\r\n"), d.count(b"\n"), BOM, octets > 127). .gitattributes de l'addon : * -text, donc aucune conversion par git.
  • Pourquoi le .bat est modifié : il ne transmettait aucun argument (%* absent, .bat:9 d'avant ; U7b-T1-CART § 1.1). Sans cette modification, il aurait fallu lancer l'exécutable depuis le pilote en recopiant la résolution GAME/UE/PROJ du .bat, ce qui duplique la logique du lanceur.

2. Diffs (git -C D:\Game\LifePlay-Sandbox-5.8 diff)

--- a/Tools/anim/AnimPipeline.ps1
+++ b/Tools/anim/AnimPipeline.ps1
@@ -304,6 +304,10 @@ function Invoke-Sandbox {
     $modeF = Join-Path $saved 'sandbox_mode.txt'
     $tourF = Join-Path $saved 'sandbox_tour.txt'
     $bat = Join-Path $LPSbRoot 'Tools\debug\LifePlay_interaction_sandbox.bat'
+    # U7b (option A, U7b-T1-CART section 5) : la tournee rend hors ecran (pas de fenetre systeme), donc une fenetre reduite
+    # ne ramene plus le back buffer a 8x8 (assertion D3D12 de UE 5.8 a la capture). Option propre au pilote, passee en
+    # argument du .bat ; l'ouverture interactive (BuildMod.ps1 -Open) lance le .bat sans argument et garde sa fenetre.
+    $sbArgs = '-RenderOffScreen'
     $sbRel = ($c.sortie.clips -replace '^/Game/', '')
     $clipRel = ($c.source.clips -replace '^/Game/', '')
     $sbRoot = [string] $c.sandbox
@@ -314,7 +318,7 @@ function Invoke-Sandbox {
     $outDir = Join-Path $saved ($sbRoot -replace '/', '\')
     Add-Cmd "ecrire Saved\sandbox_pack.ini (Name=$Pack, ...)"
     Add-Cmd 'ecrire Saved\sandbox_mode.txt = Mesure ; Saved\sandbox_tour.txt = vignettes planches quitter'
-    Add-Cmd "Tools\debug\LifePlay_interaction_sandbox.bat   (attente de la fermeture de UnrealEditor, 40 min maximum)"
+    Add-Cmd "Tools\debug\LifePlay_interaction_sandbox.bat $sbArgs   (attente de la fermeture de UnrealEditor, 40 min maximum)"
     Add-Cmd "deplacer Saved\sandbox_pack.ini vers $(Get-WorkRel)\sandbox_pack.ini ; restaurer sandbox_mode.txt d'origine"
@@ -331,7 +335,8 @@ function Invoke-Sandbox {
         Write-Text $tourF 'vignettes planches quitter'
         # Sans tuyau ni attente : avec `& $bat | Out-Null`, PowerShell attendait la fin de l'editeur lance par le .bat
         # (heritier de la sortie), puis ne le trouvait plus et concluait a tort « pas lancee » (AP7).
-        Start-Process -FilePath 'cmd.exe' -ArgumentList ('/c "{0}"' -f $bat) -WindowStyle Hidden | Out-Null
+        # Commande entre guillemets doubles : cmd /c retire le premier et le dernier, le chemin du .bat reste entre guillemets.
+        Start-Process -FilePath 'cmd.exe' -ArgumentList ('/c ""{0}" {1}"' -f $bat, $sbArgs) -WindowStyle Hidden | Out-Null

(Dans le premier Add-Cmd du contexte, j'ai abrégé la parenthèse en ... ; cette ligne n'est pas modifiée.)

--- a/Tools/anim/RetargetPack.py
+++ b/Tools/anim/RetargetPack.py
@@ -13,6 +13,8 @@
 # Methode factice ou copie, ou profil du maillage source different de profil_source : ligne
 # "RETARGET echec : <cause>" puis arret.
+# Lot U7b : sous UE >= 5.6, refus de meme forme avant toute suppression ou creation d'asset (API IK Retargeter
+# non portee, U7b-T2-CART ; portage reporte apres V2.0).
@@ -22,6 +24,7 @@
 import json
 import math
 import os
+import re
@@ -57,6 +60,24 @@ class Refusal(Exception):
     pass
 
 
+# Lot U7b (2026-10-09) : l'API Python de l'IK Retargeter a change en UE 5.6-5.8 (U7b-T2-CART : 9e argument de
+# duplicate_and_retarget devenu target_path, reglages de chaine inertes, retargeter neuf sans op). Lance tel quel,
+# le script supprimerait les IK/RTG de reference (make_rig, make_retargeter) et les clips cuits B_/M_
+# (delete_copies) avant de planter. Portage reporte apres V2.0 : refus avant toute suppression ou creation.
+UNPORTED_FROM = (5, 6)
+UNPORTED_MESSAGE = "RetargetPack : API IK Retargeter 5.8 non portee (U7b-T2-CART, reporte apres V2.0) ; aucun asset modifie"
+
+
+def refuse_unported_engine():
+    # GetEngineVersion = FEngineVersion::Current().ToString(), ex. "5.8.3-58210709+++UE5+Release-5.8".
+    # Version illisible : refus aussi (rien ne prouve alors un moteur anterieur a 5.6).
+    text = str(unreal.SystemLibrary.get_engine_version())
+    unreal.log_warning("RETARGET moteur %s" % text)
+    match = re.match(r"\s*(\d+)\.(\d+)", text)
+    if match is None or (int(match.group(1)), int(match.group(2))) >= UNPORTED_FROM:
+        raise Refusal(UNPORTED_MESSAGE)
+
+
 def load_config(saved_dir):
@@ -411,6 +432,8 @@ def bake_named(clips, source_mesh, bodies):
 def run():
     global CFG
     CFG = load_config(unreal.Paths.project_saved_dir())
+    # U7b : avant toute suppression ou creation d'asset ; apres load_config, qui lit le jeton de BuildMod.
+    refuse_unported_engine()
     method = load_method(CFG["methode"])
--- a/Tools/debug/LifePlay_interaction_sandbox.bat
+++ b/Tools/debug/LifePlay_interaction_sandbox.bat
@@ -7,4 +7,9 @@
 set "PROJ=%GAME%\LifePlay.uproject"
-start "" "%UE%" "%PROJ%" "/Engine/Maps/Entry?game=/Script/LPSandbox.LPPairSandboxGameMode" -game -windowed -ResX=1600 -ResY=900 "-ini:Engine:[/Script/EngineSettings.GameMapsSettings]:GameInstanceClass=/Script/Engine.GameInstance"
+rem Lot U7b : les arguments de l'appelant sont ajoutes en fin de ligne (AnimPipeline.ps1 : -RenderOffScreen pour la
+rem tournee Mesure). Sans argument (double-clic, BuildMod.ps1 -Target sandbox -Open), la ligne de lancement est inchangee,
+rem a l'octet pres : EXTRA n'est defini (espace de tete comprise) que si des arguments sont passes.
+set "EXTRA=%*"
+if defined EXTRA set "EXTRA= %EXTRA%"
+start "" "%UE%" "%PROJ%" "/Engine/Maps/Entry?game=/Script/LPSandbox.LPPairSandboxGameMode" -game -windowed -ResX=1600 -ResY=900 "-ini:Engine:[/Script/EngineSettings.GameMapsSettings]:GameInstanceClass=/Script/Engine.GameInstance"%EXTRA%

3. Chaîne d'appel de -RenderOffScreen (lignes après modification)

  1. AnimPipeline.ps1:310 $sbArgs = '-RenderOffScreen'. Puis :339 lance Start-Process cmd.exe -ArgumentList '/c ""<addon>\Tools\debug\LifePlay_interaction_sandbox.bat" -RenderOffScreen"'. Une chaîne unique passée en -ArgumentList est transmise telle quelle comme ligne d'arguments.
  2. cmd /c : la ligne compte 4 guillemets, donc la règle 2 de cmd /? s'applique. cmd retire le premier guillemet et le dernier, et exécute "<chemin du .bat>" -RenderOffScreen. Texte de l'aide (cmd /?, poste en français) : « Dans le cas contraire, l'ancien comportement vérifiera si le premier caractère est un caractère guillemet et si tel est le cas, enlèvera le premier caractère et le dernier caractère guillemet de la ligne de commande ». Ainsi, le chemin du .bat reste entre guillemets, même s'il contient une espace (essai § 6.2, dossier dossier avec espace).
  3. .bat:13 set "EXTRA=%*" donne EXTRA=-RenderOffScreen. .bat:14 ajoute l'espace de tête : EXTRA= -RenderOffScreen. .bat:15 lance start "" "%UE%" "%PROJ%" "/Engine/Maps/Entry?game=…" -game -windowed -ResX=1600 -ResY=900 "-ini:…GameInstance" -RenderOffScreen.
  4. Moteur 5.8 : FWindowsPlatformApplicationMisc::CreateApplication teste FParse::Param(FCommandLine::Get(), TEXT("RenderOffScreen")) et renvoie alors l'application nulle (D:\Game\Launcher\Engine\UE_5.8\Engine\Source\Runtime\ApplicationCore\Private\Windows\WindowsPlatformApplicationMisc.cpp:173-176). Il n'y a ni écran de démarrage (Runtime\Launch\Private\LaunchEngineLoop.cpp:3111) ni fenêtre système (Runtime\ApplicationCore\Private\GenericPlatform\GenericWindow.cpp:29, 113). La suite de la mécanique (texture hors écran, pas de back buffer de 8×8) est décrite dans U7b-T1-CART § 4.1.
  5. Le pilote attend toujours le processus UnrealEditor (AnimPipeline.ps1:340-345, inchangé). Le nom du processus ne change pas avec l'option.

4. Preuve que l'usage interactif est inchangé

  • Appelants du .bat (établi) : grep -rn interaction_sandbox sur l'addon (hors Content) et sur D:\Game\LifePlay-master 5.8\{Tools,README.md,Docs} :
    • BuildMod.ps1:165 & (Join-Path $LPSbRoot 'Tools\debug\LifePlay_interaction_sandbox.bat'), sans argument ;
    • AnimPipeline.ps1:306/321/339 (le pilote) ;
    • les docs 09_Commandes_Utiles.md:97 et 21_Sandbox_Addon.md:49, qui décrivent un lancement manuel sans argument. Aucun autre script n'appelle le .bat. LifePlay_measure_sandbox.bat et LifePlay_pair_sandbox.bat ne l'appellent pas et ne sont pas modifiés.
  • Sans argument, EXTRA n'est pas défini : set "EXTRA=" efface la variable. Dans un .bat, une variable non définie se développe en chaîne vide, donc .bat:15 est identique à l'ancienne ligne 9. Une valeur EXTRA héritée de l'environnement est aussi effacée (cas 6 ci-dessous).
  • Essai (établi, § 6.2) : ligne de commande brute (Environment.CommandLine, c'est-à-dire GetCommandLineW) reçue par un faux UnrealEditor.exe, en comparant l'ancien .bat (HEAD) et le nouveau :
    • cas 1 (ancien, & bat comme BuildMod.ps1:165) = cas 2 (nouveau, même appel) : identiques à l'octet (-ceq → True) ;
    • cas 5 (nouveau, cmd /c "<bat>", comme un double-clic) = cas 1 : True ;
    • cas 6 (nouveau, EXTRA=-pollution dans l'environnement, sans argument) = cas 1 : True ;
    • cas 3 (ancien appel du pilote sur l'ancien .bat) = cas 1 : True, donc avant U7b le pilote lançait bien la même ligne que l'usage interactif ;
    • cas 4 (nouveau pilote) = cas 1 + -RenderOffScreen : True ;
    • cas 7 (deux arguments) = cas 1 + -RenderOffScreen -log : True.
  • Une première version (… GameInstance" %*) laissait une espace finale dans la ligne interactive : le cas 2 se terminait par GameInstance" ] (écart constaté par le même essai). Je l'ai remplacée par la forme EXTRA avant de livrer. Ce point est noté au § 7.

5. Garde-fou de RetargetPack.py (b)

5.1 Position (lignes après modification, grep -n)

  • RP:434 CFG = load_config(...) : lecture seule de Saved\anim_retarget.json (et de anim_to_genesis_step.txt), pour le jeton (RP:89). Aucun appel d'asset dans load_config (RP:81-112).
  • RP:436 refuse_unported_engine(), définie en RP:71-78.
  • Premier appel qui touche un asset après le garde-fou : RP:451 make_rig(...), qui exécute RP:265 delete_asset (première suppression) puis RP:270 create_asset (première création). Viennent ensuite :
    • make_retargeter, appelé en RP:455 (RP:287 suppression, RP:288 création) ;
    • delete_copies, appelé en RP:461 (RP:333) ;
    • bake_named, appelé en RP:464.
  • Avant RP:436, il n'y a que des définitions et NONE = unreal.Name() au niveau du module. Aucun accès à un asset.
  • Le garde-fou précède la bifurcation mode == "rigs" : il couvre donc les deux modes (-Retarget bake et -Retarget rigs).

5.2 Comment l'échec remonte (établi par lecture du code)

  1. Refusal est interceptée par main() (RP:476-478). Le script écrit alors RETARGET echec : RetargetPack : API IK Retargeter 5.8 non portee (U7b-T2-CART, reporte apres V2.0) ; aucun asset modifie jeton <j>, puis appelle quit_editor(). Une ligne RETARGET moteur <version> la précède.
  2. BuildMod.ps1:74-76 Find-RetargetLine reconnaît la ligne comme un Failure. Ensuite, BuildMod.ps1:139 lève throw "Conversion en echec : …", et pwsh -File se termine en erreur.
  3. AnimPipeline.ps1 : le .cmd de l'étape 4 se termine par @exit /b %ERRORLEVEL% (:281).
    • :284 lit le code de sortie.
    • :288 voit le contrôle « conversion : code 0 » en échec.
    • :287-290 ne trouve pas la ligne RETARGET bridget n michael n et lève throw 'conversion non confirmee'.
  4. API moteur utilisée :
    • UKismetSystemLibrary::GetEngineVersion : D:\Game\Launcher\Engine\UE_5.8\Engine\Source\Runtime\Engine\Classes\Kismet\KismetSystemLibrary.h:213-215 (5.5 : :170). Son implémentation est FEngineVersion::Current().ToString() (…\Engine\Private\KismetSystemLibrary.cpp:268-271).
    • ToString vaut par défaut EVersionComponent::Branch (Runtime\Core\Public\Misc\EngineVersion.h:34). Le format produit est Major.Minor.Patch-CL+Branch (Runtime\Core\Private\Misc\EngineVersion.cpp:140-160).
    • Le nom Python unreal.SystemLibrary est celui que le script emploie déjà pour quit_editor (RP:344, KismetSystemLibrary.h:656).
    • Version de l'installation : Build.version, 5.8.3 (5.5 : 5.5.4).

5.3 Correctif de portage non appliqué

Aucune des lignes du diff de U7b-T2-CART § 5 n'est présente : grep -c "run_batch_retarget\|add_retarget_op\|set_fk_chains" Tools/anim/RetargetPack.py = 0.

6. Essais statiques (hors moteur, bloc-notes de session)

Dossier : %USERPROFILE%\AppData\Local\Temp\claude\D--Game-LifePlay-master-5-5\ab8918a1-261f-45b4-904a-678ecfce98f7\scratchpad\u7bt4\.

  1. Garde-fou : python -I -B test_guard.py, avec le faux module stub\unreal.py. Tout appel d'asset y lève une erreur. Le script importé est le vrai RetargetPack.py de l'addon. Résultat : echecs : 0, code 0.
    • Versions 5.8.3-58210709+++UE5+Release-5.8, 5.6.0-…, 6.0.0-… et illisible :
      • journal = RETARGET moteur <v> puis RETARGET echec : RetargetPack : API IK Retargeter 5.8 non portee (U7b-T2-CART, reporte apres V2.0) ; aucun asset modifie jeton abc123def456 ;
      • appels = get_engine_version puis quit_editor seulement, soit 0 appel d'asset.
    • Version 5.5.4-40574608+++UE5+Release-5.5 : le garde-fou laisse passer. Le premier appel d'asset est load_asset /Game/Quaternius/UAL/UAL1_Standard…, que le faux module fait échouer volontairement.
    • Aucun __pycache__ n'a été créé dans l'addon (git status --short --ignored Tools/anim : seulement les 2 M).
  2. Lanceur : pwsh -NoProfile -File sim\run_sim.ps1.
    • Faux UnrealEditor.exe compilé par csc.exe (.NET Framework 4, /target:winexe) : il écrit Environment.CommandLine.
    • Copies de l'ancien et du nouveau .bat, dans sim\dossier avec espace\. Leur moteur par défaut est remplacé par un chemin absent, et LP_ENGINE_ROOT/LP_GAMEROOT pointent vers des dossiers factices : aucun moteur réel ne pouvait partir.
    • Les 7 cas et les 6 comparaisons sont au § 4 : toutes à True.
  3. Regex de BuildMod : pwsh -NoProfile -File test_find.ps1. La fonction Find-RetargetLine est extraite de BuildMod.ps1 par l'AST (BuildMod n'est pas exécuté). Pour les modes bake et rigs : Hit=[] et Failure=[RETARGET echec : RetargetPack : … aucun asset modifie jeton abc123def456].
  4. Syntaxe :
    • ast.parse(RetargetPack.py) : OK ;
    • [Parser]::ParseFile(AnimPipeline.ps1) : erreurs de syntaxe : 0.

7. Écarts à la fiche et à la SPEC

  1. Le .bat est modifié (cas « si nécessaire » de la fiche). Il ne transmettait pas %*. Je l'ai ajouté à l'instantané avant de le modifier, avec la commande de la fiche.
  2. Forme EXTRA au lieu d'un %* brut en fin de ligne. Le %* brut ajoutait une espace finale à la ligne interactive (constaté au § 6.2). La forme retenue donne une ligne identique à l'octet. Elle coûte 2 lignes de plus que la suggestion de la fiche.
  3. Le garde-fou refuse aussi une version illisible, par prudence : rien ne prouve alors un moteur antérieur à 5.6. Il écrit en plus la ligne RETARGET moteur <version> avant le refus. Le message de refus est exactement celui de la fiche, préfixé par RETARGET echec : et suivi de jeton <j> (format existant, RP:476-478).
  4. « Ne rien lancer » : je n'ai lancé ni jeu, ni éditeur, ni pipeline. J'ai en revanche exécuté des essais statiques hors moteur (§ 6) : le vrai script Python avec un faux module unreal, et les copies du .bat avec un faux exécutable. C'est une lecture de la consigne, que je signale ici.
  5. Erreur de lecture corrigée en cours de travail : un premier grep -c $'\r$' sous Git Bash avait donné « CRLF » pour les 3 fichiers. Le comptage sur les octets montre que AnimPipeline.ps1 et RetargetPack.py sont en LF et le .bat en CRLF. Mon premier script de remplacement s'est donc arrêté sur AnimPipeline.ps1 : 0 occurrence, aucune écriture. Le .bat, déjà traité à ce moment, était en CRLF et l'est resté. Le second script détecte la fin de ligne de chaque fichier. État final au § 1.
  6. Docs non mises à jour (hors fichiers autorisés) : D:\Game\LifePlay-master 5.8\Docs\Migration\20_Chaine_Animations.md (étape 5) et 21_Sandbox_Addon.md (lanceurs, report U5 de RetargetPack). Elles relèvent de la phase DOC.

8. Incertitudes

  • Comportement réel de -RenderOffScreen en 5.8 : taille effective du viewport (avec r.setres:1280x720 en config), rythme des images, géométrie. Ce sont les risques (a) et (b) de U7b-T1-CART § 4.1. Ils restent incertains jusqu'à l'essai du § 9.
  • Garde-fou dans l'éditeur 5.8 réel : il a été essayé avec un faux module seulement. La chaîne get_engine_version → ToString est établie par les sources, le comportement Python de bout en bout ne l'est pas. Essai sans risque proposé pour la VAL :
    • commande : BuildMod.ps1 -GameRoot "D:\Game\LifePlay-master 5.8" -Retarget rigs -RetargetOnly -RetargetConfig <json>, avec {"mode":"rigs","methode":"ue4","dest":"/Game/_TempU7b/Retarget"} (mode rigs sur une destination temporaire : même si le garde-fou ne jouait pas, ni référence ni clip ne seraient touchés) ;
    • attendu : Conversion en echec : RETARGET echec : RetargetPack : API IK Retargeter 5.8 non portee … jeton <j>, et /Game/_TempU7b absent.
  • Anomalie hors de mon périmètre (établi, à examiner avant l'essai T1) : la copie de jeu 5.8 a des modifications qui ne viennent pas de moi (git -C "D:\Game\LifePlay-master 5.8" status --short : M .gitignore, M LifePlay.uproject).
    • .gitignore est modifié à 13:31:19, avant le début de cette fiche : bloc # BEGIN HYPERAISTUDIO MANAGED RUNTIME IGNORE.
    • LifePlay.uproject est modifié à 13:36:27, soit 105 lignes : des plugins Éditeur AIModuleToolset, AnimationAssistantToolset, AutomationTestToolset, ConfigSettingsToolset, DataflowAgent, etc. ont été activés.
    • Aucune de mes commandes n'écrit dans ce dossier. La seule qui s'y place est Snapshot.ps1 (Set-Location), et elle copie seulement vers Backup_5.5.
    • L'essai T1 lance ce .uproject : l'orchestrateur doit décider s'il garde ou restaure cet état avant l'essai. Je n'y ai pas touché.

9. Essai T1 à confier à lp-builder (une tournée d'un clip, AS_RightLegKick2, pack freeanims)

Conditions préalables :

  • pwsh 7, éditeur fermé ;
  • build 5.8 du jeu à jour (aucun C++ modifié par cette fiche) ;
  • DLL de l'addon vérifiées (lp-build § 8) ;
  • anomalie du § 8 tranchée.

L'essai ne lance pas AnimPipeline. Il reproduit Invoke-Sandbox pour un seul clip, avec le même appel cmd /c que AnimPipeline.ps1:339. La sortie va dans un dossier neuf, Saved\U7b\T1essai_<date>, pour ne pas écraser les planches de U4-T6.

$G = 'D:\Game\LifePlay-master 5.8'; $S = "$G\Saved"
$bat = 'D:\Game\LifePlay-Sandbox-5.8\Tools\debug\LifePlay_interaction_sandbox.bat'
$stamp = Get-Date -Format 'yyyyMMdd-HHmmss'; $rel = "U7b/T1essai_$stamp"; $W = "$S\U7b\T1essai_$stamp"
if (Get-Process UnrealEditor, UnrealEditor-Cmd -ErrorAction SilentlyContinue) { throw 'editeur ouvert' }
New-Item -ItemType Directory -Force $W | Out-Null
$utf8 = New-Object Text.UTF8Encoding $false
$origMode = if (Test-Path "$S\sandbox_mode.txt") { [IO.File]::ReadAllText("$S\sandbox_mode.txt") } else { $null }   # 'Pair' le 2026-10-09
foreach ($f in 'sandbox_pack.ini', 'sandbox_tour.txt') { if (Test-Path "$S\$f") { Move-Item "$S\$f" "$W\$f.avant" } }
$ini = [IO.File]::ReadAllText("$S\AnimPipeline\freeanims\sandbox_pack.ini") -replace 'MeasureOutputRoot=.*', "MeasureOutputRoot=$rel/sandbox"
[IO.File]::WriteAllText("$S\sandbox_pack.ini", $ini, $utf8)
[IO.File]::WriteAllText("$S\sandbox_mode.txt", 'Mesure', $utf8)
[IO.File]::WriteAllText("$S\sandbox_tour.txt", 'vignettes planches quitter AS_RightLegKick2', $utf8)
try {
    Start-Process -FilePath 'cmd.exe' -ArgumentList ('/c ""{0}" {1}"' -f $bat, '-RenderOffScreen') -WindowStyle Hidden | Out-Null
    $d = (Get-Date).AddMinutes(3); while (-not (Get-Process UnrealEditor -ErrorAction SilentlyContinue) -and (Get-Date) -lt $d) { Start-Sleep 3 }
    if (-not (Get-Process UnrealEditor -ErrorAction SilentlyContinue)) { throw 'sandbox non lancee (3 min)' }
    $d = (Get-Date).AddMinutes(15); while ((Get-Process UnrealEditor -ErrorAction SilentlyContinue) -and (Get-Date) -lt $d) { Start-Sleep 5 }
    if (Get-Process UnrealEditor -ErrorAction SilentlyContinue) { throw 'sandbox non fermee en 15 min (laissee ouverte)' }
}
finally {
    foreach ($f in 'sandbox_pack.ini', 'sandbox_tour.txt', 'sandbox_mode.txt') { if (Test-Path "$S\$f") { Move-Item "$S\$f" "$W\$f" -Force } }
    if ($null -ne $origMode) { [IO.File]::WriteAllText("$S\sandbox_mode.txt", $origMode, $utf8) }
    foreach ($f in 'sandbox_pack.ini', 'sandbox_tour.txt') { if (Test-Path "$W\$f.avant") { Move-Item "$W\$f.avant" "$S\$f" } }
}
Copy-Item "$S\Logs\LifePlay.log" "$W\LifePlay.log"
Select-String -Path "$W\LifePlay.log" -Pattern 'Command Line:', 'VIGNETTE .*AS_RightLegKick2', 'PLANCHE .*AS_RightLegKick2', 'Assertion failed', 'out of bounds' | ForEach-Object { $_.Line }
Get-ChildItem "$W\sandbox" -Recurse -File | Select-Object FullName, Length

Attendus (référence U7b-T1-CART § 6.1, relue dans D:\Game\LifePlay_Backup_5.5\U4-REF55\E4_freeanims.log:1939, 5460 et U4-T6\E4_freeanims.log:2277, 5806) :

  • ligne LogInit: Command Line: terminée par -RenderOffScreen ;
  • VIGNETTE …/vignettes/AS_RightLegKick2.png (carre 695 px a 621,173) ;
  • PLANCHE …/planches/AS_RightLegKick2.jpg 13 images 1.10 s <n> octets (carre 724 px) (le nombre d'octets varie : 88113 en 5.5, 88496 en 5.8) ;
  • 0 Assertion failed, 0 out of bounds ;
  • fichiers vignettes\AS_RightLegKick2.png (512×512), planches\AS_RightLegKick2.jpg (3328×256 pour 13 images) et planches\AS_RightLegKick2.json.

Le dossier de sortie est créé par la tournée (MakeDirectory(…, true), LPSandboxMeasureTour.cpp:421, 426, 432). Après l'essai, Saved\sandbox_mode.txt doit valoir à nouveau Pair. Variante pour un essai contraire : réduire une fenêtre est sans objet, puisqu'il n'y a plus de fenêtre système.

10. État final

git -C D:\Game\LifePlay-Sandbox-5.8 status --short :

 M Tools/anim/AnimPipeline.ps1
 M Tools/anim/RetargetPack.py
 M Tools/debug/LifePlay_interaction_sandbox.bat
  • git -C D:\Game\LifePlay-Sandbox status --short (checkout 5.5) : 0 ligne.
  • Fichiers écrits :
    • les 3 fichiers ci-dessus ;
    • D:\Game\LifePlay_Backup_5.5\U7b-addon\manifest.csv (+1 entrée) et D:\Game\LifePlay_Backup_5.5\U7b-addon\Tools\debug\LifePlay_interaction_sandbox.bat ;
    • ce livrable ;
    • les fichiers d'essai du bloc-notes de session (hors projet).
  • Retour arrière proposé, non exécuté : pwsh -NoProfile -Command "Set-Location 'D:\Game\LifePlay-master 5.8'; .\Tools\Restore.ps1 -Lot U7b-addon -ProjectRoot 'D:\Game\LifePlay-Sandbox-5.8'", ou git -C D:\Game\LifePlay-Sandbox-5.8 checkout -- <fichier>.