1941 lines
70 KiB
Diff
1941 lines
70 KiB
Diff
|
|
diff --git a/D:/Game/LifePlay-master 4.27/Source/LifePlayEditorTools/LPCheckMeshAssignmentCommandlet.cpp b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPCheckMeshAssignmentCommandlet.cpp
|
||
|
|
index 61d6490..7f6e486 100644
|
||
|
|
--- a/D:/Game/LifePlay-master 4.27/Source/LifePlayEditorTools/LPCheckMeshAssignmentCommandlet.cpp
|
||
|
|
+++ b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPCheckMeshAssignmentCommandlet.cpp
|
||
|
|
@@ -67,7 +67,7 @@ int32 ULPCheckMeshAssignmentCommandlet::Main(const FString& Params)
|
||
|
|
AssetRegistryModule.Get().SearchAllAssets(true);
|
||
|
|
|
||
|
|
TArray<FAssetData> BlueprintAssets;
|
||
|
|
- AssetRegistryModule.Get().GetAssetsByClass(UBlueprint::StaticClass()->GetFName(), BlueprintAssets, true);
|
||
|
|
+ AssetRegistryModule.Get().GetAssetsByClass(UBlueprint::StaticClass()->GetClassPathName(), BlueprintAssets, true);
|
||
|
|
|
||
|
|
int32 Total = 0;
|
||
|
|
int32 Disconnected = 0;
|
||
|
|
@@ -108,22 +108,40 @@ int32 ULPCheckMeshAssignmentCommandlet::Main(const FString& Params)
|
||
|
|
Callee = FString::Printf(TEXT(" [%s]"), *Fn->FunctionReference.GetMemberName().ToString());
|
||
|
|
}
|
||
|
|
|
||
|
|
+ // Un noeud ne nous interesse que s'il porte au moins une broche orpheline.
|
||
|
|
+ bool bHasOrphan = false;
|
||
|
|
+ for (const UEdGraphPin* Pin : GraphNode->Pins)
|
||
|
|
+ {
|
||
|
|
+ if (Pin && Pin->bOrphanedPin) { bHasOrphan = true; break; }
|
||
|
|
+ }
|
||
|
|
+ if (!bHasOrphan)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ UE_LOG(LogLPCheckMesh, Warning, TEXT(" %s :: %s -> %s%s"),
|
||
|
|
+ *Blueprint->GetName(), *Graph->GetName(), *GraphNode->GetName(), *Callee);
|
||
|
|
+
|
||
|
|
+ // On dumpe TOUTES les broches : l'orpheline porte l'ancienne valeur, et la
|
||
|
|
+ // broche de remplacement dit si la migration l'a reprise ou laissee vide.
|
||
|
|
for (UEdGraphPin* Pin : GraphNode->Pins)
|
||
|
|
{
|
||
|
|
- if (!Pin || !Pin->bOrphanedPin)
|
||
|
|
+ if (!Pin || Pin->PinType.PinCategory == UEdGraphSchema_K2::PC_Exec)
|
||
|
|
{
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
- ++Total;
|
||
|
|
- if (Pin->LinkedTo.Num() > 0)
|
||
|
|
+ const bool bOrphan = Pin->bOrphanedPin;
|
||
|
|
+ if (bOrphan)
|
||
|
|
{
|
||
|
|
- ++Disconnected;
|
||
|
|
+ ++Total;
|
||
|
|
+ if (Pin->LinkedTo.Num() > 0) { ++Disconnected; }
|
||
|
|
}
|
||
|
|
|
||
|
|
- UE_LOG(LogLPCheckMesh, Warning, TEXT(" %s :: %s -> %s%s | broche '%s' %s"),
|
||
|
|
- *Blueprint->GetName(), *Graph->GetName(), *GraphNode->GetName(), *Callee,
|
||
|
|
- *Pin->PinName.ToString(), *DescribePin(Pin));
|
||
|
|
+ UE_LOG(LogLPCheckMesh, Warning, TEXT(" %-22s %-3s %s"),
|
||
|
|
+ *Pin->PinName.ToString(),
|
||
|
|
+ bOrphan ? TEXT("[X]") : TEXT(" "),
|
||
|
|
+ *DescribePin(Pin));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
diff --git a/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPCheckStreetMapCommandlet.cpp b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPCheckStreetMapCommandlet.cpp
|
||
|
|
new file mode 100644
|
||
|
|
index 0000000..32fc3d5
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPCheckStreetMapCommandlet.cpp
|
||
|
|
@@ -0,0 +1,186 @@
|
||
|
|
+// Portage UE 5.5 - voir LPCheckStreetMapCommandlet.h
|
||
|
|
+
|
||
|
|
+#include "LPCheckStreetMapCommandlet.h"
|
||
|
|
+
|
||
|
|
+#include "AssetRegistry/AssetRegistryModule.h"
|
||
|
|
+#include "HAL/FileManager.h"
|
||
|
|
+#include "Misc/FileHelper.h"
|
||
|
|
+#include "Misc/Paths.h"
|
||
|
|
+#include "StreetMap.h"
|
||
|
|
+#include "UObject/UObjectGlobals.h"
|
||
|
|
+
|
||
|
|
+DEFINE_LOG_CATEGORY_STATIC(LogLPCheckStreetMap, Log, All);
|
||
|
|
+
|
||
|
|
+namespace
|
||
|
|
+{
|
||
|
|
+ /** Ce qu'on a trouve dans une ville. */
|
||
|
|
+ struct FCityReport
|
||
|
|
+ {
|
||
|
|
+ FString Name;
|
||
|
|
+ int32 Roads = 0;
|
||
|
|
+ int32 Nodes = 0;
|
||
|
|
+ int32 Buildings = 0;
|
||
|
|
+ int32 Waters = 0;
|
||
|
|
+ int32 Parks = 0;
|
||
|
|
+ int32 NamedBuildings = 0; // batiments avec un nom non vide
|
||
|
|
+ int32 WithAmenity = 0; // batiments avec un Amenity non vide
|
||
|
|
+ int32 DistinctAmenities = 0;
|
||
|
|
+ bool bLoaded = false;
|
||
|
|
+ };
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+ULPCheckStreetMapCommandlet::ULPCheckStreetMapCommandlet()
|
||
|
|
+{
|
||
|
|
+ IsClient = false;
|
||
|
|
+ IsServer = false;
|
||
|
|
+ IsEditor = true;
|
||
|
|
+ LogToConsole = true;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+int32 ULPCheckStreetMapCommandlet::Main(const FString& Params)
|
||
|
|
+{
|
||
|
|
+ TArray<FString> Tokens;
|
||
|
|
+ TArray<FString> Switches;
|
||
|
|
+ TMap<FString, FString> ParamsMap;
|
||
|
|
+ ParseCommandLine(*Params, Tokens, Switches, ParamsMap);
|
||
|
|
+
|
||
|
|
+ const bool bVerbose = Switches.Contains(TEXT("Verbose"));
|
||
|
|
+ const bool bDumpAmenities = Switches.Contains(TEXT("DumpAmenities"));
|
||
|
|
+ const FString CsvPath = ParamsMap.FindRef(TEXT("CSV"));
|
||
|
|
+
|
||
|
|
+ UE_LOG(LogLPCheckStreetMap, Warning, TEXT("=== Verification des assets UStreetMap ==="));
|
||
|
|
+
|
||
|
|
+ FAssetRegistryModule& AssetRegistryModule =
|
||
|
|
+ FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
|
||
|
|
+ AssetRegistryModule.Get().SearchAllAssets(true);
|
||
|
|
+
|
||
|
|
+ TArray<FAssetData> Assets;
|
||
|
|
+ AssetRegistryModule.Get().GetAssetsByClass(UStreetMap::StaticClass()->GetClassPathName(), Assets, true);
|
||
|
|
+
|
||
|
|
+ // Ordre stable : indispensable pour diffing entre deux executions.
|
||
|
|
+ Assets.Sort([](const FAssetData& A, const FAssetData& B)
|
||
|
|
+ {
|
||
|
|
+ return A.AssetName.LexicalLess(B.AssetName);
|
||
|
|
+ });
|
||
|
|
+
|
||
|
|
+ UE_LOG(LogLPCheckStreetMap, Warning, TEXT("%d asset(s) UStreetMap trouve(s)."), Assets.Num());
|
||
|
|
+
|
||
|
|
+ TArray<FCityReport> Reports;
|
||
|
|
+ Reports.Reserve(Assets.Num());
|
||
|
|
+
|
||
|
|
+ int32 LoadFailures = 0;
|
||
|
|
+ int32 EmptyCities = 0;
|
||
|
|
+
|
||
|
|
+ for (const FAssetData& AssetData : Assets)
|
||
|
|
+ {
|
||
|
|
+ FCityReport Report;
|
||
|
|
+ Report.Name = AssetData.AssetName.ToString();
|
||
|
|
+
|
||
|
|
+ UStreetMap* StreetMap = Cast<UStreetMap>(AssetData.GetAsset());
|
||
|
|
+ if (StreetMap == nullptr)
|
||
|
|
+ {
|
||
|
|
+ ++LoadFailures;
|
||
|
|
+ UE_LOG(LogLPCheckStreetMap, Error, TEXT(" ECHEC de chargement : %s"), *Report.Name);
|
||
|
|
+ Reports.Add(Report);
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ Report.bLoaded = true;
|
||
|
|
+ Report.Roads = StreetMap->GetRoads().Num();
|
||
|
|
+ Report.Nodes = StreetMap->GetNodes().Num();
|
||
|
|
+ Report.Buildings = StreetMap->GetBuildings().Num();
|
||
|
|
+ Report.Waters = StreetMap->GetWaters().Num();
|
||
|
|
+ Report.Parks = StreetMap->GetParks().Num();
|
||
|
|
+
|
||
|
|
+ // Amenity est le mecanisme par lequel le jeu identifie bars, salles de sport et
|
||
|
|
+ // commerces : c'est la donnee dont la perte serait la plus grave.
|
||
|
|
+ TSet<FString> Amenities;
|
||
|
|
+ for (const FStreetMapBuilding& Building : StreetMap->GetBuildings())
|
||
|
|
+ {
|
||
|
|
+ if (!Building.BuildingName.IsEmpty())
|
||
|
|
+ {
|
||
|
|
+ ++Report.NamedBuildings;
|
||
|
|
+ }
|
||
|
|
+ if (!Building.Amenity.IsEmpty())
|
||
|
|
+ {
|
||
|
|
+ ++Report.WithAmenity;
|
||
|
|
+ Amenities.Add(Building.Amenity);
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ Report.DistinctAmenities = Amenities.Num();
|
||
|
|
+
|
||
|
|
+ // Les comptes seuls ne prouvent pas que la donnee est la bonne : on releve les
|
||
|
|
+ // valeurs pour pouvoir les croiser avec les types de lieux du jeu (*.lpworld).
|
||
|
|
+ if (bDumpAmenities && Amenities.Num() > 0)
|
||
|
|
+ {
|
||
|
|
+ TArray<FString> Sorted = Amenities.Array();
|
||
|
|
+ Sorted.Sort();
|
||
|
|
+ UE_LOG(LogLPCheckStreetMap, Warning, TEXT(" --- amenities de %s (%d) : %s"),
|
||
|
|
+ *Report.Name, Sorted.Num(), *FString::Join(Sorted, TEXT(", ")));
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (Report.Roads == 0 && Report.Buildings == 0)
|
||
|
|
+ {
|
||
|
|
+ ++EmptyCities;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (bVerbose)
|
||
|
|
+ {
|
||
|
|
+ UE_LOG(LogLPCheckStreetMap, Warning,
|
||
|
|
+ TEXT(" %-24s routes=%-7d noeuds=%-7d batiments=%-7d eaux=%-4d parcs=%-4d nommes=%-6d amenity=%-6d (%d types)"),
|
||
|
|
+ *Report.Name, Report.Roads, Report.Nodes, Report.Buildings,
|
||
|
|
+ Report.Waters, Report.Parks, Report.NamedBuildings,
|
||
|
|
+ Report.WithAmenity, Report.DistinctAmenities);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ Reports.Add(Report);
|
||
|
|
+
|
||
|
|
+ // Sans cela, charger les 280 villes fait exploser la memoire (CentralLondon pese
|
||
|
|
+ // 33 Mo de donnees a lui seul).
|
||
|
|
+ CollectGarbage(RF_NoFlags);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ // --- Synthese
|
||
|
|
+ int64 TotalRoads = 0, TotalBuildings = 0, TotalWaters = 0, TotalParks = 0, TotalAmenity = 0;
|
||
|
|
+ for (const FCityReport& R : Reports)
|
||
|
|
+ {
|
||
|
|
+ TotalRoads += R.Roads;
|
||
|
|
+ TotalBuildings += R.Buildings;
|
||
|
|
+ TotalWaters += R.Waters;
|
||
|
|
+ TotalParks += R.Parks;
|
||
|
|
+ TotalAmenity += R.WithAmenity;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ UE_LOG(LogLPCheckStreetMap, Warning, TEXT("=== Synthese ==="));
|
||
|
|
+ UE_LOG(LogLPCheckStreetMap, Warning, TEXT(" villes chargees : %d / %d"), Assets.Num() - LoadFailures, Assets.Num());
|
||
|
|
+ UE_LOG(LogLPCheckStreetMap, Warning, TEXT(" echecs de chargement : %d"), LoadFailures);
|
||
|
|
+ UE_LOG(LogLPCheckStreetMap, Warning, TEXT(" villes sans donnees : %d"), EmptyCities);
|
||
|
|
+ UE_LOG(LogLPCheckStreetMap, Warning, TEXT(" routes : %lld"), TotalRoads);
|
||
|
|
+ UE_LOG(LogLPCheckStreetMap, Warning, TEXT(" batiments : %lld"), TotalBuildings);
|
||
|
|
+ UE_LOG(LogLPCheckStreetMap, Warning, TEXT(" batiments avec amenity : %lld"), TotalAmenity);
|
||
|
|
+ UE_LOG(LogLPCheckStreetMap, Warning, TEXT(" plans d'eau : %lld"), TotalWaters);
|
||
|
|
+ UE_LOG(LogLPCheckStreetMap, Warning, TEXT(" parcs : %lld"), TotalParks);
|
||
|
|
+
|
||
|
|
+ if (!CsvPath.IsEmpty())
|
||
|
|
+ {
|
||
|
|
+ FString Csv = TEXT("Ville;Charge;Routes;Noeuds;Batiments;Eaux;Parcs;BatimentsNommes;AvecAmenity;TypesAmenity\n");
|
||
|
|
+ for (const FCityReport& R : Reports)
|
||
|
|
+ {
|
||
|
|
+ Csv += FString::Printf(TEXT("%s;%d;%d;%d;%d;%d;%d;%d;%d;%d\n"),
|
||
|
|
+ *R.Name, R.bLoaded ? 1 : 0, R.Roads, R.Nodes, R.Buildings,
|
||
|
|
+ R.Waters, R.Parks, R.NamedBuildings, R.WithAmenity, R.DistinctAmenities);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (FFileHelper::SaveStringToFile(Csv, *CsvPath))
|
||
|
|
+ {
|
||
|
|
+ UE_LOG(LogLPCheckStreetMap, Warning, TEXT(" CSV ecrit : %s"), *CsvPath);
|
||
|
|
+ }
|
||
|
|
+ else
|
||
|
|
+ {
|
||
|
|
+ UE_LOG(LogLPCheckStreetMap, Error, TEXT(" ECHEC d'ecriture du CSV : %s"), *CsvPath);
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ // Code de retour non nul si une ville n'a pas pu etre chargee : exploitable en CI.
|
||
|
|
+ return LoadFailures > 0 ? 1 : 0;
|
||
|
|
+}
|
||
|
|
diff --git a/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPCheckStreetMapCommandlet.h b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPCheckStreetMapCommandlet.h
|
||
|
|
new file mode 100644
|
||
|
|
index 0000000..2d54589
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPCheckStreetMapCommandlet.h
|
||
|
|
@@ -0,0 +1,27 @@
|
||
|
|
+// Portage UE 5.5 - verification du chargement des assets ville apres migration.
|
||
|
|
+//
|
||
|
|
+// Charge chaque UStreetMap du projet et compte ce qu'il contient reellement : routes,
|
||
|
|
+// noeuds, batiments, plans d'eau, parcs, et amenities non vides. Le but est de prouver
|
||
|
|
+// que la fusion du plugin StreetMap n'a rien perdu, sans avoir a ouvrir l'editeur et
|
||
|
|
+// inspecter 280 villes a la main.
|
||
|
|
+//
|
||
|
|
+// Sortie CSV optionnelle, pour comparer une execution 4.27 et une execution 5.5.
|
||
|
|
+//
|
||
|
|
+// UnrealEditor-Cmd.exe <projet> -run=LPCheckStreetMap [-CSV=chemin.csv] [-Verbose]
|
||
|
|
+
|
||
|
|
+#pragma once
|
||
|
|
+
|
||
|
|
+#include "CoreMinimal.h"
|
||
|
|
+#include "Commandlets/Commandlet.h"
|
||
|
|
+#include "LPCheckStreetMapCommandlet.generated.h"
|
||
|
|
+
|
||
|
|
+UCLASS()
|
||
|
|
+class ULPCheckStreetMapCommandlet : public UCommandlet
|
||
|
|
+{
|
||
|
|
+ GENERATED_BODY()
|
||
|
|
+
|
||
|
|
+public:
|
||
|
|
+ ULPCheckStreetMapCommandlet();
|
||
|
|
+
|
||
|
|
+ virtual int32 Main(const FString& Params) override;
|
||
|
|
+};
|
||
|
|
diff --git a/D:/Game/LifePlay-master 4.27/Source/LifePlayEditorTools/LPFixAssetRegistryNodesCommandlet.cpp b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixAssetRegistryNodesCommandlet.cpp
|
||
|
|
index da20732..fb40e85 100644
|
||
|
|
--- a/D:/Game/LifePlay-master 4.27/Source/LifePlayEditorTools/LPFixAssetRegistryNodesCommandlet.cpp
|
||
|
|
+++ b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixAssetRegistryNodesCommandlet.cpp
|
||
|
|
@@ -14,6 +14,7 @@
|
||
|
|
#include "Misc/FeedbackContext.h"
|
||
|
|
#include "Misc/PackageName.h"
|
||
|
|
#include "UObject/Package.h"
|
||
|
|
+#include "UObject/SavePackage.h"
|
||
|
|
#include "UObject/UObjectGlobals.h"
|
||
|
|
|
||
|
|
DEFINE_LOG_CATEGORY_STATIC(LogLPFixNodes, Log, All);
|
||
|
|
@@ -80,7 +81,8 @@ int32 ULPFixAssetRegistryNodesCommandlet::Main(const FString& Params)
|
||
|
|
AssetRegistryModule.Get().SearchAllAssets(true);
|
||
|
|
|
||
|
|
TArray<FAssetData> BlueprintAssets;
|
||
|
|
- AssetRegistryModule.Get().GetAssetsByClass(UBlueprint::StaticClass()->GetFName(), BlueprintAssets, true);
|
||
|
|
+ // 5.1+ : GetAssetsByClass prend un FTopLevelAssetPath, plus un FName de classe.
|
||
|
|
+ AssetRegistryModule.Get().GetAssetsByClass(UBlueprint::StaticClass()->GetClassPathName(), BlueprintAssets, true);
|
||
|
|
|
||
|
|
UE_LOG(LogLPFixNodes, Warning, TEXT("%d Blueprints a inspecter."), BlueprintAssets.Num());
|
||
|
|
|
||
|
|
@@ -190,8 +192,16 @@ int32 ULPFixAssetRegistryNodesCommandlet::Main(const FString& Params)
|
||
|
|
|
||
|
|
UE_LOG(LogLPFixNodes, Warning, TEXT(" -> sauvegarde vers %s"), *Filename);
|
||
|
|
|
||
|
|
+ // 5.x : les arguments passent par FSavePackageArgs (Conform n'est plus implemente).
|
||
|
|
+ FSavePackageArgs SaveArgs;
|
||
|
|
+ SaveArgs.TopLevelFlags = RF_Public | RF_Standalone;
|
||
|
|
+ SaveArgs.SaveFlags = SAVE_None;
|
||
|
|
+ SaveArgs.bForceByteSwapping = false;
|
||
|
|
+ SaveArgs.bWarnOfLongFilename = true;
|
||
|
|
// GWarn et non GError : en commandlet, GError rend toute erreur de sauvegarde fatale.
|
||
|
|
- if (UPackage::SavePackage(Package, nullptr, RF_Public | RF_Standalone, *Filename, GWarn, nullptr, false, true, SAVE_None))
|
||
|
|
+ SaveArgs.Error = GWarn;
|
||
|
|
+
|
||
|
|
+ if (UPackage::SavePackage(Package, nullptr, *Filename, SaveArgs))
|
||
|
|
{
|
||
|
|
UE_LOG(LogLPFixNodes, Warning, TEXT(" -> %s sauvegarde (%d noeud(s))."), *Package->GetName(), NodesFixedHere);
|
||
|
|
}
|
||
|
|
diff --git a/D:/Game/LifePlay-master 4.27/Source/LifePlayEditorTools/LPFixAssetRegistryNodesCommandlet.h b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixAssetRegistryNodesCommandlet.h
|
||
|
|
index 781d3a6..427776f 100644
|
||
|
|
--- a/D:/Game/LifePlay-master 4.27/Source/LifePlayEditorTools/LPFixAssetRegistryNodesCommandlet.h
|
||
|
|
+++ b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixAssetRegistryNodesCommandlet.h
|
||
|
|
@@ -1,11 +1,11 @@
|
||
|
|
-// Portage UE 4.27 (2026.9 beta)
|
||
|
|
+// Portage UE 5.5 (2026.9 beta) - correctif introduit lors du portage 4.27, toujours actif.
|
||
|
|
//
|
||
|
|
// Commandlet de correction ponctuelle : remplace les noeuds Blueprint appelant
|
||
|
|
// IAssetRegistry::GetAssetByObjectPath (devenu impur cote Epic) par la version pure
|
||
|
|
// ULPAssetRegistryHelpers::GetAssetByObjectPath, puis resauvegarde les Blueprints.
|
||
|
|
//
|
||
|
|
// Usage :
|
||
|
|
-// UE4Editor-Cmd.exe <chemin>\LifePlay.uproject -run=LPFixAssetRegistryNodes [-DryRun]
|
||
|
|
+// UnrealEditor-Cmd.exe <chemin>\LifePlay.uproject -run=LPFixAssetRegistryNodes [-DryRun]
|
||
|
|
|
||
|
|
#pragma once
|
||
|
|
|
||
|
|
diff --git a/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixAssetRegistryPinsCommandlet.cpp b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixAssetRegistryPinsCommandlet.cpp
|
||
|
|
new file mode 100644
|
||
|
|
index 0000000..7aa6146
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixAssetRegistryPinsCommandlet.cpp
|
||
|
|
@@ -0,0 +1,319 @@
|
||
|
|
+// Portage UE 5.5 - voir LPFixAssetRegistryPinsCommandlet.h
|
||
|
|
+
|
||
|
|
+#include "LPFixAssetRegistryPinsCommandlet.h"
|
||
|
|
+
|
||
|
|
+#include "AssetRegistry/AssetData.h"
|
||
|
|
+#include "AssetRegistry/AssetRegistryModule.h"
|
||
|
|
+#include "EdGraph/EdGraph.h"
|
||
|
|
+#include "EdGraph/EdGraphPin.h"
|
||
|
|
+#include "EdGraphSchema_K2.h"
|
||
|
|
+#include "Engine/Blueprint.h"
|
||
|
|
+#include "K2Node_BreakStruct.h"
|
||
|
|
+#include "K2Node_CallFunction.h"
|
||
|
|
+#include "Kismet2/BlueprintEditorUtils.h"
|
||
|
|
+#include "Kismet2/KismetEditorUtilities.h"
|
||
|
|
+#include "LPAssetRegistryHelpers.h"
|
||
|
|
+#include "Misc/PackageName.h"
|
||
|
|
+#include "UObject/Package.h"
|
||
|
|
+#include "UObject/SavePackage.h"
|
||
|
|
+#include "UObject/UObjectGlobals.h"
|
||
|
|
+
|
||
|
|
+DEFINE_LOG_CATEGORY_STATIC(LogLPFixARPins, Log, All);
|
||
|
|
+
|
||
|
|
+namespace
|
||
|
|
+{
|
||
|
|
+ const FName DeprecatedClassNamePin(TEXT("ClassName"));
|
||
|
|
+ const FName DeprecatedObjectPathPin(TEXT("ObjectPath"));
|
||
|
|
+ const FName AssetDataPin(TEXT("AssetData"));
|
||
|
|
+ const FName AssetDataStructName(TEXT("AssetData"));
|
||
|
|
+
|
||
|
|
+ const FName GetAssetsByClassFunction(TEXT("GetAssetsByClass"));
|
||
|
|
+ const FName ReplacementEnumFunction(TEXT("GetAssetsByClassName"));
|
||
|
|
+ const FName ReplacementPathFunction(TEXT("GetAssetObjectPath"));
|
||
|
|
+
|
||
|
|
+ /** Broche orpheline portant ce nom, s'il y en a une. */
|
||
|
|
+ UEdGraphPin* FindOrphan(UEdGraphNode* Node, FName PinName)
|
||
|
|
+ {
|
||
|
|
+ for (UEdGraphPin* Pin : Node->Pins)
|
||
|
|
+ {
|
||
|
|
+ if (Pin && Pin->bOrphanedPin && Pin->PinName == PinName)
|
||
|
|
+ {
|
||
|
|
+ return Pin;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ return nullptr;
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+ULPFixAssetRegistryPinsCommandlet::ULPFixAssetRegistryPinsCommandlet()
|
||
|
|
+{
|
||
|
|
+ IsClient = false;
|
||
|
|
+ IsServer = false;
|
||
|
|
+ IsEditor = true;
|
||
|
|
+ LogToConsole = true;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+int32 ULPFixAssetRegistryPinsCommandlet::Main(const FString& Params)
|
||
|
|
+{
|
||
|
|
+ const bool bDryRun = Params.Contains(TEXT("DryRun"), ESearchCase::IgnoreCase);
|
||
|
|
+
|
||
|
|
+ UFunction* EnumFunction = ULPAssetRegistryHelpers::StaticClass()->FindFunctionByName(ReplacementEnumFunction);
|
||
|
|
+ UFunction* PathFunction = ULPAssetRegistryHelpers::StaticClass()->FindFunctionByName(ReplacementPathFunction);
|
||
|
|
+ if (!EnumFunction || !PathFunction)
|
||
|
|
+ {
|
||
|
|
+ UE_LOG(LogLPFixARPins, Error, TEXT("Fonctions de remplacement introuvables (%s=%s, %s=%s)."),
|
||
|
|
+ *ReplacementEnumFunction.ToString(), EnumFunction ? TEXT("ok") : TEXT("NULL"),
|
||
|
|
+ *ReplacementPathFunction.ToString(), PathFunction ? TEXT("ok") : TEXT("NULL"));
|
||
|
|
+ return 1;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ UE_LOG(LogLPFixARPins, Warning, TEXT("=== Broches AssetRegistry perdues a la migration 5.1%s ==="),
|
||
|
|
+ bDryRun ? TEXT(" [DRY RUN]") : TEXT(""));
|
||
|
|
+
|
||
|
|
+ FAssetRegistryModule& AssetRegistryModule =
|
||
|
|
+ FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
|
||
|
|
+ AssetRegistryModule.Get().SearchAllAssets(true);
|
||
|
|
+
|
||
|
|
+ TArray<FAssetData> BlueprintAssets;
|
||
|
|
+ AssetRegistryModule.Get().GetAssetsByClass(UBlueprint::StaticClass()->GetClassPathName(), BlueprintAssets, true);
|
||
|
|
+
|
||
|
|
+ int32 EnumFixed = 0;
|
||
|
|
+ int32 PathFixed = 0;
|
||
|
|
+ int32 Unhandled = 0;
|
||
|
|
+ int32 BlueprintsModified = 0;
|
||
|
|
+ int32 SaveFailures = 0;
|
||
|
|
+
|
||
|
|
+ const UEdGraphSchema_K2* Schema = GetDefault<UEdGraphSchema_K2>();
|
||
|
|
+
|
||
|
|
+ for (const FAssetData& AssetData : BlueprintAssets)
|
||
|
|
+ {
|
||
|
|
+ if (!AssetData.PackageName.ToString().StartsWith(TEXT("/Game/")))
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ UBlueprint* Blueprint = Cast<UBlueprint>(AssetData.GetAsset());
|
||
|
|
+ if (!Blueprint)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ TArray<UEdGraph*> Graphs;
|
||
|
|
+ Blueprint->GetAllGraphs(Graphs);
|
||
|
|
+
|
||
|
|
+ int32 FixedHere = 0;
|
||
|
|
+
|
||
|
|
+ for (UEdGraph* Graph : Graphs)
|
||
|
|
+ {
|
||
|
|
+ if (!Graph)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ TArray<UEdGraphNode*> Snapshot = Graph->Nodes;
|
||
|
|
+ for (UEdGraphNode* GraphNode : Snapshot)
|
||
|
|
+ {
|
||
|
|
+ // -------------------------------------------------------------------
|
||
|
|
+ // 1. GetAssetsByClass : la valeur de classe est restee sur l'orpheline.
|
||
|
|
+ // On bascule sur l'enrobage FName, qui la reprend telle quelle.
|
||
|
|
+ // -------------------------------------------------------------------
|
||
|
|
+ if (UK2Node_CallFunction* CallNode = Cast<UK2Node_CallFunction>(GraphNode))
|
||
|
|
+ {
|
||
|
|
+ if (CallNode->FunctionReference.GetMemberName() != GetAssetsByClassFunction)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ UEdGraphPin* Orphan = FindOrphan(CallNode, DeprecatedClassNamePin);
|
||
|
|
+ if (!Orphan)
|
||
|
|
+ {
|
||
|
|
+ continue; // deja corrige, ou noeud sain
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ const FString ClassValue = Orphan->DefaultValue;
|
||
|
|
+ UE_LOG(LogLPFixARPins, Warning, TEXT(" [enum] %s :: %s -> %s | classe='%s'"),
|
||
|
|
+ *Blueprint->GetName(), *Graph->GetName(), *GraphNode->GetName(), *ClassValue);
|
||
|
|
+
|
||
|
|
+ if (ClassValue.IsEmpty())
|
||
|
|
+ {
|
||
|
|
+ ++Unhandled;
|
||
|
|
+ UE_LOG(LogLPFixARPins, Error, TEXT(" orpheline vide : rien a reporter, reprise manuelle."));
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+ if (bDryRun)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ CallNode->Modify();
|
||
|
|
+ // La broche orpheline doit disparaitre AVANT la reconstruction, sinon
|
||
|
|
+ // ReconstructNode la conserve (garde-fou d'UE contre la perte de donnees).
|
||
|
|
+ Orphan->BreakAllPinLinks();
|
||
|
|
+ Orphan->DefaultValue.Empty();
|
||
|
|
+
|
||
|
|
+ CallNode->SetFromFunction(EnumFunction);
|
||
|
|
+ CallNode->ReconstructNode();
|
||
|
|
+
|
||
|
|
+ // La fonction de remplacement a une broche ClassName de meme nom : on y
|
||
|
|
+ // remet la valeur recuperee.
|
||
|
|
+ if (UEdGraphPin* NewPin = CallNode->FindPin(DeprecatedClassNamePin, EGPD_Input))
|
||
|
|
+ {
|
||
|
|
+ NewPin->DefaultValue = ClassValue;
|
||
|
|
+ UE_LOG(LogLPFixARPins, Warning, TEXT(" -> GetAssetsByClassName(ClassName='%s')"), *ClassValue);
|
||
|
|
+ ++EnumFixed;
|
||
|
|
+ ++FixedHere;
|
||
|
|
+ }
|
||
|
|
+ else
|
||
|
|
+ {
|
||
|
|
+ ++Unhandled;
|
||
|
|
+ UE_LOG(LogLPFixARPins, Error, TEXT(" broche ClassName absente apres reconstruction."));
|
||
|
|
+ }
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ // -------------------------------------------------------------------
|
||
|
|
+ // 2. Break AssetData : la sortie ObjectPath n'existe plus. On insere un
|
||
|
|
+ // appel a GetAssetObjectPath alimente par la meme structure, et on lui
|
||
|
|
+ // transfere les liaisons restees sur l'orpheline.
|
||
|
|
+ // -------------------------------------------------------------------
|
||
|
|
+ UK2Node_BreakStruct* BreakNode = Cast<UK2Node_BreakStruct>(GraphNode);
|
||
|
|
+ if (!BreakNode || !BreakNode->StructType ||
|
||
|
|
+ BreakNode->StructType->GetFName() != AssetDataStructName)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ UEdGraphPin* Orphan = FindOrphan(BreakNode, DeprecatedObjectPathPin);
|
||
|
|
+ if (!Orphan)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ UEdGraphPin* StructInput = BreakNode->FindPin(AssetDataPin, EGPD_Input);
|
||
|
|
+ UE_LOG(LogLPFixARPins, Warning, TEXT(" [path] %s :: %s -> %s | %d consommateur(s)"),
|
||
|
|
+ *Blueprint->GetName(), *Graph->GetName(), *GraphNode->GetName(), Orphan->LinkedTo.Num());
|
||
|
|
+
|
||
|
|
+ if (Orphan->LinkedTo.Num() == 0)
|
||
|
|
+ {
|
||
|
|
+ // Personne ne la lit : la vider suffit a la faire disparaitre.
|
||
|
|
+ if (!bDryRun)
|
||
|
|
+ {
|
||
|
|
+ BreakNode->Modify();
|
||
|
|
+ Orphan->DefaultValue.Empty();
|
||
|
|
+ BreakNode->ReconstructNode();
|
||
|
|
+ ++PathFixed;
|
||
|
|
+ ++FixedHere;
|
||
|
|
+ }
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!StructInput || StructInput->LinkedTo.Num() == 0)
|
||
|
|
+ {
|
||
|
|
+ ++Unhandled;
|
||
|
|
+ UE_LOG(LogLPFixARPins, Error, TEXT(" entree AssetData non connectee : reprise manuelle."));
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+ if (bDryRun)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ // Noeud de remplacement, place juste sous le Break.
|
||
|
|
+ UK2Node_CallFunction* PathNode = NewObject<UK2Node_CallFunction>(Graph);
|
||
|
|
+ PathNode->SetFromFunction(PathFunction);
|
||
|
|
+ PathNode->NodePosX = BreakNode->NodePosX;
|
||
|
|
+ PathNode->NodePosY = BreakNode->NodePosY + 120;
|
||
|
|
+ PathNode->CreateNewGuid();
|
||
|
|
+ PathNode->PostPlacedNewNode();
|
||
|
|
+ PathNode->AllocateDefaultPins();
|
||
|
|
+ Graph->Modify();
|
||
|
|
+ Graph->AddNode(PathNode, false, false);
|
||
|
|
+
|
||
|
|
+ UEdGraphPin* PathStructIn = PathNode->FindPin(AssetDataPin, EGPD_Input);
|
||
|
|
+ UEdGraphPin* PathReturn = PathNode->GetReturnValuePin();
|
||
|
|
+
|
||
|
|
+ bool bOk = PathStructIn && PathReturn;
|
||
|
|
+
|
||
|
|
+ // Meme source de structure que le Break.
|
||
|
|
+ if (bOk)
|
||
|
|
+ {
|
||
|
|
+ UEdGraphPin* Source = StructInput->LinkedTo[0];
|
||
|
|
+ bOk = Schema->TryCreateConnection(Source, PathStructIn);
|
||
|
|
+ if (!bOk)
|
||
|
|
+ {
|
||
|
|
+ UE_LOG(LogLPFixARPins, Error, TEXT(" source AssetData incompatible avec la nouvelle entree."));
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ // Transfert des consommateurs de l'orpheline vers la nouvelle sortie.
|
||
|
|
+ if (bOk)
|
||
|
|
+ {
|
||
|
|
+ const FPinConnectionResponse R = Schema->MovePinLinks(*Orphan, *PathReturn);
|
||
|
|
+ bOk = R.Response != CONNECT_RESPONSE_DISALLOW;
|
||
|
|
+ if (!bOk)
|
||
|
|
+ {
|
||
|
|
+ UE_LOG(LogLPFixARPins, Error, TEXT(" transfert impossible (%s)."), *R.Message.ToString());
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!bOk)
|
||
|
|
+ {
|
||
|
|
+ ++Unhandled;
|
||
|
|
+ PathNode->DestroyNode();
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ BreakNode->Modify();
|
||
|
|
+ Orphan->BreakAllPinLinks();
|
||
|
|
+ Orphan->DefaultValue.Empty();
|
||
|
|
+ BreakNode->ReconstructNode();
|
||
|
|
+
|
||
|
|
+ UE_LOG(LogLPFixARPins, Warning, TEXT(" -> GetAssetObjectPath inserE"));
|
||
|
|
+ ++PathFixed;
|
||
|
|
+ ++FixedHere;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (FixedHere > 0 && !bDryRun)
|
||
|
|
+ {
|
||
|
|
+ ++BlueprintsModified;
|
||
|
|
+ FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(Blueprint);
|
||
|
|
+ FKismetEditorUtilities::CompileBlueprint(Blueprint);
|
||
|
|
+
|
||
|
|
+ UPackage* Package = Blueprint->GetOutermost();
|
||
|
|
+ FString Filename;
|
||
|
|
+ if (!FPackageName::TryConvertLongPackageNameToFilename(
|
||
|
|
+ Package->GetName(), Filename, FPackageName::GetAssetPackageExtension()))
|
||
|
|
+ {
|
||
|
|
+ ++SaveFailures;
|
||
|
|
+ UE_LOG(LogLPFixARPins, Error, TEXT(" chemin introuvable pour %s"), *Package->GetName());
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ ResetLoaders(Package);
|
||
|
|
+
|
||
|
|
+ FSavePackageArgs SaveArgs;
|
||
|
|
+ SaveArgs.TopLevelFlags = RF_Public | RF_Standalone;
|
||
|
|
+ SaveArgs.SaveFlags = SAVE_None;
|
||
|
|
+ SaveArgs.bWarnOfLongFilename = true;
|
||
|
|
+ // GWarn et non GError : en commandlet, GError rend toute erreur de save fatale.
|
||
|
|
+ SaveArgs.Error = GWarn;
|
||
|
|
+
|
||
|
|
+ if (UPackage::SavePackage(Package, nullptr, *Filename, SaveArgs))
|
||
|
|
+ {
|
||
|
|
+ UE_LOG(LogLPFixARPins, Warning, TEXT(" -> %s sauvegarde (%d noeud(s))."), *Package->GetName(), FixedHere);
|
||
|
|
+ }
|
||
|
|
+ else
|
||
|
|
+ {
|
||
|
|
+ ++SaveFailures;
|
||
|
|
+ UE_LOG(LogLPFixARPins, Error, TEXT(" -> ECHEC de sauvegarde de %s"), *Package->GetName());
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ UE_LOG(LogLPFixARPins, Warning,
|
||
|
|
+ TEXT("=== Termine : %d enumeration(s), %d chemin(s), %d Blueprint(s) modifie(s), %d cas non traite(s), %d echec(s). ==="),
|
||
|
|
+ EnumFixed, PathFixed, BlueprintsModified, Unhandled, SaveFailures);
|
||
|
|
+
|
||
|
|
+ return (SaveFailures > 0 || Unhandled > 0) ? 1 : 0;
|
||
|
|
+}
|
||
|
|
diff --git a/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixAssetRegistryPinsCommandlet.h b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixAssetRegistryPinsCommandlet.h
|
||
|
|
new file mode 100644
|
||
|
|
index 0000000..95ef029
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixAssetRegistryPinsCommandlet.h
|
||
|
|
@@ -0,0 +1,50 @@
|
||
|
|
+// Portage UE 5.5 (2026.9 beta) - correctif du 2026-09-28.
|
||
|
|
+//
|
||
|
|
+// SYMPTOME : pendant un evenement, l'homme s'appelle toujours Tyrone et la femme girl ou
|
||
|
|
+// Meihui, tous nus et au meme visage. generatePerson() sans argument doit produire un
|
||
|
|
+// acteur completement aleatoire ; il retombait sur un personnage par defaut.
|
||
|
|
+//
|
||
|
|
+// CAUSE : UE 5.1 a remplace
|
||
|
|
+// IAssetRegistry::GetAssetsByClass(FName ClassName, ...)
|
||
|
|
+// par GetAssetsByClass(FTopLevelAssetPath ClassPathName, ...)
|
||
|
|
+// FAssetData::ObjectPath (FName)
|
||
|
|
+// par FAssetData::GetSoftObjectPath()
|
||
|
|
+// La montee de version a supprime les anciennes broches des noeuds existants SANS reporter
|
||
|
|
+// leur contenu sur les nouvelles. Releve par LPCheckMeshAssignment :
|
||
|
|
+//
|
||
|
|
+// [GetAssetsByClass] ClassPathName [TopLevelAssetPath] VIDE
|
||
|
|
+// ClassName [orpheline] defaut='SkeletalMesh'
|
||
|
|
+//
|
||
|
|
+// Les trois appels de GI interrogeaient donc l'AssetRegistry avec un chemin de classe vide
|
||
|
|
+// et ne renvoyaient rien. Plus aucune enumeration de corps, de vetements ni de coiffures :
|
||
|
|
+// le tirage aleatoire n'avait plus de population ou puiser. Le chargement par chemin
|
||
|
|
+// explicite (GetAssetByObjectPath) fonctionnait, d'ou les seuls personnages visibles : ceux
|
||
|
|
+// que les scenes nomment explicitement, comme Tyrone via generatePerson(bggw_tyrone).
|
||
|
|
+//
|
||
|
|
+// Aucune erreur de compilation ne le signalait : 103 Blueprints compilaient a zero
|
||
|
|
+// avertissement. Seul le drapeau bOrphanedPin pose par le moteur le revelait (5 en 5.5,
|
||
|
|
+// 0 en 4.27).
|
||
|
|
+//
|
||
|
|
+// CORRECTIF : reaiguiller vers ULPAssetRegistryHelpers, qui re-expose les deux API avec
|
||
|
|
+// leur ancienne signature. Meme patron que LPFixAssetRegistryNodes et
|
||
|
|
+// LPFixEditableTextBoxFont.
|
||
|
|
+//
|
||
|
|
+// Usage :
|
||
|
|
+// UnrealEditor-Cmd.exe <projet> -run=LPFixAssetRegistryPins [-DryRun]
|
||
|
|
+
|
||
|
|
+#pragma once
|
||
|
|
+
|
||
|
|
+#include "CoreMinimal.h"
|
||
|
|
+#include "Commandlets/Commandlet.h"
|
||
|
|
+#include "LPFixAssetRegistryPinsCommandlet.generated.h"
|
||
|
|
+
|
||
|
|
+UCLASS()
|
||
|
|
+class ULPFixAssetRegistryPinsCommandlet : public UCommandlet
|
||
|
|
+{
|
||
|
|
+ GENERATED_BODY()
|
||
|
|
+
|
||
|
|
+public:
|
||
|
|
+ ULPFixAssetRegistryPinsCommandlet();
|
||
|
|
+
|
||
|
|
+ virtual int32 Main(const FString& Params) override;
|
||
|
|
+};
|
||
|
|
diff --git a/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixDeprecatedNodesCommandlet.cpp b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixDeprecatedNodesCommandlet.cpp
|
||
|
|
new file mode 100644
|
||
|
|
index 0000000..e54c698
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixDeprecatedNodesCommandlet.cpp
|
||
|
|
@@ -0,0 +1,323 @@
|
||
|
|
+// Portage UE 5.5 - voir LPFixDeprecatedNodesCommandlet.h
|
||
|
|
+
|
||
|
|
+#include "LPFixDeprecatedNodesCommandlet.h"
|
||
|
|
+
|
||
|
|
+#include "AssetRegistry/AssetRegistryModule.h"
|
||
|
|
+#include "Components/SkeletalMeshComponent.h"
|
||
|
|
+#include "Components/SkinnedMeshComponent.h"
|
||
|
|
+#include "EdGraph/EdGraph.h"
|
||
|
|
+#include "EdGraph/EdGraphPin.h"
|
||
|
|
+#include "EdGraphSchema_K2.h"
|
||
|
|
+#include "Engine/Blueprint.h"
|
||
|
|
+#include "K2Node_CallFunction.h"
|
||
|
|
+#include "K2Node_VariableGet.h"
|
||
|
|
+#include "Kismet2/BlueprintEditorUtils.h"
|
||
|
|
+#include "Kismet2/KismetEditorUtilities.h"
|
||
|
|
+#include "LPNavigationHelpers.h"
|
||
|
|
+#include "Misc/PackageName.h"
|
||
|
|
+#include "NavigationSystem.h"
|
||
|
|
+#include "UObject/Package.h"
|
||
|
|
+#include "UObject/SavePackage.h"
|
||
|
|
+#include "UObject/UObjectGlobals.h"
|
||
|
|
+
|
||
|
|
+DEFINE_LOG_CATEGORY_STATIC(LogLPFixDeprecated, Log, All);
|
||
|
|
+
|
||
|
|
+namespace
|
||
|
|
+{
|
||
|
|
+ // --- R-03 ---
|
||
|
|
+ const FName SkeletalMeshPropertyName(TEXT("SkeletalMesh"));
|
||
|
|
+ const FName DeprecatedGetterName(TEXT("GetSkeletalMesh_DEPRECATED"));
|
||
|
|
+ const FName ReplacementGetterName(TEXT("GetSkeletalMeshAsset"));
|
||
|
|
+
|
||
|
|
+ // --- R-04 ---
|
||
|
|
+ const FName DeprecatedNavFunctionName(TEXT("K2_GetRandomPointInNavigableRadius"));
|
||
|
|
+ const FName ReplacementNavFunctionName(TEXT("GetRandomLocationInNavigableRadius"));
|
||
|
|
+
|
||
|
|
+ /** Decrit une broche et ses liaisons, pour le rapport. Copie du motif de LPFixEditableTextBoxFont. */
|
||
|
|
+ FString DescribeLinks(const UEdGraphPin* Pin)
|
||
|
|
+ {
|
||
|
|
+ if (!Pin)
|
||
|
|
+ {
|
||
|
|
+ return TEXT("(broche absente)");
|
||
|
|
+ }
|
||
|
|
+ if (Pin->LinkedTo.Num() == 0)
|
||
|
|
+ {
|
||
|
|
+ return FString::Printf(TEXT("non connectee (defaut: '%s')"), *Pin->DefaultValue);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ TArray<FString> Targets;
|
||
|
|
+ for (const UEdGraphPin* Linked : Pin->LinkedTo)
|
||
|
|
+ {
|
||
|
|
+ Targets.Add(FString::Printf(TEXT("%s.%s"),
|
||
|
|
+ Linked->GetOwningNode() ? *Linked->GetOwningNode()->GetName() : TEXT("?"),
|
||
|
|
+ *Linked->PinName.ToString()));
|
||
|
|
+ }
|
||
|
|
+ return FString::Printf(TEXT("%d liaison(s) -> %s"), Pin->LinkedTo.Num(), *FString::Join(Targets, TEXT(", ")));
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /** Vrai si la classe proprietaire du membre est USkinnedMeshComponent ou une de ses filles. */
|
||
|
|
+ bool IsSkinnedMeshOwner(const UClass* OwnerClass)
|
||
|
|
+ {
|
||
|
|
+ return OwnerClass && OwnerClass->IsChildOf(USkinnedMeshComponent::StaticClass());
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+ULPFixDeprecatedNodesCommandlet::ULPFixDeprecatedNodesCommandlet()
|
||
|
|
+{
|
||
|
|
+ IsClient = false;
|
||
|
|
+ IsServer = false;
|
||
|
|
+ IsEditor = true;
|
||
|
|
+ LogToConsole = true;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+int32 ULPFixDeprecatedNodesCommandlet::Main(const FString& Params)
|
||
|
|
+{
|
||
|
|
+ const bool bDryRun = Params.Contains(TEXT("DryRun"), ESearchCase::IgnoreCase);
|
||
|
|
+
|
||
|
|
+ UFunction* ReplacementGetter =
|
||
|
|
+ USkeletalMeshComponent::StaticClass()->FindFunctionByName(ReplacementGetterName);
|
||
|
|
+ UFunction* ReplacementNavFunction =
|
||
|
|
+ ULPNavigationHelpers::StaticClass()->FindFunctionByName(ReplacementNavFunctionName);
|
||
|
|
+
|
||
|
|
+ if (!ReplacementGetter || !ReplacementNavFunction)
|
||
|
|
+ {
|
||
|
|
+ UE_LOG(LogLPFixDeprecated, Error,
|
||
|
|
+ TEXT("Fonctions de remplacement introuvables (GetSkeletalMeshAsset=%s, GetRandomLocationInNavigableRadius=%s)."),
|
||
|
|
+ ReplacementGetter ? TEXT("ok") : TEXT("NULL"),
|
||
|
|
+ ReplacementNavFunction ? TEXT("ok") : TEXT("NULL"));
|
||
|
|
+ return 1;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ UE_LOG(LogLPFixDeprecated, Warning, TEXT("=== Noeuds deprecies : SkeletalMesh (R-03) + GetRandomPointInNavigableRadius (R-04)%s ==="),
|
||
|
|
+ bDryRun ? TEXT(" [DRY RUN]") : TEXT(""));
|
||
|
|
+
|
||
|
|
+ FAssetRegistryModule& AssetRegistryModule =
|
||
|
|
+ FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
|
||
|
|
+ AssetRegistryModule.Get().SearchAllAssets(true);
|
||
|
|
+
|
||
|
|
+ TArray<FAssetData> BlueprintAssets;
|
||
|
|
+ // bSearchSubClasses = true : couvre aussi les UWidgetBlueprint (CharGen, Inventory, ...).
|
||
|
|
+ AssetRegistryModule.Get().GetAssetsByClass(UBlueprint::StaticClass()->GetClassPathName(), BlueprintAssets, true);
|
||
|
|
+
|
||
|
|
+ int32 MeshNodesFound = 0;
|
||
|
|
+ int32 NavNodesFound = 0;
|
||
|
|
+ int32 MeshNodesFixed = 0;
|
||
|
|
+ int32 NavNodesFixed = 0;
|
||
|
|
+ int32 BlueprintsModified = 0;
|
||
|
|
+ int32 SaveFailures = 0;
|
||
|
|
+ int32 Unhandled = 0;
|
||
|
|
+
|
||
|
|
+ const UEdGraphSchema_K2* Schema = GetDefault<UEdGraphSchema_K2>();
|
||
|
|
+
|
||
|
|
+ for (const FAssetData& AssetData : BlueprintAssets)
|
||
|
|
+ {
|
||
|
|
+ if (!AssetData.PackageName.ToString().StartsWith(TEXT("/Game/")))
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ UBlueprint* Blueprint = Cast<UBlueprint>(AssetData.GetAsset());
|
||
|
|
+ if (!Blueprint)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ TArray<UEdGraph*> Graphs;
|
||
|
|
+ Blueprint->GetAllGraphs(Graphs);
|
||
|
|
+
|
||
|
|
+ int32 FixedHere = 0;
|
||
|
|
+
|
||
|
|
+ for (UEdGraph* Graph : Graphs)
|
||
|
|
+ {
|
||
|
|
+ if (!Graph)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ // Snapshot : on cree et on detruit des noeuds pendant l'iteration.
|
||
|
|
+ TArray<UEdGraphNode*> Snapshot = Graph->Nodes;
|
||
|
|
+ for (UEdGraphNode* GraphNode : Snapshot)
|
||
|
|
+ {
|
||
|
|
+ // ---------------------------------------------------------------
|
||
|
|
+ // R-04 : reference de fonction a reaiguiller, rien d'autre a faire.
|
||
|
|
+ // Signatures et noms de broches identiques -> ReconstructNode conserve
|
||
|
|
+ // toutes les liaisons.
|
||
|
|
+ // ---------------------------------------------------------------
|
||
|
|
+ if (UK2Node_CallFunction* CallNode = Cast<UK2Node_CallFunction>(GraphNode))
|
||
|
|
+ {
|
||
|
|
+ const FName MemberName = CallNode->FunctionReference.GetMemberName();
|
||
|
|
+ const UClass* MemberOwner = CallNode->FunctionReference.GetMemberParentClass();
|
||
|
|
+
|
||
|
|
+ if (MemberName == DeprecatedNavFunctionName)
|
||
|
|
+ {
|
||
|
|
+ ++NavNodesFound;
|
||
|
|
+ UE_LOG(LogLPFixDeprecated, Warning, TEXT(" [R-04] %s :: %s -> %s"),
|
||
|
|
+ *Blueprint->GetName(), *Graph->GetName(), *GraphNode->GetName());
|
||
|
|
+ UE_LOG(LogLPFixDeprecated, Warning, TEXT(" RandomLocation : %s"),
|
||
|
|
+ *DescribeLinks(GraphNode->FindPin(TEXT("RandomLocation"))));
|
||
|
|
+
|
||
|
|
+ if (!bDryRun)
|
||
|
|
+ {
|
||
|
|
+ GraphNode->Modify();
|
||
|
|
+ CallNode->SetFromFunction(ReplacementNavFunction);
|
||
|
|
+ CallNode->ReconstructNode();
|
||
|
|
+ ++NavNodesFixed;
|
||
|
|
+ ++FixedHere;
|
||
|
|
+ }
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ // R-03, variante « appel explicite du getter deprecie ».
|
||
|
|
+ if (MemberName == DeprecatedGetterName && IsSkinnedMeshOwner(MemberOwner))
|
||
|
|
+ {
|
||
|
|
+ ++MeshNodesFound;
|
||
|
|
+ UE_LOG(LogLPFixDeprecated, Warning, TEXT(" [R-03/appel] %s :: %s -> %s"),
|
||
|
|
+ *Blueprint->GetName(), *Graph->GetName(), *GraphNode->GetName());
|
||
|
|
+
|
||
|
|
+ if (!bDryRun)
|
||
|
|
+ {
|
||
|
|
+ GraphNode->Modify();
|
||
|
|
+ CallNode->SetFromFunction(ReplacementGetter);
|
||
|
|
+ CallNode->ReconstructNode();
|
||
|
|
+ ++MeshNodesFixed;
|
||
|
|
+ ++FixedHere;
|
||
|
|
+ }
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ // ---------------------------------------------------------------
|
||
|
|
+ // R-03 : acces direct a la propriete depreciee. Il faut remplacer le
|
||
|
|
+ // noeud, pas seulement sa reference : un K2Node_VariableGet ne peut pas
|
||
|
|
+ // devenir un K2Node_CallFunction.
|
||
|
|
+ // ---------------------------------------------------------------
|
||
|
|
+ UK2Node_VariableGet* VarGet = Cast<UK2Node_VariableGet>(GraphNode);
|
||
|
|
+ if (!VarGet || VarGet->VariableReference.GetMemberName() != SkeletalMeshPropertyName)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+ if (!IsSkinnedMeshOwner(VarGet->VariableReference.GetMemberParentClass()))
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ UEdGraphPin* OldSelfPin = VarGet->FindPin(UEdGraphSchema_K2::PN_Self, EGPD_Input);
|
||
|
|
+ UEdGraphPin* OldValuePin = VarGet->GetValuePin();
|
||
|
|
+
|
||
|
|
+ ++MeshNodesFound;
|
||
|
|
+ UE_LOG(LogLPFixDeprecated, Warning, TEXT(" [R-03/propriete] %s :: %s -> %s"),
|
||
|
|
+ *Blueprint->GetName(), *Graph->GetName(), *GraphNode->GetName());
|
||
|
|
+ UE_LOG(LogLPFixDeprecated, Warning, TEXT(" Target : %s"), *DescribeLinks(OldSelfPin));
|
||
|
|
+ UE_LOG(LogLPFixDeprecated, Warning, TEXT(" Valeur : %s"), *DescribeLinks(OldValuePin));
|
||
|
|
+
|
||
|
|
+ if (bDryRun)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!OldValuePin)
|
||
|
|
+ {
|
||
|
|
+ ++Unhandled;
|
||
|
|
+ UE_LOG(LogLPFixDeprecated, Error, TEXT(" broche de valeur introuvable, noeud laisse en l'etat."));
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ // Construction du noeud de remplacement au meme emplacement.
|
||
|
|
+ UK2Node_CallFunction* NewNode = NewObject<UK2Node_CallFunction>(Graph);
|
||
|
|
+ NewNode->SetFromFunction(ReplacementGetter);
|
||
|
|
+ NewNode->NodePosX = VarGet->NodePosX;
|
||
|
|
+ NewNode->NodePosY = VarGet->NodePosY;
|
||
|
|
+ NewNode->CreateNewGuid();
|
||
|
|
+ NewNode->PostPlacedNewNode();
|
||
|
|
+ NewNode->AllocateDefaultPins();
|
||
|
|
+ Graph->Modify();
|
||
|
|
+ Graph->AddNode(NewNode, false, false);
|
||
|
|
+
|
||
|
|
+ UEdGraphPin* NewSelfPin = NewNode->FindPin(UEdGraphSchema_K2::PN_Self, EGPD_Input);
|
||
|
|
+ UEdGraphPin* NewValuePin = NewNode->GetReturnValuePin();
|
||
|
|
+
|
||
|
|
+ bool bMoved = true;
|
||
|
|
+
|
||
|
|
+ // GetSkeletalMeshAsset() n'existe que sur USkeletalMeshComponent alors que la
|
||
|
|
+ // propriete depreciee vit sur USkinnedMeshComponent. Si la cible du noeud est
|
||
|
|
+ // typee sur la classe de base, le deplacement echoue : on le signale au lieu de
|
||
|
|
+ // casser le graphe.
|
||
|
|
+ if (OldSelfPin && NewSelfPin)
|
||
|
|
+ {
|
||
|
|
+ const FPinConnectionResponse Response = Schema->MovePinLinks(*OldSelfPin, *NewSelfPin);
|
||
|
|
+ if (Response.Response == CONNECT_RESPONSE_DISALLOW)
|
||
|
|
+ {
|
||
|
|
+ bMoved = false;
|
||
|
|
+ UE_LOG(LogLPFixDeprecated, Error, TEXT(" Target incompatible (%s) : reprise manuelle necessaire."),
|
||
|
|
+ *Response.Message.ToString());
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (bMoved && NewValuePin)
|
||
|
|
+ {
|
||
|
|
+ const FPinConnectionResponse Response = Schema->MovePinLinks(*OldValuePin, *NewValuePin);
|
||
|
|
+ if (Response.Response == CONNECT_RESPONSE_DISALLOW)
|
||
|
|
+ {
|
||
|
|
+ bMoved = false;
|
||
|
|
+ UE_LOG(LogLPFixDeprecated, Error, TEXT(" Valeur incompatible (%s) : reprise manuelle necessaire."),
|
||
|
|
+ *Response.Message.ToString());
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!bMoved)
|
||
|
|
+ {
|
||
|
|
+ // On remet tout en place : le noeud d'origine garde ses liaisons.
|
||
|
|
+ ++Unhandled;
|
||
|
|
+ NewNode->DestroyNode();
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ VarGet->DestroyNode();
|
||
|
|
+ ++MeshNodesFixed;
|
||
|
|
+ ++FixedHere;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (FixedHere > 0 && !bDryRun)
|
||
|
|
+ {
|
||
|
|
+ ++BlueprintsModified;
|
||
|
|
+ FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(Blueprint);
|
||
|
|
+ FKismetEditorUtilities::CompileBlueprint(Blueprint);
|
||
|
|
+
|
||
|
|
+ UPackage* Package = Blueprint->GetOutermost();
|
||
|
|
+ FString Filename;
|
||
|
|
+ if (!FPackageName::TryConvertLongPackageNameToFilename(
|
||
|
|
+ Package->GetName(), Filename, FPackageName::GetAssetPackageExtension()))
|
||
|
|
+ {
|
||
|
|
+ ++SaveFailures;
|
||
|
|
+ UE_LOG(LogLPFixDeprecated, Error, TEXT(" chemin introuvable pour %s"), *Package->GetName());
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ ResetLoaders(Package);
|
||
|
|
+
|
||
|
|
+ FSavePackageArgs SaveArgs;
|
||
|
|
+ SaveArgs.TopLevelFlags = RF_Public | RF_Standalone;
|
||
|
|
+ SaveArgs.SaveFlags = SAVE_None;
|
||
|
|
+ SaveArgs.bWarnOfLongFilename = true;
|
||
|
|
+ // GWarn et non GError : en commandlet, GError rend toute erreur de save fatale.
|
||
|
|
+ SaveArgs.Error = GWarn;
|
||
|
|
+
|
||
|
|
+ if (UPackage::SavePackage(Package, nullptr, *Filename, SaveArgs))
|
||
|
|
+ {
|
||
|
|
+ UE_LOG(LogLPFixDeprecated, Warning, TEXT(" -> %s sauvegarde (%d noeud(s))."), *Package->GetName(), FixedHere);
|
||
|
|
+ }
|
||
|
|
+ else
|
||
|
|
+ {
|
||
|
|
+ ++SaveFailures;
|
||
|
|
+ UE_LOG(LogLPFixDeprecated, Error, TEXT(" -> ECHEC de sauvegarde de %s"), *Package->GetName());
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ UE_LOG(LogLPFixDeprecated, Warning,
|
||
|
|
+ TEXT("=== Termine : R-03 %d trouve(s) / %d corrige(s), R-04 %d trouve(s) / %d corrige(s), %d Blueprint(s) modifie(s), %d cas non traite(s), %d echec(s) de sauvegarde. ==="),
|
||
|
|
+ MeshNodesFound, MeshNodesFixed, NavNodesFound, NavNodesFixed, BlueprintsModified, Unhandled, SaveFailures);
|
||
|
|
+
|
||
|
|
+ return (SaveFailures > 0 || Unhandled > 0) ? 1 : 0;
|
||
|
|
+}
|
||
|
|
diff --git a/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixDeprecatedNodesCommandlet.h b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixDeprecatedNodesCommandlet.h
|
||
|
|
new file mode 100644
|
||
|
|
index 0000000..0c6aba4
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixDeprecatedNodesCommandlet.h
|
||
|
|
@@ -0,0 +1,39 @@
|
||
|
|
+// Portage UE 5.5 (2026.9 beta) - remediations R-03 et R-04.
|
||
|
|
+//
|
||
|
|
+// Deux familles de noeuds Blueprint deprecies subsistent apres la migration ; elles
|
||
|
|
+// representent a elles seules la quasi-totalite des avertissements de cook.
|
||
|
|
+//
|
||
|
|
+// R-03 USkinnedMeshComponent::SkeletalMesh (propriete) et son BlueprintGetter
|
||
|
|
+// GetSkeletalMesh_DEPRECATED -> USkeletalMeshComponent::GetSkeletalMeshAsset()
|
||
|
|
+// Les deux rendent le meme type (USkeletalMesh*), le remplacement conserve donc les
|
||
|
|
+// liaisons aval. Le noeud d'origine peut etre un K2Node_VariableGet (acces direct a
|
||
|
|
+// la propriete) ou un K2Node_CallFunction (appel du getter) : les deux sont traites.
|
||
|
|
+//
|
||
|
|
+// R-04 UNavigationSystemV1::K2_GetRandomPointInNavigableRadius
|
||
|
|
+// -> ULPNavigationHelpers::GetRandomLocationInNavigableRadius
|
||
|
|
+// On NE pointe PAS vers K2_GetRandomLocationInNavigableRadius du moteur : celui-ci
|
||
|
|
+// est BlueprintCallable alors que les noeuds existants sont purs. Voir
|
||
|
|
+// LPNavigationHelpers.h.
|
||
|
|
+//
|
||
|
|
+// Usage :
|
||
|
|
+// UnrealEditor-Cmd.exe <chemin>\LifePlay.uproject -run=LPFixDeprecatedNodes [-DryRun]
|
||
|
|
+//
|
||
|
|
+// -DryRun n'ecrit rien : il liste les noeuds trouves, leur Blueprint, leur graphe et l'etat
|
||
|
|
+// de leurs broches. A lancer systematiquement avant la passe reelle.
|
||
|
|
+
|
||
|
|
+#pragma once
|
||
|
|
+
|
||
|
|
+#include "CoreMinimal.h"
|
||
|
|
+#include "Commandlets/Commandlet.h"
|
||
|
|
+#include "LPFixDeprecatedNodesCommandlet.generated.h"
|
||
|
|
+
|
||
|
|
+UCLASS()
|
||
|
|
+class ULPFixDeprecatedNodesCommandlet : public UCommandlet
|
||
|
|
+{
|
||
|
|
+ GENERATED_BODY()
|
||
|
|
+
|
||
|
|
+public:
|
||
|
|
+ ULPFixDeprecatedNodesCommandlet();
|
||
|
|
+
|
||
|
|
+ virtual int32 Main(const FString& Params) override;
|
||
|
|
+};
|
||
|
|
diff --git a/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixEditableTextBoxFontCommandlet.cpp b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixEditableTextBoxFontCommandlet.cpp
|
||
|
|
new file mode 100644
|
||
|
|
index 0000000..80058af
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixEditableTextBoxFontCommandlet.cpp
|
||
|
|
@@ -0,0 +1,255 @@
|
||
|
|
+// Portage UE 5.5 - voir LPFixEditableTextBoxFontCommandlet.h
|
||
|
|
+
|
||
|
|
+#include "LPFixEditableTextBoxFontCommandlet.h"
|
||
|
|
+
|
||
|
|
+#include "AssetRegistry/AssetRegistryModule.h"
|
||
|
|
+#include "EdGraph/EdGraph.h"
|
||
|
|
+#include "EdGraph/EdGraphPin.h"
|
||
|
|
+#include "EdGraphSchema_K2.h"
|
||
|
|
+#include "Engine/Blueprint.h"
|
||
|
|
+#include "K2Node_BreakStruct.h"
|
||
|
|
+#include "K2Node_MakeStruct.h"
|
||
|
|
+#include "Kismet2/BlueprintEditorUtils.h"
|
||
|
|
+#include "Kismet2/KismetEditorUtilities.h"
|
||
|
|
+#include "Misc/PackageName.h"
|
||
|
|
+#include "Styling/SlateTypes.h"
|
||
|
|
+#include "UObject/Package.h"
|
||
|
|
+#include "UObject/SavePackage.h"
|
||
|
|
+#include "UObject/UObjectGlobals.h"
|
||
|
|
+
|
||
|
|
+DEFINE_LOG_CATEGORY_STATIC(LogLPFixFont, Log, All);
|
||
|
|
+
|
||
|
|
+namespace
|
||
|
|
+{
|
||
|
|
+ const TCHAR* OrphanPinName = TEXT("Font");
|
||
|
|
+ const TCHAR* TextStylePinName = TEXT("TextStyle");
|
||
|
|
+
|
||
|
|
+ /** Decrit une broche et ses liaisons, pour le rapport. */
|
||
|
|
+ FString DescribeLinks(const UEdGraphPin* Pin)
|
||
|
|
+ {
|
||
|
|
+ if (!Pin)
|
||
|
|
+ {
|
||
|
|
+ return TEXT("(broche absente)");
|
||
|
|
+ }
|
||
|
|
+ if (Pin->LinkedTo.Num() == 0)
|
||
|
|
+ {
|
||
|
|
+ return FString::Printf(TEXT("non connectee (defaut: '%s')"), *Pin->DefaultValue);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ TArray<FString> Targets;
|
||
|
|
+ for (const UEdGraphPin* Linked : Pin->LinkedTo)
|
||
|
|
+ {
|
||
|
|
+ Targets.Add(FString::Printf(TEXT("%s.%s"),
|
||
|
|
+ Linked->GetOwningNode() ? *Linked->GetOwningNode()->GetName() : TEXT("?"),
|
||
|
|
+ *Linked->PinName.ToString()));
|
||
|
|
+ }
|
||
|
|
+ return FString::Printf(TEXT("%d liaison(s) -> %s"), Pin->LinkedTo.Num(), *FString::Join(Targets, TEXT(", ")));
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+ULPFixEditableTextBoxFontCommandlet::ULPFixEditableTextBoxFontCommandlet()
|
||
|
|
+{
|
||
|
|
+ IsClient = false;
|
||
|
|
+ IsServer = false;
|
||
|
|
+ IsEditor = true;
|
||
|
|
+ LogToConsole = true;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+int32 ULPFixEditableTextBoxFontCommandlet::Main(const FString& Params)
|
||
|
|
+{
|
||
|
|
+ const bool bDryRun = Params.Contains(TEXT("DryRun"), ESearchCase::IgnoreCase);
|
||
|
|
+
|
||
|
|
+ UScriptStruct* EditableStruct = TBaseStructure<FEditableTextBoxStyle>::Get();
|
||
|
|
+ if (!EditableStruct)
|
||
|
|
+ {
|
||
|
|
+ UE_LOG(LogLPFixFont, Error, TEXT("Structure FEditableTextBoxStyle introuvable."));
|
||
|
|
+ return 1;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ UE_LOG(LogLPFixFont, Warning, TEXT("=== Rebranchement de la broche Font (EditableTextBoxStyle)%s ==="),
|
||
|
|
+ bDryRun ? TEXT(" [DRY RUN]") : TEXT(""));
|
||
|
|
+
|
||
|
|
+ FAssetRegistryModule& AssetRegistryModule =
|
||
|
|
+ FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
|
||
|
|
+ AssetRegistryModule.Get().SearchAllAssets(true);
|
||
|
|
+
|
||
|
|
+ TArray<FAssetData> BlueprintAssets;
|
||
|
|
+ AssetRegistryModule.Get().GetAssetsByClass(UBlueprint::StaticClass()->GetClassPathName(), BlueprintAssets, true);
|
||
|
|
+
|
||
|
|
+ int32 NodesFound = 0;
|
||
|
|
+ int32 NodesFixed = 0;
|
||
|
|
+ int32 BlueprintsModified = 0;
|
||
|
|
+ int32 SaveFailures = 0;
|
||
|
|
+ int32 UnhandledLinks = 0;
|
||
|
|
+
|
||
|
|
+ for (const FAssetData& AssetData : BlueprintAssets)
|
||
|
|
+ {
|
||
|
|
+ if (!AssetData.PackageName.ToString().StartsWith(TEXT("/Game/")))
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ UBlueprint* Blueprint = Cast<UBlueprint>(AssetData.GetAsset());
|
||
|
|
+ if (!Blueprint)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ TArray<UEdGraph*> Graphs;
|
||
|
|
+ Blueprint->GetAllGraphs(Graphs);
|
||
|
|
+
|
||
|
|
+ int32 FixedHere = 0;
|
||
|
|
+ struct FPendingLink { UK2Node_BreakStruct* Break; UK2Node_MakeStruct* Make; };
|
||
|
|
+ TArray<FPendingLink> PendingLinks;
|
||
|
|
+ TArray<UEdGraphNode*> NodesToReconstruct;
|
||
|
|
+
|
||
|
|
+ for (UEdGraph* Graph : Graphs)
|
||
|
|
+ {
|
||
|
|
+ if (!Graph)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ TArray<UEdGraphNode*> Snapshot = Graph->Nodes;
|
||
|
|
+ for (UEdGraphNode* GraphNode : Snapshot)
|
||
|
|
+ {
|
||
|
|
+ UK2Node_MakeStruct* MakeNode = Cast<UK2Node_MakeStruct>(GraphNode);
|
||
|
|
+ UK2Node_BreakStruct* BreakNode = Cast<UK2Node_BreakStruct>(GraphNode);
|
||
|
|
+
|
||
|
|
+ const bool bIsTarget =
|
||
|
|
+ (MakeNode && MakeNode->StructType == EditableStruct) ||
|
||
|
|
+ (BreakNode && BreakNode->StructType == EditableStruct);
|
||
|
|
+ if (!bIsTarget)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ UEdGraphPin* FontPin = GraphNode->FindPin(OrphanPinName);
|
||
|
|
+ if (!FontPin)
|
||
|
|
+ {
|
||
|
|
+ continue; // deja corrige
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ ++NodesFound;
|
||
|
|
+ UE_LOG(LogLPFixFont, Warning, TEXT(" %s :: %s -> %s"),
|
||
|
|
+ *Blueprint->GetName(), *Graph->GetName(), *GraphNode->GetName());
|
||
|
|
+ UE_LOG(LogLPFixFont, Warning, TEXT(" broche Font : %s"), *DescribeLinks(FontPin));
|
||
|
|
+ UE_LOG(LogLPFixFont, Warning, TEXT(" broche TextStyle : %s"),
|
||
|
|
+ *DescribeLinks(GraphNode->FindPin(TextStylePinName)));
|
||
|
|
+
|
||
|
|
+ if (bDryRun)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ // Topologie relevee sur CharGen et StatMenu :
|
||
|
|
+ // [Break EditableTextBoxStyle].Font -> [Make EditableTextBoxStyle].Font
|
||
|
|
+ // La police n'est pas construite, elle est recopiee d'un style vers un autre.
|
||
|
|
+ // Les deux extremites etant la meme structure et le champ ayant migre dans
|
||
|
|
+ // TextStyle, la correspondance fidele est TextStyle -> TextStyle : aucun
|
||
|
|
+ // noeud intermediaire n'est necessaire, et le reste du style suit.
|
||
|
|
+ if (MakeNode)
|
||
|
|
+ {
|
||
|
|
+ for (UEdGraphPin* Source : FontPin->LinkedTo)
|
||
|
|
+ {
|
||
|
|
+ UK2Node_BreakStruct* SourceBreak = Cast<UK2Node_BreakStruct>(Source->GetOwningNode());
|
||
|
|
+ if (SourceBreak && SourceBreak->StructType == EditableStruct)
|
||
|
|
+ {
|
||
|
|
+ PendingLinks.Add({ SourceBreak, MakeNode });
|
||
|
|
+ }
|
||
|
|
+ else
|
||
|
|
+ {
|
||
|
|
+ UE_LOG(LogLPFixFont, Error,
|
||
|
|
+ TEXT(" source Font inattendue (%s) : rebranchement a faire a la main."),
|
||
|
|
+ Source->GetOwningNode() ? *Source->GetOwningNode()->GetName() : TEXT("?"));
|
||
|
|
+ ++UnhandledLinks;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ // ReconstructNode conserve une broche orpheline dans DEUX cas : si elle
|
||
|
|
+ // porte des liaisons, et si elle porte une valeur differente du defaut.
|
||
|
|
+ // C'est le garde-fou d'UE contre la perte de donnees. Il faut donc lever
|
||
|
|
+ // les deux, APRES avoir releve la topologie et AVANT de reconstruire,
|
||
|
|
+ // sans quoi la broche Font survit et l'erreur persiste.
|
||
|
|
+ FontPin->BreakAllPinLinks();
|
||
|
|
+ GetDefault<UEdGraphSchema_K2>()->ResetPinToAutogeneratedDefaultValue(FontPin, false);
|
||
|
|
+
|
||
|
|
+ NodesToReconstruct.AddUnique(GraphNode);
|
||
|
|
+
|
||
|
|
+ ++NodesFixed;
|
||
|
|
+ ++FixedHere;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ // La reconstruction invalide les broches : on la fait en bloc, puis on relie.
|
||
|
|
+ for (UEdGraphNode* Node : NodesToReconstruct)
|
||
|
|
+ {
|
||
|
|
+ Node->ReconstructNode();
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ for (const FPendingLink& Link : PendingLinks)
|
||
|
|
+ {
|
||
|
|
+ UEdGraphPin* From = Link.Break->FindPin(TextStylePinName, EGPD_Output);
|
||
|
|
+ UEdGraphPin* To = Link.Make->FindPin(TextStylePinName, EGPD_Input);
|
||
|
|
+ if (From && To)
|
||
|
|
+ {
|
||
|
|
+ // Idempotent : une seconde execution ne doit pas doubler la liaison.
|
||
|
|
+ if (!From->LinkedTo.Contains(To))
|
||
|
|
+ {
|
||
|
|
+ From->MakeLinkTo(To);
|
||
|
|
+ }
|
||
|
|
+ UE_LOG(LogLPFixFont, Warning, TEXT(" %s.TextStyle -> %s.TextStyle"),
|
||
|
|
+ *Link.Break->GetName(), *Link.Make->GetName());
|
||
|
|
+ }
|
||
|
|
+ else
|
||
|
|
+ {
|
||
|
|
+ ++UnhandledLinks;
|
||
|
|
+ UE_LOG(LogLPFixFont, Error, TEXT(" TextStyle introuvable sur %s ou %s."),
|
||
|
|
+ *Link.Break->GetName(), *Link.Make->GetName());
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (FixedHere > 0 && !bDryRun)
|
||
|
|
+ {
|
||
|
|
+ ++BlueprintsModified;
|
||
|
|
+ FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(Blueprint);
|
||
|
|
+ FKismetEditorUtilities::CompileBlueprint(Blueprint);
|
||
|
|
+
|
||
|
|
+ UPackage* Package = Blueprint->GetOutermost();
|
||
|
|
+ FString Filename;
|
||
|
|
+ if (!FPackageName::TryConvertLongPackageNameToFilename(
|
||
|
|
+ Package->GetName(), Filename, FPackageName::GetAssetPackageExtension()))
|
||
|
|
+ {
|
||
|
|
+ ++SaveFailures;
|
||
|
|
+ UE_LOG(LogLPFixFont, Error, TEXT(" chemin introuvable pour %s"), *Package->GetName());
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ ResetLoaders(Package);
|
||
|
|
+
|
||
|
|
+ FSavePackageArgs SaveArgs;
|
||
|
|
+ SaveArgs.TopLevelFlags = RF_Public | RF_Standalone;
|
||
|
|
+ SaveArgs.SaveFlags = SAVE_None;
|
||
|
|
+ SaveArgs.bWarnOfLongFilename = true;
|
||
|
|
+ // GWarn et non GError : en commandlet, GError rend toute erreur de save fatale.
|
||
|
|
+ SaveArgs.Error = GWarn;
|
||
|
|
+
|
||
|
|
+ if (UPackage::SavePackage(Package, nullptr, *Filename, SaveArgs))
|
||
|
|
+ {
|
||
|
|
+ UE_LOG(LogLPFixFont, Warning, TEXT(" -> %s sauvegarde (%d noeud(s))."), *Package->GetName(), FixedHere);
|
||
|
|
+ }
|
||
|
|
+ else
|
||
|
|
+ {
|
||
|
|
+ ++SaveFailures;
|
||
|
|
+ UE_LOG(LogLPFixFont, Error, TEXT(" -> ECHEC de sauvegarde de %s"), *Package->GetName());
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ UE_LOG(LogLPFixFont, Warning, TEXT("=== Termine : %d noeud(s) trouve(s), %d traite(s) dans %d Blueprint(s), %d liaison(s) non geree(s), %d echec(s) de sauvegarde. ==="),
|
||
|
|
+ NodesFound, NodesFixed, BlueprintsModified, UnhandledLinks, SaveFailures);
|
||
|
|
+
|
||
|
|
+ return (SaveFailures > 0 || UnhandledLinks > 0) ? 1 : 0;
|
||
|
|
+}
|
||
|
|
diff --git a/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixEditableTextBoxFontCommandlet.h b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixEditableTextBoxFontCommandlet.h
|
||
|
|
new file mode 100644
|
||
|
|
index 0000000..c8039a7
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixEditableTextBoxFontCommandlet.h
|
||
|
|
@@ -0,0 +1,32 @@
|
||
|
|
+// Portage UE 5.5 - rebranchement de la broche Font des noeuds Make/Break EditableTextBoxStyle.
|
||
|
|
+//
|
||
|
|
+// FEditableTextBoxStyle::Font est devenu Font_DEPRECATED en 5.1 : la police vit desormais
|
||
|
|
+// dans TextStyle (FTextBlockStyle). Les noeuds Make/Break existants gardent une broche
|
||
|
|
+// orpheline "Font" qui fait echouer la compilation, et donc le cook :
|
||
|
|
+//
|
||
|
|
+// La broche "Font" n'existe plus sur le noeud "Break Editable Text Box Style".
|
||
|
|
+//
|
||
|
|
+// La commandlet retablit le chemin via TextStyle :
|
||
|
|
+// Make : source Font -> [Make TextBlockStyle].Font -> [Make EditableTextBoxStyle].TextStyle
|
||
|
|
+// Break : [Break EditableTextBoxStyle].TextStyle -> [Break TextBlockStyle].Font -> consommateurs
|
||
|
|
+//
|
||
|
|
+// UnrealEditor-Cmd.exe <projet> -run=LPFixEditableTextBoxFont [-DryRun]
|
||
|
|
+//
|
||
|
|
+// Sans -DryRun, les Blueprints modifies sont recompiles et sauvegardes.
|
||
|
|
+
|
||
|
|
+#pragma once
|
||
|
|
+
|
||
|
|
+#include "CoreMinimal.h"
|
||
|
|
+#include "Commandlets/Commandlet.h"
|
||
|
|
+#include "LPFixEditableTextBoxFontCommandlet.generated.h"
|
||
|
|
+
|
||
|
|
+UCLASS()
|
||
|
|
+class ULPFixEditableTextBoxFontCommandlet : public UCommandlet
|
||
|
|
+{
|
||
|
|
+ GENERATED_BODY()
|
||
|
|
+
|
||
|
|
+public:
|
||
|
|
+ ULPFixEditableTextBoxFontCommandlet();
|
||
|
|
+
|
||
|
|
+ virtual int32 Main(const FString& Params) override;
|
||
|
|
+};
|
||
|
|
diff --git a/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixOrphanBoundEventsCommandlet.cpp b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixOrphanBoundEventsCommandlet.cpp
|
||
|
|
new file mode 100644
|
||
|
|
index 0000000..cbfb64c
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixOrphanBoundEventsCommandlet.cpp
|
||
|
|
@@ -0,0 +1,200 @@
|
||
|
|
+// Portage UE 5.5 - voir LPFixOrphanBoundEventsCommandlet.h
|
||
|
|
+
|
||
|
|
+#include "LPFixOrphanBoundEventsCommandlet.h"
|
||
|
|
+
|
||
|
|
+#include "AssetRegistry/AssetRegistryModule.h"
|
||
|
|
+#include "EdGraph/EdGraph.h"
|
||
|
|
+#include "EdGraph/EdGraphPin.h"
|
||
|
|
+#include "EdGraphSchema_K2.h"
|
||
|
|
+#include "Engine/Blueprint.h"
|
||
|
|
+#include "K2Node_ComponentBoundEvent.h"
|
||
|
|
+#include "Kismet2/BlueprintEditorUtils.h"
|
||
|
|
+#include "Kismet2/KismetEditorUtilities.h"
|
||
|
|
+#include "Misc/PackageName.h"
|
||
|
|
+#include "UObject/Package.h"
|
||
|
|
+#include "UObject/SavePackage.h"
|
||
|
|
+#include "UObject/UObjectGlobals.h"
|
||
|
|
+
|
||
|
|
+DEFINE_LOG_CATEGORY_STATIC(LogLPFixBoundEvents, Log, All);
|
||
|
|
+
|
||
|
|
+namespace
|
||
|
|
+{
|
||
|
|
+ /**
|
||
|
|
+ * Reproduit le test que le compilateur applique lui-meme : le composant referencE par
|
||
|
|
+ * l'evenement doit exister sous forme de FObjectProperty sur la classe squelette du
|
||
|
|
+ * Blueprint. UK2Node_ComponentBoundEvent::IsDelegateValid() est prive, d'ou la copie.
|
||
|
|
+ */
|
||
|
|
+ bool ComponentStillExists(const UBlueprint* Blueprint, FName ComponentPropertyName)
|
||
|
|
+ {
|
||
|
|
+ if (!Blueprint || ComponentPropertyName.IsNone())
|
||
|
|
+ {
|
||
|
|
+ return false;
|
||
|
|
+ }
|
||
|
|
+ const UClass* Scope = Blueprint->SkeletonGeneratedClass
|
||
|
|
+ ? Blueprint->SkeletonGeneratedClass
|
||
|
|
+ : Blueprint->GeneratedClass;
|
||
|
|
+ return Scope && FindFProperty<FObjectProperty>(Scope, ComponentPropertyName) != nullptr;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /** Compte les noeuds atteignables depuis la broche Exec de sortie de l'evenement. */
|
||
|
|
+ int32 CountDownstreamNodes(const UEdGraphNode* EventNode)
|
||
|
|
+ {
|
||
|
|
+ TSet<const UEdGraphNode*> Seen;
|
||
|
|
+ TArray<const UEdGraphNode*> Pending;
|
||
|
|
+ Pending.Add(EventNode);
|
||
|
|
+ Seen.Add(EventNode);
|
||
|
|
+
|
||
|
|
+ while (Pending.Num() > 0)
|
||
|
|
+ {
|
||
|
|
+ const UEdGraphNode* Current = Pending.Pop();
|
||
|
|
+ for (const UEdGraphPin* Pin : Current->Pins)
|
||
|
|
+ {
|
||
|
|
+ if (!Pin || Pin->Direction != EGPD_Output || Pin->PinType.PinCategory != UEdGraphSchema_K2::PC_Exec)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+ for (const UEdGraphPin* Linked : Pin->LinkedTo)
|
||
|
|
+ {
|
||
|
|
+ const UEdGraphNode* Next = Linked ? Linked->GetOwningNode() : nullptr;
|
||
|
|
+ if (Next && !Seen.Contains(Next))
|
||
|
|
+ {
|
||
|
|
+ Seen.Add(Next);
|
||
|
|
+ Pending.Add(Next);
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ return Seen.Num() - 1; // on ne compte pas l'evenement lui-meme
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+ULPFixOrphanBoundEventsCommandlet::ULPFixOrphanBoundEventsCommandlet()
|
||
|
|
+{
|
||
|
|
+ IsClient = false;
|
||
|
|
+ IsServer = false;
|
||
|
|
+ IsEditor = true;
|
||
|
|
+ LogToConsole = true;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+int32 ULPFixOrphanBoundEventsCommandlet::Main(const FString& Params)
|
||
|
|
+{
|
||
|
|
+ const bool bDryRun = Params.Contains(TEXT("DryRun"), ESearchCase::IgnoreCase);
|
||
|
|
+
|
||
|
|
+ UE_LOG(LogLPFixBoundEvents, Warning, TEXT("=== Evenements de composant orphelins (R-05)%s ==="),
|
||
|
|
+ bDryRun ? TEXT(" [DRY RUN]") : TEXT(""));
|
||
|
|
+
|
||
|
|
+ FAssetRegistryModule& AssetRegistryModule =
|
||
|
|
+ FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
|
||
|
|
+ AssetRegistryModule.Get().SearchAllAssets(true);
|
||
|
|
+
|
||
|
|
+ TArray<FAssetData> BlueprintAssets;
|
||
|
|
+ AssetRegistryModule.Get().GetAssetsByClass(UBlueprint::StaticClass()->GetClassPathName(), BlueprintAssets, true);
|
||
|
|
+
|
||
|
|
+ int32 NodesFound = 0;
|
||
|
|
+ int32 NodesRemoved = 0;
|
||
|
|
+ int32 BlueprintsModified = 0;
|
||
|
|
+ int32 SaveFailures = 0;
|
||
|
|
+
|
||
|
|
+ for (const FAssetData& AssetData : BlueprintAssets)
|
||
|
|
+ {
|
||
|
|
+ if (!AssetData.PackageName.ToString().StartsWith(TEXT("/Game/")))
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ UBlueprint* Blueprint = Cast<UBlueprint>(AssetData.GetAsset());
|
||
|
|
+ if (!Blueprint)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ TArray<UEdGraph*> Graphs;
|
||
|
|
+ Blueprint->GetAllGraphs(Graphs);
|
||
|
|
+
|
||
|
|
+ int32 RemovedHere = 0;
|
||
|
|
+
|
||
|
|
+ for (UEdGraph* Graph : Graphs)
|
||
|
|
+ {
|
||
|
|
+ if (!Graph)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ TArray<UEdGraphNode*> Snapshot = Graph->Nodes;
|
||
|
|
+ for (UEdGraphNode* GraphNode : Snapshot)
|
||
|
|
+ {
|
||
|
|
+ UK2Node_ComponentBoundEvent* BoundEvent = Cast<UK2Node_ComponentBoundEvent>(GraphNode);
|
||
|
|
+ if (!BoundEvent)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ const FName ComponentName = BoundEvent->GetComponentPropertyName();
|
||
|
|
+ if (ComponentStillExists(Blueprint, ComponentName))
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ ++NodesFound;
|
||
|
|
+ const int32 Downstream = CountDownstreamNodes(BoundEvent);
|
||
|
|
+ UE_LOG(LogLPFixBoundEvents, Warning,
|
||
|
|
+ TEXT(" %s :: %s -> %s (composant '%s' introuvable, %d noeud(s) en aval)"),
|
||
|
|
+ *Blueprint->GetName(), *Graph->GetName(), *GraphNode->GetName(),
|
||
|
|
+ *ComponentName.ToString(), Downstream);
|
||
|
|
+
|
||
|
|
+ if (bDryRun)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ Graph->Modify();
|
||
|
|
+ BoundEvent->Modify();
|
||
|
|
+ BoundEvent->DestroyNode();
|
||
|
|
+ ++NodesRemoved;
|
||
|
|
+ ++RemovedHere;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (RemovedHere > 0 && !bDryRun)
|
||
|
|
+ {
|
||
|
|
+ ++BlueprintsModified;
|
||
|
|
+ FBlueprintEditorUtils::MarkBlueprintAsStructurallyModified(Blueprint);
|
||
|
|
+ FKismetEditorUtilities::CompileBlueprint(Blueprint);
|
||
|
|
+
|
||
|
|
+ UPackage* Package = Blueprint->GetOutermost();
|
||
|
|
+ FString Filename;
|
||
|
|
+ if (!FPackageName::TryConvertLongPackageNameToFilename(
|
||
|
|
+ Package->GetName(), Filename, FPackageName::GetAssetPackageExtension()))
|
||
|
|
+ {
|
||
|
|
+ ++SaveFailures;
|
||
|
|
+ UE_LOG(LogLPFixBoundEvents, Error, TEXT(" chemin introuvable pour %s"), *Package->GetName());
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ ResetLoaders(Package);
|
||
|
|
+
|
||
|
|
+ FSavePackageArgs SaveArgs;
|
||
|
|
+ SaveArgs.TopLevelFlags = RF_Public | RF_Standalone;
|
||
|
|
+ SaveArgs.SaveFlags = SAVE_None;
|
||
|
|
+ SaveArgs.bWarnOfLongFilename = true;
|
||
|
|
+ SaveArgs.Error = GWarn;
|
||
|
|
+
|
||
|
|
+ if (UPackage::SavePackage(Package, nullptr, *Filename, SaveArgs))
|
||
|
|
+ {
|
||
|
|
+ UE_LOG(LogLPFixBoundEvents, Warning, TEXT(" -> %s sauvegarde (%d evenement(s) retire(s))."),
|
||
|
|
+ *Package->GetName(), RemovedHere);
|
||
|
|
+ }
|
||
|
|
+ else
|
||
|
|
+ {
|
||
|
|
+ ++SaveFailures;
|
||
|
|
+ UE_LOG(LogLPFixBoundEvents, Error, TEXT(" -> ECHEC de sauvegarde de %s"), *Package->GetName());
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ UE_LOG(LogLPFixBoundEvents, Warning,
|
||
|
|
+ TEXT("=== Termine : %d evenement(s) orphelin(s) trouve(s), %d retire(s) dans %d Blueprint(s), %d echec(s) de sauvegarde. ==="),
|
||
|
|
+ NodesFound, NodesRemoved, BlueprintsModified, SaveFailures);
|
||
|
|
+
|
||
|
|
+ return SaveFailures > 0 ? 1 : 0;
|
||
|
|
+}
|
||
|
|
diff --git a/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixOrphanBoundEventsCommandlet.h b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixOrphanBoundEventsCommandlet.h
|
||
|
|
new file mode 100644
|
||
|
|
index 0000000..7bf014a
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixOrphanBoundEventsCommandlet.h
|
||
|
|
@@ -0,0 +1,31 @@
|
||
|
|
+// Portage UE 5.5 (2026.9 beta) - remediation R-05.
|
||
|
|
+//
|
||
|
|
+// Trois evenements « On Clicked » restent lies a des widgets qui n'existent plus dans l'arbre
|
||
|
|
+// de leur Blueprint (UI/TopRight::StatButtonL, UI/CharGen::ButtonPreviewErect et
|
||
|
|
+// ButtonEyelashColor). Le compilateur emet « n'a pas de composant correspondant valide ! » et
|
||
|
|
+// le delegue n'est jamais branche : le clic est deja mort a l'execution.
|
||
|
|
+//
|
||
|
|
+// Cette commandlet repere ces UK2Node_ComponentBoundEvent orphelins et les supprime. Les
|
||
|
|
+// noeuds situes en aval sont CONSERVES tels quels : ils deviennent simplement inatteignables,
|
||
|
|
+// ce qui n'a aucun effet a l'execution mais laisse la logique visible pour qui voudrait
|
||
|
|
+// recreer le widget manquant. Le rapport indique combien de noeuds passent dans ce cas.
|
||
|
|
+//
|
||
|
|
+// Usage :
|
||
|
|
+// UnrealEditor-Cmd.exe <chemin>\LifePlay.uproject -run=LPFixOrphanBoundEvents [-DryRun]
|
||
|
|
+
|
||
|
|
+#pragma once
|
||
|
|
+
|
||
|
|
+#include "CoreMinimal.h"
|
||
|
|
+#include "Commandlets/Commandlet.h"
|
||
|
|
+#include "LPFixOrphanBoundEventsCommandlet.generated.h"
|
||
|
|
+
|
||
|
|
+UCLASS()
|
||
|
|
+class ULPFixOrphanBoundEventsCommandlet : public UCommandlet
|
||
|
|
+{
|
||
|
|
+ GENERATED_BODY()
|
||
|
|
+
|
||
|
|
+public:
|
||
|
|
+ ULPFixOrphanBoundEventsCommandlet();
|
||
|
|
+
|
||
|
|
+ virtual int32 Main(const FString& Params) override;
|
||
|
|
+};
|
||
|
|
diff --git a/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixZeroScaleActorsCommandlet.cpp b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixZeroScaleActorsCommandlet.cpp
|
||
|
|
new file mode 100644
|
||
|
|
index 0000000..c1d5e9c
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixZeroScaleActorsCommandlet.cpp
|
||
|
|
@@ -0,0 +1,223 @@
|
||
|
|
+// Portage UE 5.5 - voir LPFixZeroScaleActorsCommandlet.h
|
||
|
|
+
|
||
|
|
+#include "LPFixZeroScaleActorsCommandlet.h"
|
||
|
|
+
|
||
|
|
+#include "AssetRegistry/AssetRegistryModule.h"
|
||
|
|
+#include "Components/SceneComponent.h"
|
||
|
|
+#include "Components/PrimitiveComponent.h"
|
||
|
|
+#include "Components/StaticMeshComponent.h"
|
||
|
|
+#include "Engine/StaticMesh.h"
|
||
|
|
+#include "Engine/World.h"
|
||
|
|
+#include "GameFramework/Actor.h"
|
||
|
|
+#include "Misc/PackageName.h"
|
||
|
|
+#include "UObject/Package.h"
|
||
|
|
+#include "UObject/SavePackage.h"
|
||
|
|
+#include "UObject/UObjectGlobals.h"
|
||
|
|
+
|
||
|
|
+DEFINE_LOG_CATEGORY_STATIC(LogLPFixZeroScale, Log, All);
|
||
|
|
+
|
||
|
|
+namespace
|
||
|
|
+{
|
||
|
|
+ /** Seuil du moteur : FMath::IsNearlyZero sur chaque composante avant creation du body. */
|
||
|
|
+ constexpr double ZeroScaleTolerance = UE_KINDA_SMALL_NUMBER;
|
||
|
|
+
|
||
|
|
+ /** Decrit le maillage porte par un composant, pour pouvoir juger de la valeur a remettre. */
|
||
|
|
+ FString DescribeMesh(const USceneComponent* Component)
|
||
|
|
+ {
|
||
|
|
+ const UStaticMeshComponent* MeshComponent = Cast<UStaticMeshComponent>(Component);
|
||
|
|
+ if (!MeshComponent || !MeshComponent->GetStaticMesh())
|
||
|
|
+ {
|
||
|
|
+ return TEXT("(pas de maillage statique)");
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ const UStaticMesh* Mesh = MeshComponent->GetStaticMesh();
|
||
|
|
+ const FBoxSphereBounds Bounds = Mesh->GetBounds();
|
||
|
|
+ return FString::Printf(TEXT("%s demi-dimensions locales (X=%.2f Y=%.2f Z=%.2f)"),
|
||
|
|
+ *Mesh->GetPathName(),
|
||
|
|
+ Bounds.BoxExtent.X, Bounds.BoxExtent.Y, Bounds.BoxExtent.Z);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /**
|
||
|
|
+ * Visibilite et collision : ce sont elles qui dictent la valeur de remplacement.
|
||
|
|
+ * Un bloqueur invisible tolere une epaisseur quelconque ; un mur visible non.
|
||
|
|
+ */
|
||
|
|
+ FString DescribeRendering(const USceneComponent* Component)
|
||
|
|
+ {
|
||
|
|
+ const UPrimitiveComponent* Primitive = Cast<UPrimitiveComponent>(Component);
|
||
|
|
+ if (!Primitive)
|
||
|
|
+ {
|
||
|
|
+ return TEXT("(pas un composant primitif)");
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ const UEnum* CollisionEnum = StaticEnum<ECollisionEnabled::Type>();
|
||
|
|
+ const ECollisionEnabled::Type Collision = Primitive->GetCollisionEnabled();
|
||
|
|
+
|
||
|
|
+ return FString::Printf(TEXT("visible=%s cacheEnJeu=%s collision=%s profil=%s"),
|
||
|
|
+ Primitive->IsVisible() ? TEXT("oui") : TEXT("NON"),
|
||
|
|
+ Primitive->bHiddenInGame ? TEXT("oui") : TEXT("non"),
|
||
|
|
+ CollisionEnum ? *CollisionEnum->GetNameStringByValue(static_cast<int64>(Collision)) : TEXT("?"),
|
||
|
|
+ *Primitive->GetCollisionProfileName().ToString());
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+ULPFixZeroScaleActorsCommandlet::ULPFixZeroScaleActorsCommandlet()
|
||
|
|
+{
|
||
|
|
+ IsClient = false;
|
||
|
|
+ IsServer = false;
|
||
|
|
+ IsEditor = true;
|
||
|
|
+ LogToConsole = true;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+int32 ULPFixZeroScaleActorsCommandlet::Main(const FString& Params)
|
||
|
|
+{
|
||
|
|
+ TArray<FString> Tokens;
|
||
|
|
+ TArray<FString> Switches;
|
||
|
|
+ TMap<FString, FString> ParamsMap;
|
||
|
|
+ ParseCommandLine(*Params, Tokens, Switches, ParamsMap);
|
||
|
|
+
|
||
|
|
+ const bool bFix = Switches.Contains(TEXT("Fix"));
|
||
|
|
+ double Replacement = 1.0;
|
||
|
|
+ if (const FString* ScaleText = ParamsMap.Find(TEXT("Scale")))
|
||
|
|
+ {
|
||
|
|
+ Replacement = FCString::Atod(**ScaleText);
|
||
|
|
+ }
|
||
|
|
+ // Garde-fou volontaire : PowerShell coupe « -Scale=0.1 » en deux arguments si on ne le
|
||
|
|
+ // guillemette pas, et la commandlet recevrait alors 0 sans rien dire. Voir l'en-tete.
|
||
|
|
+ if (bFix && FMath::IsNearlyZero(Replacement, ZeroScaleTolerance))
|
||
|
|
+ {
|
||
|
|
+ UE_LOG(LogLPFixZeroScale, Error,
|
||
|
|
+ TEXT("-Scale lu a %f : valeur nulle ou argument coupe par le shell. Guillemettez \"-Scale=0.1\"."),
|
||
|
|
+ Replacement);
|
||
|
|
+ return 1;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ UE_LOG(LogLPFixZeroScale, Warning, TEXT("=== Composantes d'echelle nulles (R-06)%s ==="),
|
||
|
|
+ bFix ? *FString::Printf(TEXT(" [CORRECTION -> %.4f]"), Replacement) : TEXT(" [RAPPORT SEUL]"));
|
||
|
|
+
|
||
|
|
+ FAssetRegistryModule& AssetRegistryModule =
|
||
|
|
+ FModuleManager::LoadModuleChecked<FAssetRegistryModule>(TEXT("AssetRegistry"));
|
||
|
|
+ AssetRegistryModule.Get().SearchAllAssets(true);
|
||
|
|
+
|
||
|
|
+ TArray<FAssetData> MapAssets;
|
||
|
|
+ AssetRegistryModule.Get().GetAssetsByClass(UWorld::StaticClass()->GetClassPathName(), MapAssets, true);
|
||
|
|
+
|
||
|
|
+ int32 ComponentsFound = 0;
|
||
|
|
+ int32 ComponentsFixed = 0;
|
||
|
|
+ int32 MapsModified = 0;
|
||
|
|
+ int32 SaveFailures = 0;
|
||
|
|
+
|
||
|
|
+ for (const FAssetData& AssetData : MapAssets)
|
||
|
|
+ {
|
||
|
|
+ const FString PackageName = AssetData.PackageName.ToString();
|
||
|
|
+ if (!PackageName.StartsWith(TEXT("/Game/")))
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ UPackage* Package = LoadPackage(nullptr, *PackageName, LOAD_None);
|
||
|
|
+ UWorld* World = Package ? UWorld::FindWorldInPackage(Package) : nullptr;
|
||
|
|
+ if (!World || !World->PersistentLevel)
|
||
|
|
+ {
|
||
|
|
+ UE_LOG(LogLPFixZeroScale, Warning, TEXT(" %s : monde illisible, ignore."), *PackageName);
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ int32 FixedHere = 0;
|
||
|
|
+
|
||
|
|
+ for (AActor* Actor : World->PersistentLevel->Actors)
|
||
|
|
+ {
|
||
|
|
+ if (!Actor)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ TArray<USceneComponent*> Components;
|
||
|
|
+ Actor->GetComponents<USceneComponent>(Components);
|
||
|
|
+
|
||
|
|
+ for (USceneComponent* Component : Components)
|
||
|
|
+ {
|
||
|
|
+ if (!Component)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ FVector Scale = Component->GetRelativeScale3D();
|
||
|
|
+ const bool bZeroX = FMath::IsNearlyZero(Scale.X, ZeroScaleTolerance);
|
||
|
|
+ const bool bZeroY = FMath::IsNearlyZero(Scale.Y, ZeroScaleTolerance);
|
||
|
|
+ const bool bZeroZ = FMath::IsNearlyZero(Scale.Z, ZeroScaleTolerance);
|
||
|
|
+ if (!bZeroX && !bZeroY && !bZeroZ)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ ++ComponentsFound;
|
||
|
|
+ UE_LOG(LogLPFixZeroScale, Warning, TEXT(" %s : %s.%s"),
|
||
|
|
+ *PackageName, *Actor->GetName(), *Component->GetName());
|
||
|
|
+ UE_LOG(LogLPFixZeroScale, Warning, TEXT(" echelle : X=%.4f Y=%.4f Z=%.4f"),
|
||
|
|
+ Scale.X, Scale.Y, Scale.Z);
|
||
|
|
+ UE_LOG(LogLPFixZeroScale, Warning, TEXT(" maillage : %s"), *DescribeMesh(Component));
|
||
|
|
+ UE_LOG(LogLPFixZeroScale, Warning, TEXT(" rendu : %s"), *DescribeRendering(Component));
|
||
|
|
+
|
||
|
|
+ if (!bFix)
|
||
|
|
+ {
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (bZeroX) { Scale.X = Replacement; }
|
||
|
|
+ if (bZeroY) { Scale.Y = Replacement; }
|
||
|
|
+ if (bZeroZ) { Scale.Z = Replacement; }
|
||
|
|
+
|
||
|
|
+ Actor->Modify();
|
||
|
|
+ Component->Modify();
|
||
|
|
+ Component->SetRelativeScale3D(Scale);
|
||
|
|
+ Component->MarkRenderStateDirty();
|
||
|
|
+ // Recalcule le corps physique avec la nouvelle echelle.
|
||
|
|
+ Component->RecreatePhysicsState();
|
||
|
|
+
|
||
|
|
+ UE_LOG(LogLPFixZeroScale, Warning, TEXT(" -> X=%.4f Y=%.4f Z=%.4f"),
|
||
|
|
+ Scale.X, Scale.Y, Scale.Z);
|
||
|
|
+
|
||
|
|
+ ++ComponentsFixed;
|
||
|
|
+ ++FixedHere;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (FixedHere > 0)
|
||
|
|
+ {
|
||
|
|
+ ++MapsModified;
|
||
|
|
+
|
||
|
|
+ FString Filename;
|
||
|
|
+ if (!FPackageName::TryConvertLongPackageNameToFilename(
|
||
|
|
+ PackageName, Filename, FPackageName::GetMapPackageExtension()))
|
||
|
|
+ {
|
||
|
|
+ ++SaveFailures;
|
||
|
|
+ UE_LOG(LogLPFixZeroScale, Error, TEXT(" chemin introuvable pour %s"), *PackageName);
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ Package->MarkPackageDirty();
|
||
|
|
+
|
||
|
|
+ FSavePackageArgs SaveArgs;
|
||
|
|
+ SaveArgs.TopLevelFlags = RF_Public | RF_Standalone;
|
||
|
|
+ SaveArgs.SaveFlags = SAVE_None;
|
||
|
|
+ SaveArgs.bWarnOfLongFilename = true;
|
||
|
|
+ SaveArgs.Error = GWarn;
|
||
|
|
+
|
||
|
|
+ if (UPackage::SavePackage(Package, World, *Filename, SaveArgs))
|
||
|
|
+ {
|
||
|
|
+ UE_LOG(LogLPFixZeroScale, Warning, TEXT(" -> %s sauvegarde (%d composant(s))."), *PackageName, FixedHere);
|
||
|
|
+ }
|
||
|
|
+ else
|
||
|
|
+ {
|
||
|
|
+ ++SaveFailures;
|
||
|
|
+ UE_LOG(LogLPFixZeroScale, Error, TEXT(" -> ECHEC de sauvegarde de %s"), *PackageName);
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ UE_LOG(LogLPFixZeroScale, Warning,
|
||
|
|
+ TEXT("=== Termine : %d composant(s) a echelle nulle, %d corrige(s) dans %d carte(s), %d echec(s) de sauvegarde. ==="),
|
||
|
|
+ ComponentsFound, ComponentsFixed, MapsModified, SaveFailures);
|
||
|
|
+
|
||
|
|
+ return SaveFailures > 0 ? 1 : 0;
|
||
|
|
+}
|
||
|
|
diff --git a/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixZeroScaleActorsCommandlet.h b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixZeroScaleActorsCommandlet.h
|
||
|
|
new file mode 100644
|
||
|
|
index 0000000..975b6a8
|
||
|
|
--- /dev/null
|
||
|
|
+++ b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LPFixZeroScaleActorsCommandlet.h
|
||
|
|
@@ -0,0 +1,39 @@
|
||
|
|
+// Portage UE 5.5 (2026.9 beta) - remediation R-06.
|
||
|
|
+//
|
||
|
|
+// /Game/Scenes/CentralLondon:PersistentLevel.Wall.StaticMeshComponent0 porte une echelle
|
||
|
|
+// (X=0.000, Y=12.562, Z=5.750). Une composante nulle produit un corps physique degenere :
|
||
|
|
+// le moteur emet « has a component set to zero, which will result in a bad body instance »
|
||
|
|
+// a chaque cook, un MapCheck: Error, et l'inversion de la matrice de transformation declenche
|
||
|
|
+// un ensure « TMatrix::InverseFast() ... results in NaNs » en session d'edition.
|
||
|
|
+//
|
||
|
|
+// La commandlet parcourt les cartes de /Game/, signale toute composante d'echelle nulle avec
|
||
|
|
+// le maillage concerne et ses dimensions (pour pouvoir juger de la valeur de remplacement),
|
||
|
|
+// puis corrige si on le lui demande.
|
||
|
|
+//
|
||
|
|
+// Usage :
|
||
|
|
+// UnrealEditor-Cmd.exe <projet> -run=LPFixZeroScaleActors (rapport seul)
|
||
|
|
+// UnrealEditor-Cmd.exe <projet> -run=LPFixZeroScaleActors -Fix [-Scale=1.0]
|
||
|
|
+//
|
||
|
|
+// ATTENTION sous PowerShell : « -Scale=0.1 » non guillemete est coupe en « -Scale=0 » et
|
||
|
|
+// « .1 », la commandlet recevrait 0. Ecrire "-Scale=0.1". Le garde-fou sur la valeur nulle
|
||
|
|
+// est la pour attraper le cas.
|
||
|
|
+//
|
||
|
|
+// Le rapport est le mode par defaut : contrairement aux autres commandlets du projet, la
|
||
|
|
+// valeur de remplacement est un choix de niveau, pas une equivalence mecanique.
|
||
|
|
+
|
||
|
|
+#pragma once
|
||
|
|
+
|
||
|
|
+#include "CoreMinimal.h"
|
||
|
|
+#include "Commandlets/Commandlet.h"
|
||
|
|
+#include "LPFixZeroScaleActorsCommandlet.generated.h"
|
||
|
|
+
|
||
|
|
+UCLASS()
|
||
|
|
+class ULPFixZeroScaleActorsCommandlet : public UCommandlet
|
||
|
|
+{
|
||
|
|
+ GENERATED_BODY()
|
||
|
|
+
|
||
|
|
+public:
|
||
|
|
+ ULPFixZeroScaleActorsCommandlet();
|
||
|
|
+
|
||
|
|
+ virtual int32 Main(const FString& Params) override;
|
||
|
|
+};
|
||
|
|
diff --git a/D:/Game/LifePlay-master 4.27/Source/LifePlayEditorTools/LifePlayEditorTools.Build.cs b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LifePlayEditorTools.Build.cs
|
||
|
|
index 438d0c9..da7afda 100644
|
||
|
|
--- a/D:/Game/LifePlay-master 4.27/Source/LifePlayEditorTools/LifePlayEditorTools.Build.cs
|
||
|
|
+++ b/D:/Game/LifePlay-master 5.5/Source/LifePlayEditorTools/LifePlayEditorTools.Build.cs
|
||
|
|
@@ -21,7 +21,19 @@ public class LifePlayEditorTools : ModuleRules
|
||
|
|
"UnrealEd",
|
||
|
|
"BlueprintGraph",
|
||
|
|
"KismetCompiler",
|
||
|
|
- "AssetRegistry"
|
||
|
|
+ "AssetRegistry",
|
||
|
|
+ // Portage 5.5 : LPCheckStreetMapCommandlet lit les assets UStreetMap
|
||
|
|
+ "StreetMapRuntime",
|
||
|
|
+ // Portage 5.5 : LPFixEditableTextBoxFontCommandlet manipule
|
||
|
|
+ // FEditableTextBoxStyle et FTextBlockStyle
|
||
|
|
+ "SlateCore",
|
||
|
|
+ // Portage 5.5 (R-04) : LPFixDeprecatedNodesCommandlet reference
|
||
|
|
+ // UNavigationSystemV1 pour identifier les noeuds a reaiguiller
|
||
|
|
+ "NavigationSystem",
|
||
|
|
+ // Portage 5.5 (R-05) : LPFixOrphanBoundEventsCommandlet traite les
|
||
|
|
+ // UWidgetBlueprint au meme titre que les UBlueprint
|
||
|
|
+ "UMG",
|
||
|
|
+ "UMGEditor"
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|