L7j : camera SecondScreen dotee d'une racine et placee (ERR-031) ; L7l : diagnostic du sol de neige (ERR-036)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
edujiro5972 2026-10-01 22:08:14 +02:00
parent 928826139f
commit af1861b989
6 changed files with 228 additions and 6 deletions

Binary file not shown.

View file

@ -150,8 +150,8 @@ Ordre indicatif, à réviser selon le registre :
| L7g | Packaging | build Shipping `LifePlay_Build_5.5_Shipping` construite (CHG-046), même structure que la version de l'auteur ; `McpAutomationBridge` déjà limité à l'éditeur ; ✅ validée en jeu le 2026-10-01 | | L7g | Packaging | build Shipping `LifePlay_Build_5.5_Shipping` construite (CHG-046), même structure que la version de l'auteur ; `McpAutomationBridge` déjà limité à l'éditeur ; ✅ validée en jeu le 2026-10-01 |
| L7h | Vérification StreetMap | ✅ 280 villes et 280 maillages identiques 4.27/5.5 (ERR-018 clos, CHG-044) | | L7h | Vérification StreetMap | ✅ 280 villes et 280 maillages identiques 4.27/5.5 (ERR-018 clos, CHG-044) |
| L7i | Variables DSL `Person` vides | ✅ ERR-030, ERR-037, ERR-003 préexistants en 4.27 ; ERR-005 corrigé par CX-B12 (385 nœuds `Contains`/`Split`/`FindSubstring`), validé en jeu le 2026-10-01 | | L7i | Variables DSL `Person` vides | ✅ ERR-030, ERR-037, ERR-003 préexistants en 4.27 ; ERR-005 corrigé par CX-B12 (385 nœuds `Contains`/`Split`/`FindSubstring`), validé en jeu le 2026-10-01 |
| L7j | Écran secondaire (amélioration) | ERR-031, préexistant en 4.27 : caméra `SecondScreen` sans racine ; seulement si souhaité | | L7j | Écran secondaire (amélioration) | caméra `SecondScreen` dotée d'une racine et placée sur `CameraScene` − 10 000 000 Y (CHG-052) ; test en jeu en attente |
| L7l | Personnages enfoncés dans le sol en extérieur (amélioration) | ERR-036, préexistant en 4.27 ; seulement si souhaité | | L7l | Personnages enfoncés dans le sol en extérieur (amélioration) | diagnostic (CHG-053) : sol de neige `fnt_new208` étiré ×100 en hauteur dans `forest___vin01.lpworld` (donnée de module) ; correction à caler par une mesure en jeu |
| L7k | Erreurs d'exécution fréquentes (ex-L7b) | ✅ ERR-006 et ERR-007 revenus au niveau 4.27 avec CX-B12 ; signatures restantes au niveau 4.27 (CHG-045) | | L7k | Erreurs d'exécution fréquentes (ex-L7b) | ✅ ERR-006 et ERR-007 revenus au niveau 4.27 avec CX-B12 ; signatures restantes au niveau 4.27 (CHG-045) |
## 4. Décisions ## 4. Décisions

View file

@ -823,3 +823,34 @@ le rendu passait donc déjà par SkyAtmosphere. Éclairage précalculé : `Centr
sont déjà actifs ; ils exécutent les 34 actions et axes hérités de `DefaultInput.ini`. Une migration complète sont déjà actifs ; ils exécutent les 34 actions et axes hérités de `DefaultInput.ini`. Une migration complète
(Input Actions, Mapping Contexts, réécriture des événements d'entrée des Blueprints) n'apporterait rien au joueur (Input Actions, Mapping Contexts, réécriture des événements d'entrée des Blueprints) n'apporterait rien au joueur
et demanderait un test manuel des 34 commandes : reportée. et demanderait un test manuel des 34 commandes : reportée.
### L7j — image du contact pendant un appel (ERR-031, amélioration), 2026-10-01
| CHG | Date | Lot | Fichiers | Raison | Retour arrière |
|---|---|---|---|---|---|
| CHG-052 | 2026-10-01 | L7j | `Source/LifePlayEditorTools/LPFixSceneCaptureCommandlet` (nouveau) ; `Content/Scenes/CentralLondon.umap` | ERR-031 (présent en 4.27) : la caméra `SecondScreen` filme le ciel | `Tools\Restore.ps1 -Lot L7j` |
Chaîne (L6f et L7j) : `GI::secondScreen` marque le contact (`Person.secondScreen`) ; `GI::Show` le place sur la position
de son emplacement de scène (`ActorTransforms[i]`) **décalée de −10 000 000 en Y**, sur la copie de studio
`SecondScreenFloor` (−3 131 543 ; −24 967 212, soit le studio des scènes − 10 000 000 Y) ; l'encadré affiche
`Render/SecondScreen`, rendu par la caméra `SecondScreen`. Aucun Blueprint ne déplace cette caméra ; dans la carte
(4.27 comme 5.5) elle n'a pas de racine (`RootComponent = None`) et ses composants sont à l'origine.
Correctif : racine = son `SceneComponent` existant, capture rattachée, position = `CameraScene` (cadrage des scènes du
studio : −3 131 132 ; −14 967 241 ; 50, lacet 180°) − 10 000 000 Y. Contrôle intégré (racine, rattachement, position
monde = cible) puis diff `LPDumpAssets` de la carte : **3 lignes modifiées**, toutes sur `SecondScreen`
(`Saved/Logs/portage/L7d_map_apres.txt` → `L7j_map_apres.txt`). Le cadrage (scène entière plutôt que portrait) est à
ajuster d'après le test en jeu si nécessaire (`-From=CameraPortrait`).
### L7l — personnages enfoncés dans le sol en extérieur (ERR-036, amélioration), 2026-10-01 : diagnostic
| CHG | Date | Lot | Fichiers | Raison | Retour arrière |
|---|---|---|---|---|---|
| CHG-053 | 2026-10-01 | L7l | `Source/LifePlayEditorTools/LPCheckMeshesCommandlet` (colonnes `MinZ`, `MaxZ`) | diagnostic | — |
Le lieu `Modules/vin_Base/World/forest___vin01.lpworld` (donnée de module, identique en 4.27) pose comme sol le meuble
`fnt_new208` (dalle 230 × 99 × 0,6) en Z = −31,2 avec une échelle (0,713 ; 1,481 ; **100**) ; ailleurs (`bathroom`,
`shower`, `sports_centre`) le même meuble est un petit objet (Z = 60, échelle 5). Les meubles sont rattachés à un point
d'ancrage en Z = 60 (`Room::addObject`). La hauteur exacte de la surface de neige par rapport au sol de marche dépend
de la chaîne de composants du meuble : une mesure en jeu est nécessaire avant de corriger le fichier (ou d'ajuster la
dalle avec l'éditeur de lieu intégré au jeu, « Edit building »).

View file

@ -42,7 +42,7 @@ int32 ULPCheckMeshesCommandlet::Main(const FString& Params)
Assets.Sort([](const FAssetData& A, const FAssetData& B) { return A.AssetName.LexicalLess(B.AssetName); }); Assets.Sort([](const FAssetData& A, const FAssetData& B) { return A.AssetName.LexicalLess(B.AssetName); });
TArray<FString> Lines; TArray<FString> Lines;
Lines.Add(TEXT("Mesh;LODs;SommetsSource;TrianglesSource;SommetsRendu;TrianglesRendu;Sections;Materiaux;TailleX;TailleY;TailleZ")); Lines.Add(TEXT("Mesh;LODs;SommetsSource;TrianglesSource;SommetsRendu;TrianglesRendu;Sections;Materiaux;TailleX;TailleY;TailleZ;MinZ;MaxZ"));
int32 Failures = 0; int32 Failures = 0;
for (const FAssetData& AssetData : Assets) for (const FAssetData& AssetData : Assets)
@ -66,11 +66,12 @@ int32 ULPCheckMeshesCommandlet::Main(const FString& Params)
const int32 RenderVerts = Mesh->GetNumVertices(0); const int32 RenderVerts = Mesh->GetNumVertices(0);
const int32 RenderTris = Mesh->GetNumTriangles(0); const int32 RenderTris = Mesh->GetNumTriangles(0);
const int32 Sections = Mesh->GetNumSections(0); const int32 Sections = Mesh->GetNumSections(0);
const FVector Size = Mesh->GetBoundingBox().GetSize(); const FBox Box = Mesh->GetBoundingBox();
const FVector Size = Box.GetSize();
Lines.Add(FString::Printf(TEXT("%s;%d;%d;%d;%d;%d;%d;%d;%.0f;%.0f;%.0f"), Lines.Add(FString::Printf(TEXT("%s;%d;%d;%d;%d;%d;%d;%d;%.0f;%.0f;%.0f;%.2f;%.2f"),
*AssetData.AssetName.ToString(), Mesh->GetNumLODs(), SrcVerts, SrcTris, RenderVerts, RenderTris, *AssetData.AssetName.ToString(), Mesh->GetNumLODs(), SrcVerts, SrcTris, RenderVerts, RenderTris,
Sections, Mesh->GetStaticMaterials().Num(), Size.X, Size.Y, Size.Z)); Sections, Mesh->GetStaticMaterials().Num(), Size.X, Size.Y, Size.Z, Box.Min.Z, Box.Max.Z));
} }
if (!FFileHelper::SaveStringArrayToFile(Lines, *CsvPath, FFileHelper::EEncodingOptions::ForceUTF8WithoutBOM)) if (!FFileHelper::SaveStringArrayToFile(Lines, *CsvPath, FFileHelper::EEncodingOptions::ForceUTF8WithoutBOM))

View file

@ -0,0 +1,159 @@
// Portage UE 5.5 - voir LPFixSceneCaptureCommandlet.h
#include "LPFixSceneCaptureCommandlet.h"
#include "Components/SceneCaptureComponent2D.h"
#include "Engine/Level.h"
#include "Engine/SceneCapture2D.h"
#include "Engine/World.h"
#include "Misc/PackageName.h"
#include "UObject/Package.h"
#include "UObject/SavePackage.h"
DEFINE_LOG_CATEGORY_STATIC(LogLPFixSceneCapture, Log, All);
namespace
{
AActor* FindActorByLabelOrName(ULevel* Level, const FString& Name)
{
for (AActor* Actor : Level->Actors)
{
if (Actor && (Actor->GetActorLabel() == Name || Actor->GetName() == Name))
{
return Actor;
}
}
return nullptr;
}
}
ULPFixSceneCaptureCommandlet::ULPFixSceneCaptureCommandlet()
{
IsClient = false;
IsServer = false;
IsEditor = true;
LogToConsole = true;
}
int32 ULPFixSceneCaptureCommandlet::Main(const FString& Params)
{
TArray<FString> Tokens, Switches;
TMap<FString, FString> ParamsMap;
ParseCommandLine(*Params, Tokens, Switches, ParamsMap);
const bool bDryRun = Switches.Contains(TEXT("DryRun"));
const FString MapPath = ParamsMap.FindRef(TEXT("Map"));
const FString ActorName = ParamsMap.FindRef(TEXT("Actor"));
const FString FromName = ParamsMap.FindRef(TEXT("From"));
FVector Offset = FVector::ZeroVector;
{
TArray<FString> Parts;
ParamsMap.FindRef(TEXT("Offset")).ParseIntoArray(Parts, TEXT(","), true);
if (Parts.Num() == 3)
{
Offset = FVector(FCString::Atod(*Parts[0]), FCString::Atod(*Parts[1]), FCString::Atod(*Parts[2]));
}
}
if (MapPath.IsEmpty() || ActorName.IsEmpty() || FromName.IsEmpty())
{
UE_LOG(LogLPFixSceneCapture, Error, TEXT("Usage : -Map=/Game/Scenes/X -Actor=<capture> -From=<acteur de reference> [-Offset=x,y,z] [-DryRun]"));
return 1;
}
const FString WorldPath = MapPath + TEXT(".") + FPackageName::GetShortName(MapPath);
UWorld* World = LoadObject<UWorld>(nullptr, *WorldPath);
if (!World || !World->PersistentLevel)
{
UE_LOG(LogLPFixSceneCapture, Error, TEXT("Carte introuvable : %s"), *WorldPath);
return 1;
}
World->AddToRoot();
ASceneCapture2D* Capture = Cast<ASceneCapture2D>(FindActorByLabelOrName(World->PersistentLevel, ActorName));
AActor* From = FindActorByLabelOrName(World->PersistentLevel, FromName);
if (!Capture || !From || !From->GetRootComponent())
{
UE_LOG(LogLPFixSceneCapture, Error, TEXT("Acteur introuvable : %s (capture) ou %s (reference, avec racine)"), *ActorName, *FromName);
World->RemoveFromRoot();
return 1;
}
USceneCaptureComponent2D* CaptureComp = Capture->GetCaptureComponent2D();
USceneComponent* NewRoot = nullptr;
for (UActorComponent* Comp : Capture->GetComponents())
{
USceneComponent* SceneComp = Cast<USceneComponent>(Comp);
if (SceneComp && SceneComp != CaptureComp && SceneComp->GetClass() == USceneComponent::StaticClass())
{
NewRoot = SceneComp;
break;
}
}
if (!NewRoot)
{
NewRoot = CaptureComp;
}
const FTransform FromTransform = From->GetRootComponent()->GetRelativeTransform();
const FTransform Target(FromTransform.GetRotation(), FromTransform.GetLocation() + Offset, FVector::OneVector);
UE_LOG(LogLPFixSceneCapture, Warning, TEXT("=== %s : racine %s -> %s, cible %s (= %s + %s)%s ==="),
*Capture->GetActorLabel(), *GetNameSafe(Capture->GetRootComponent()), *GetNameSafe(NewRoot),
*Target.ToString(), *FromName, *Offset.ToString(), bDryRun ? TEXT(" [DRY RUN]") : TEXT(""));
if (bDryRun)
{
World->RemoveFromRoot();
return 0;
}
Capture->Modify();
Capture->SetRootComponent(NewRoot);
if (CaptureComp && CaptureComp != NewRoot)
{
CaptureComp->AttachToComponent(NewRoot, FAttachmentTransformRules::KeepRelativeTransform);
CaptureComp->SetRelativeTransform(FTransform::Identity);
}
NewRoot->SetRelativeTransform(Target);
NewRoot->UpdateComponentToWorld();
if (CaptureComp && CaptureComp != NewRoot)
{
CaptureComp->UpdateComponentToWorld();
}
// Verification : racine, rattachement, position monde de la capture.
int32 Errors = 0;
if (Capture->GetRootComponent() != NewRoot) { ++Errors; UE_LOG(LogLPFixSceneCapture, Error, TEXT(" racine non affectee")); }
if (CaptureComp && CaptureComp != NewRoot && CaptureComp->GetAttachParent() != NewRoot) { ++Errors; UE_LOG(LogLPFixSceneCapture, Error, TEXT(" capture non rattachee")); }
const FTransform Final = CaptureComp ? CaptureComp->GetComponentTransform() : NewRoot->GetComponentTransform();
if (!Final.Equals(Target, 0.01))
{
++Errors;
UE_LOG(LogLPFixSceneCapture, Error, TEXT(" position finale %s differente de la cible %s"), *Final.ToString(), *Target.ToString());
}
UE_LOG(LogLPFixSceneCapture, Warning, TEXT(" capture : position monde %s"), *Final.ToString());
int32 Result = 0;
if (Errors == 0)
{
UPackage* Package = World->GetOutermost();
const FString Filename = FPackageName::LongPackageNameToFilename(Package->GetName(), FPackageName::GetMapPackageExtension());
FSavePackageArgs SaveArgs;
SaveArgs.TopLevelFlags = RF_Standalone;
SaveArgs.Error = GWarn;
if (UPackage::SavePackage(Package, World, *Filename, SaveArgs))
{
UE_LOG(LogLPFixSceneCapture, Warning, TEXT(" -> carte sauvegardee"));
}
else
{
UE_LOG(LogLPFixSceneCapture, Error, TEXT(" ECHEC de sauvegarde"));
Result = 1;
}
}
else
{
UE_LOG(LogLPFixSceneCapture, Error, TEXT(" %d ecart(s) : carte NON sauvegardee"), Errors);
Result = 1;
}
World->RemoveFromRoot();
return Result;
}

View file

@ -0,0 +1,31 @@
// Portage UE 5.5 - lot L7j (ERR-031, amelioration : defaut deja present en 4.27).
//
// La camera SceneCapture2D "SecondScreen" de CentralLondon (image du contact dans l'encadre d'appel) n'a
// pas de composant racine (RootComponent = None) et ses composants sont a l'origine : elle filme le ciel.
// Les Blueprints ne la deplacent pas. Le contact affiche est place a la position de son emplacement de
// scene decalee de -10 000 000 en Y (GI::Show), sur la copie de scene SecondScreenFloor.
//
// Cette commandlet donne a l'acteur vise un composant racine (son SceneComponent existant, ou le
// composant de capture a defaut), y rattache le composant de capture, et le place sur la transformation
// d'un acteur de reference (camera du portrait) augmentee d'un decalage. Tout est verifie apres coup ;
// en cas d'ecart, la carte n'est pas sauvegardee.
//
// Usage :
// UnrealEditor-Cmd.exe <projet> -run=LPFixSceneCapture -Map=/Game/Scenes/CentralLondon -Actor=SecondScreen
// -From=CameraPortrait -Offset=0,-10000000,0 [-DryRun]
#pragma once
#include "CoreMinimal.h"
#include "Commandlets/Commandlet.h"
#include "LPFixSceneCaptureCommandlet.generated.h"
UCLASS()
class ULPFixSceneCaptureCommandlet : public UCommandlet
{
GENERATED_BODY()
public:
ULPFixSceneCaptureCommandlet();
virtual int32 Main(const FString& Params) override;
};