You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
FStructUtilsEditorModule::StartupModule is not called for commandlets, and so this resulted in the custom localization gather callback being missing for FInstancedStruct. This caused an issue for the localization commandlet (which fixed it by loading the module directly), but still left other commandlets with the issue, and could mean that things like resaving packages could generate an incomplete localization cache. This change removes the special fix for the localization commandlet, and instead has the CoreUObject module (which now owns FInstancedStruct) directly register the custom localization gather callback during initialization. [FYI] Leon.Huang #rb Rex.Hill #rnx [CL 35351349 by jamie dale in ue5-main branch]
150 lines
5.7 KiB
C++
150 lines
5.7 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "StructUtilsEditorModule.h"
|
|
#include "CoreGlobals.h"
|
|
#include "GameFramework/Actor.h"
|
|
#include "Modules/ModuleManager.h"
|
|
#include "PropertyBagDetails.h"
|
|
#include "PropertyEditorModule.h"
|
|
#include "StructUtils/InstancedStruct.h"
|
|
#include "StructUtils/InstancedStructContainer.h"
|
|
#include "StructUtils/UserDefinedStruct.h"
|
|
#include "StructUtilsDelegates.h"
|
|
#include "UObject/Package.h"
|
|
#include "UObject/UObjectGlobals.h"
|
|
#include "UObject/UObjectIterator.h"
|
|
#include "UserDefinedStructure/UserDefinedStructEditorData.h"
|
|
|
|
#define LOCTEXT_NAMESPACE "StructUtilsEditor"
|
|
|
|
IMPLEMENT_MODULE(FStructUtilsEditorModule, StructUtilsEditor)
|
|
|
|
void FStructUtilsEditorModule::StartupModule()
|
|
{
|
|
// Register the details customizer
|
|
FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");
|
|
PropertyModule.RegisterCustomPropertyTypeLayout("InstancedStruct", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FInstancedStructDetails::MakeInstance));
|
|
PropertyModule.RegisterCustomPropertyTypeLayout("InstancedPropertyBag", FOnGetPropertyTypeCustomizationInstance::CreateStatic(&FPropertyBagDetails::MakeInstance));
|
|
PropertyModule.NotifyCustomizationModuleChanged();
|
|
}
|
|
|
|
void FStructUtilsEditorModule::ShutdownModule()
|
|
{
|
|
// Unregister the details customization
|
|
if (FModuleManager::Get().IsModuleLoaded("PropertyEditor"))
|
|
{
|
|
FPropertyEditorModule& PropertyModule = FModuleManager::LoadModuleChecked<FPropertyEditorModule>("PropertyEditor");
|
|
PropertyModule.UnregisterCustomPropertyTypeLayout("InstancedStruct");
|
|
PropertyModule.UnregisterCustomPropertyTypeLayout("InstancedPropertyBag");
|
|
PropertyModule.NotifyCustomizationModuleChanged();
|
|
}
|
|
}
|
|
|
|
namespace UE::StructUtils::Private
|
|
{
|
|
|
|
static void VisitReferencedObjects(const UUserDefinedStruct* StructToReinstantiate)
|
|
{
|
|
// Helper preference collector, does not collect anything, but makes sure AddStructReferencedObjects() gets called e.g. on instanced struct.
|
|
class FVisitorReferenceCollector : public FReferenceCollector
|
|
{
|
|
public:
|
|
virtual bool IsIgnoringArchetypeRef() const override { return false; }
|
|
virtual bool IsIgnoringTransient() const override { return false; }
|
|
|
|
virtual void HandleObjectReference(UObject*& Object, const UObject* ReferencingObject, const FProperty* ReferencingProperty) override
|
|
{
|
|
// Empty
|
|
}
|
|
};
|
|
|
|
FVisitorReferenceCollector Collector;
|
|
|
|
// This sets global variable which read in the AddStructReferencedObjects().
|
|
FStructureToReinstantiateScope StructureToReinstantiateScope(StructToReinstantiate);
|
|
|
|
for (TObjectIterator<UObject> ObjectIt; ObjectIt; ++ObjectIt)
|
|
{
|
|
UObject* Object = *ObjectIt;
|
|
|
|
// This sets global variable which read in the AddStructReferencedObjects().
|
|
FCurrentReinstantiationOuterObjectScope CurrentReinstantiateOuterObjectScope(Object);
|
|
|
|
Collector.AddPropertyReferencesWithStructARO(Object->GetClass(), Object);
|
|
}
|
|
|
|
// Handle CDOs and sparse class data
|
|
for (TObjectIterator<UClass> ClassIt; ClassIt; ++ClassIt)
|
|
{
|
|
UClass* Class = *ClassIt;
|
|
|
|
// Handle Sparse class data
|
|
if (void* SparseData = const_cast<void*>(Class->GetSparseClassData(EGetSparseClassDataMethod::ReturnIfNull)))
|
|
{
|
|
FCurrentReinstantiationOuterObjectScope CurrentReinstantiateOuterObjectScope(Class);
|
|
const UScriptStruct* SparseDataStruct = Class->GetSparseClassDataStruct();
|
|
Collector.AddPropertyReferencesWithStructARO(SparseDataStruct, SparseData);
|
|
}
|
|
|
|
// Handle CDO
|
|
if (UObject* CDO = Class->GetDefaultObject())
|
|
{
|
|
FCurrentReinstantiationOuterObjectScope CurrentReinstantiateOuterObjectScope(CDO);
|
|
Collector.AddPropertyReferencesWithStructARO(Class, CDO);
|
|
}
|
|
}
|
|
}
|
|
|
|
} // UE::StructUtils::Private
|
|
|
|
void FStructUtilsEditorModule::PreChange(const UUserDefinedStruct* StructToReinstantiate, FStructureEditorUtils::EStructureEditorChangeInfo Info)
|
|
{
|
|
if (!StructToReinstantiate)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Make a duplicate of the existing struct, and point all instances of the struct to point to the duplicate.
|
|
// This is done because the original struct will be changed.
|
|
UUserDefinedStruct* DuplicatedStruct = nullptr;
|
|
{
|
|
const FString ReinstantiatedName = FString::Printf(TEXT("STRUCT_REINST_%s"), *StructToReinstantiate->GetName());
|
|
const FName UniqueName = MakeUniqueObjectName(GetTransientPackage(), UUserDefinedStruct::StaticClass(), FName(*ReinstantiatedName));
|
|
|
|
TGuardValue<FIsDuplicatingClassForReinstancing, bool> IsDuplicatingClassForReinstancing(GIsDuplicatingClassForReinstancing, true);
|
|
DuplicatedStruct = (UUserDefinedStruct*)StaticDuplicateObject(StructToReinstantiate, GetTransientPackage(), UniqueName, ~RF_Transactional);
|
|
|
|
DuplicatedStruct->Guid = StructToReinstantiate->Guid;
|
|
DuplicatedStruct->Bind();
|
|
DuplicatedStruct->StaticLink(true);
|
|
DuplicatedStruct->PrimaryStruct = const_cast<UUserDefinedStruct*>(StructToReinstantiate);
|
|
DuplicatedStruct->Status = EUserDefinedStructureStatus::UDSS_Duplicate;
|
|
DuplicatedStruct->SetFlags(RF_Transient);
|
|
DuplicatedStruct->AddToRoot();
|
|
}
|
|
|
|
UUserDefinedStructEditorData* DuplicatedEditorData = CastChecked<UUserDefinedStructEditorData>(DuplicatedStruct->EditorData);
|
|
DuplicatedEditorData->RecreateDefaultInstance();
|
|
|
|
UE::StructUtils::Private::VisitReferencedObjects(DuplicatedStruct);
|
|
|
|
DuplicatedStruct->RemoveFromRoot();
|
|
}
|
|
|
|
void FStructUtilsEditorModule::PostChange(const UUserDefinedStruct* StructToReinstantiate, FStructureEditorUtils::EStructureEditorChangeInfo Info)
|
|
{
|
|
if (!StructToReinstantiate)
|
|
{
|
|
return;
|
|
}
|
|
|
|
UE::StructUtils::Private::VisitReferencedObjects(StructToReinstantiate);
|
|
|
|
if (UE::StructUtils::Delegates::OnUserDefinedStructReinstanced.IsBound())
|
|
{
|
|
UE::StructUtils::Delegates::OnUserDefinedStructReinstanced.Broadcast(*StructToReinstantiate);
|
|
}
|
|
}
|
|
|
|
#undef LOCTEXT_NAMESPACE
|