From 8abf1d4ad81c5f980e5fc62d2d2f98f10cda9be3 Mon Sep 17 00:00:00 2001 From: edujiro5972 <336072401+edujiro5972@users.noreply.github.com> Date: Fri, 2 Oct 2026 08:26:53 +0200 Subject: [PATCH] O9 : collision retiree des arbres et voitures decoratifs de la carte (MapMarkers Tree/Car), commandlet LPSetComponentCollision Co-Authored-By: Claude Opus 5.5 --- Content/BPs/MapMarkers.uasset | Bin 722476 -> 723520 bytes Docs/Migration/Journal_Modifications.md | 1 + .../LPSetComponentCollisionCommandlet.cpp | 121 ++++++++++++++++++ .../LPSetComponentCollisionCommandlet.h | 31 +++++ 4 files changed, 153 insertions(+) create mode 100644 Source/LifePlayEditorTools/LPSetComponentCollisionCommandlet.cpp create mode 100644 Source/LifePlayEditorTools/LPSetComponentCollisionCommandlet.h diff --git a/Content/BPs/MapMarkers.uasset b/Content/BPs/MapMarkers.uasset index 97a7bc18a6eb1c1f3a2b3f897334b38d161e0b5c..806a81774d3ce08ed8d8d8012aa7333eeb8037a8 100644 GIT binary patch delta 4791 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 diff --git a/Docs/Migration/Journal_Modifications.md b/Docs/Migration/Journal_Modifications.md index ecc1bb5..eea5f53 100644 --- a/Docs/Migration/Journal_Modifications.md +++ b/Docs/Migration/Journal_Modifications.md @@ -906,3 +906,4 @@ Validation L7c/L7d (2026-10-02, parc, même cadrage) : la nuit reste claire (sol | CHG-059 | 2026-10-02 | O0 | nouveaux `Tools/AuditAssets.py`, `Docs/Migration/11_Audit_Optimisation.md` ; lanceur `LifePlay_profil_O0.bat` (build L7cdj, hors dépôt) | audit d'optimisation en lecture seule : inventaire des assets, build livré, leviers et lots proposés ; aucune modification du projet | `git revert` du commit | | CHG-060 | 2026-10-02 | O0 | `Docs/Migration/11_Audit_Optimisation.md` §9-10 ; lanceur `LifePlay_profil_O0.bat` corrigé (capture par `-ExecCmds`) | résultats de la mesure en jeu (60 images/s tenues, à-coups du thread de jeu dus aux minuteries Blueprint, 463 Mo de physique) ; produits utiles de la bibliothèque Fab ; lots révisés | `git revert` du commit | | CHG-061 | 2026-10-02 | O1 | `LifePlay.uproject` (20 plugins limités à l'éditeur), `Config/DefaultGame.ini` (16 `DirectoriesToNeverCook`), nouveau `Tools/AuditScriptDeps.py` ; `README.md` : lien Mega de la V1.1 | build Shipping allégé de 387 Mo sans changement de contenu ; build `LifePlay_Build_5.5_O1` | `Tools\Restore.ps1 -Lot O1` ou `git checkout O1-avant -- LifePlay.uproject Config` | +| CHG-062 | 2026-10-02 | O9 | nouvelle commandlet `LPSetComponentCollision` ; `Content/BPs/MapMarkers.uasset` : composants `Tree` et `Car` en `NoCollision` (diff avant/après : 2 lignes) | chargement de partie de 71 s (identique en 4.27) dû aux ≈ 160 000 corps physiques des arbres et voitures décoratifs de la carte (décision utilisateur : option 1) ; build `LifePlay_Build_5.5_O9` | `Tools\Restore.ps1 -Lot O9` | diff --git a/Source/LifePlayEditorTools/LPSetComponentCollisionCommandlet.cpp b/Source/LifePlayEditorTools/LPSetComponentCollisionCommandlet.cpp new file mode 100644 index 0000000..55fc53f --- /dev/null +++ b/Source/LifePlayEditorTools/LPSetComponentCollisionCommandlet.cpp @@ -0,0 +1,121 @@ +// Portage UE 5.5 - voir LPSetComponentCollisionCommandlet.h + +#include "LPSetComponentCollisionCommandlet.h" + +#include "Components/PrimitiveComponent.h" +#include "Engine/Blueprint.h" +#include "Engine/SCS_Node.h" +#include "Engine/SimpleConstructionScript.h" +#include "Kismet2/KismetEditorUtilities.h" +#include "Misc/PackageName.h" +#include "UObject/Package.h" +#include "UObject/SavePackage.h" + +DEFINE_LOG_CATEGORY_STATIC(LogLPSetCollision, Log, All); + +ULPSetComponentCollisionCommandlet::ULPSetComponentCollisionCommandlet() +{ + IsClient = false; + IsServer = false; + IsEditor = true; + LogToConsole = true; +} + +int32 ULPSetComponentCollisionCommandlet::Main(const FString& Params) +{ + TArray Tokens, Switches; + TMap ParamsMap; + ParseCommandLine(*Params, Tokens, Switches, ParamsMap); + const bool bDryRun = Switches.Contains(TEXT("DryRun")); + const FString BPPath = ParamsMap.FindRef(TEXT("BP")); + FString Profile = ParamsMap.FindRef(TEXT("Profile")); + if (Profile.IsEmpty()) + { + Profile = TEXT("NoCollision"); + } + TArray Names; + ParamsMap.FindRef(TEXT("Components")).ParseIntoArray(Names, TEXT(","), true); + if (BPPath.IsEmpty() || Names.Num() == 0) + { + UE_LOG(LogLPSetCollision, Error, TEXT("Usage : -BP=/Game/BPs/X -Components=A,B [-Profile=NoCollision] [-DryRun]")); + return 1; + } + + const FString ObjectPath = BPPath + TEXT(".") + FPackageName::GetShortName(BPPath); + UBlueprint* Blueprint = LoadObject(nullptr, *ObjectPath); + if (!Blueprint || !Blueprint->SimpleConstructionScript) + { + UE_LOG(LogLPSetCollision, Error, TEXT("Blueprint introuvable ou sans SimpleConstructionScript : %s"), *ObjectPath); + return 1; + } + + UE_LOG(LogLPSetCollision, Warning, TEXT("=== %s : composants [%s] -> profil %s%s ==="), + *BPPath, *FString::Join(Names, TEXT(",")), *Profile, bDryRun ? TEXT(" [DRY RUN]") : TEXT("")); + + TArray Targets; + int32 Errors = 0; + for (const FString& Name : Names) + { + USCS_Node* Node = Blueprint->SimpleConstructionScript->FindSCSNode(FName(*Name)); + UPrimitiveComponent* Template = Node ? Cast(Node->ComponentTemplate) : nullptr; + if (!Template) + { + ++Errors; + UE_LOG(LogLPSetCollision, Error, TEXT(" %s : composant primitif introuvable"), *Name); + continue; + } + UE_LOG(LogLPSetCollision, Warning, TEXT(" %s [%s] : profil actuel %s, collision %d"), + *Name, *Template->GetClass()->GetName(), *Template->GetCollisionProfileName().ToString(), (int32)Template->GetCollisionEnabled()); + Targets.Add(Template); + } + if (Errors > 0 || bDryRun) + { + return Errors > 0 ? 1 : 0; + } + + for (UPrimitiveComponent* Template : Targets) + { + Template->Modify(); + Template->SetCollisionProfileName(FName(*Profile)); + } + FKismetEditorUtilities::CompileBlueprint(Blueprint); + + // Verification apres compilation : relecture des modeles et des composants generes de la classe. + for (const FString& Name : Names) + { + const USCS_Node* Node = Blueprint->SimpleConstructionScript->FindSCSNode(FName(*Name)); + const UPrimitiveComponent* Template = Node ? Cast(Node->ComponentTemplate) : nullptr; + if (!Template || Template->GetCollisionProfileName() != FName(*Profile) + || (Profile == TEXT("NoCollision") && Template->GetCollisionEnabled() != ECollisionEnabled::NoCollision)) + { + ++Errors; + UE_LOG(LogLPSetCollision, Error, TEXT(" %s : profil non applique"), *Name); + continue; + } + UE_LOG(LogLPSetCollision, Warning, TEXT(" %s : profil %s, collision %d"), *Name, + *Template->GetCollisionProfileName().ToString(), (int32)Template->GetCollisionEnabled()); + } + if (Blueprint->Status == BS_Error) + { + ++Errors; + UE_LOG(LogLPSetCollision, Error, TEXT(" compilation en erreur")); + } + if (Errors > 0) + { + UE_LOG(LogLPSetCollision, Error, TEXT(" %d ecart(s) : Blueprint NON sauvegarde"), Errors); + return 1; + } + + UPackage* Package = Blueprint->GetOutermost(); + const FString Filename = FPackageName::LongPackageNameToFilename(Package->GetName(), FPackageName::GetAssetPackageExtension()); + FSavePackageArgs SaveArgs; + SaveArgs.TopLevelFlags = RF_Public | RF_Standalone; + SaveArgs.Error = GWarn; + if (!UPackage::SavePackage(Package, nullptr, *Filename, SaveArgs)) + { + UE_LOG(LogLPSetCollision, Error, TEXT(" ECHEC de sauvegarde")); + return 1; + } + UE_LOG(LogLPSetCollision, Warning, TEXT(" -> %s sauvegarde"), *Filename); + return 0; +} diff --git a/Source/LifePlayEditorTools/LPSetComponentCollisionCommandlet.h b/Source/LifePlayEditorTools/LPSetComponentCollisionCommandlet.h new file mode 100644 index 0000000..498daac --- /dev/null +++ b/Source/LifePlayEditorTools/LPSetComponentCollisionCommandlet.h @@ -0,0 +1,31 @@ +// Portage UE 5.5 - lot O9 (optimisation ; defaut deja present en 4.27). +// +// Le chargement d'une partie prend ~70 s (4.27 comme 5.5). La trace Unreal Insights montre que 60 s +// vont a la carte de la ville : MapMarkers.GenerateTrees ajoute ~160 000 instances aux composants +// HierarchicalInstancedStaticMesh "Tree" et "Car", qui gardent la collision par defaut (BlockAll) : +// chaque instance recoit un corps physique Chaos (HISMC_AddInstance 55 s, AddActorsToScene x161 000, +// et ~460 Mo de physique en memoire). Ces arbres et voitures sont decoratifs (decision utilisateur). +// +// Cette commandlet change le profil de collision des composants nommes d'un Blueprint (noeuds de la +// SimpleConstructionScript), recompile et sauvegarde. Controle : le profil et l'etat de collision +// sont relus apres modification ; tout ecart, ou composant introuvable : rien n'est sauvegarde. +// +// Usage : +// UnrealEditor-Cmd.exe -run=LPSetComponentCollision -BP=/Game/BPs/MapMarkers -Components=Tree,Car +// [-Profile=NoCollision] [-DryRun] + +#pragma once + +#include "CoreMinimal.h" +#include "Commandlets/Commandlet.h" +#include "LPSetComponentCollisionCommandlet.generated.h" + +UCLASS() +class ULPSetComponentCollisionCommandlet : public UCommandlet +{ + GENERATED_BODY() + +public: + ULPSetComponentCollisionCommandlet(); + virtual int32 Main(const FString& Params) override; +};