void UUnrealEdEngine::GetPackageList( TArray<UPackage*>* InPackages, UClass* InClass ) { InPackages->Empty(); for( FObjectIterator It ; It ; ++It ) { if( It->GetOuter() && It->GetOuter() != GetTransientPackage() ) { UObject* TopParent = NULL; if( InClass == NULL || It->IsA( InClass ) ) TopParent = It->GetOutermost(); if( Cast<UPackage>(TopParent) ) InPackages->AddUnique( (UPackage*)TopParent ); } } }
void FEnumEditorUtils::BroadcastChanges(const UUserDefinedEnum* Enum, const TArray<TPair<FName, int8>>& OldNames, bool bResolveData) { check(NULL != Enum); if (bResolveData) { FArchiveEnumeratorResolver EnumeratorResolver(Enum, OldNames); TArray<UClass*> ClassesToCheck; for (TObjectIterator<UByteProperty> PropertyIter; PropertyIter; ++PropertyIter) { const UByteProperty* ByteProperty = *PropertyIter; if (ByteProperty && (Enum == ByteProperty->GetIntPropertyEnum())) { UClass* OwnerClass = ByteProperty->GetOwnerClass(); if (OwnerClass) { ClassesToCheck.Add(OwnerClass); } } } for (FObjectIterator ObjIter; ObjIter; ++ObjIter) { for (auto ClassIter = ClassesToCheck.CreateConstIterator(); ClassIter; ++ClassIter) { if (ObjIter->IsA(*ClassIter)) { ObjIter->Serialize(EnumeratorResolver); break; } } } } struct FNodeValidatorHelper { static bool IsValid(UK2Node* Node) { return Node && (NULL != Cast<UEdGraph>(Node->GetOuter())) && !Node->HasAnyFlags(RF_Transient | RF_PendingKill); } }; TSet<UBlueprint*> BlueprintsToRefresh; { //CUSTOM NODES DEPENTENT ON ENUM for (TObjectIterator<UK2Node> It(RF_Transient); It; ++It) { UK2Node* Node = *It; INodeDependingOnEnumInterface* NodeDependingOnEnum = Cast<INodeDependingOnEnumInterface>(Node); if (FNodeValidatorHelper::IsValid(Node) && NodeDependingOnEnum && (Enum == NodeDependingOnEnum->GetEnum())) { if (UBlueprint* Blueprint = Node->GetBlueprint()) { if (NodeDependingOnEnum->ShouldBeReconstructedAfterEnumChanged()) { Node->ReconstructNode(); } BlueprintsToRefresh.Add(Blueprint); } } } } for (TObjectIterator<UEdGraphPin> It(RF_Transient); It; ++It) { UEdGraphPin* Pin = *It; if (Pin && (Enum == Pin->PinType.PinSubCategoryObject.Get()) && (EEdGraphPinDirection::EGPD_Input == Pin->Direction)) { UK2Node* Node = Cast<UK2Node>(Pin->GetOuter()); if (FNodeValidatorHelper::IsValid(Node)) { if (UBlueprint* Blueprint = Node->GetBlueprint()) { if (INDEX_NONE == Enum->FindEnumIndex(*Pin->DefaultValue)) { Pin->Modify(); if (Blueprint->BlueprintType == BPTYPE_Interface) { Pin->DefaultValue = Enum->GetEnumName(0); } else { Pin->DefaultValue = FEnumEditorUtilsHelper::InvalidName(); } Node->PinDefaultValueChanged(Pin); BlueprintsToRefresh.Add(Blueprint); } } } } } for (auto It = BlueprintsToRefresh.CreateIterator(); It; ++It) { FBlueprintEditorUtils::MarkBlueprintAsModified(*It); (*It)->BroadcastChanged(); } FEnumEditorManager::Get().PostChange(Enum, EEnumEditorChangeInfo::Changed); }
bool UOnlineHotfixManager::HotfixIniFile(const FString& FileName, const FString& IniData) { FConfigFile* ConfigFile = GetConfigFile(FileName); // Merge the string into the config file ConfigFile->CombineFromBuffer(IniData); TArray<UClass*> Classes; TArray<UObject*> PerObjectConfigObjects; int32 StartIndex = 0; int32 EndIndex = 0; // Find the set of object classes that were affected while (StartIndex >= 0 && StartIndex < IniData.Len() && EndIndex >= StartIndex) { // Find the next section header StartIndex = IniData.Find(TEXT("["), ESearchCase::IgnoreCase, ESearchDir::FromStart, StartIndex); if (StartIndex > -1) { // Find the ending section identifier EndIndex = IniData.Find(TEXT("]"), ESearchCase::IgnoreCase, ESearchDir::FromStart, StartIndex); if (EndIndex > StartIndex) { int32 PerObjectNameIndex = IniData.Find(TEXT(" "), ESearchCase::IgnoreCase, ESearchDir::FromStart, StartIndex); // Per object config entries will have a space in the name, but classes won't if (PerObjectNameIndex == -1 || PerObjectNameIndex > EndIndex) { if (IniData.StartsWith(TEXT("[/Script/"), ESearchCase::IgnoreCase)) { const int32 ScriptSectionTag = 9; // Snip the text out and try to find the class for that const FString PackageClassName = IniData.Mid(StartIndex + ScriptSectionTag, EndIndex - StartIndex - ScriptSectionTag); // Find the class for this so we know what to update UClass* Class = FindObject<UClass>(nullptr, *PackageClassName, true); if (Class) { // Add this to the list to check against Classes.Add(Class); } } } // Handle the per object config case by finding the object for reload else { const int32 Count = PerObjectNameIndex - StartIndex - 1; const FString PerObjectName = IniData.Mid(StartIndex + 1, Count); // Explicitly search the transient package (won't update non-transient objects) UObject* PerObject = FindObject<UObject>(ANY_PACKAGE, *PerObjectName, false); if (PerObject != nullptr) { PerObjectConfigObjects.Add(PerObject); } } StartIndex = EndIndex; } } } int32 NumObjectsReloaded = 0; const double StartTime = FPlatformTime::Seconds(); if (Classes.Num()) { // Now that we have a list of classes to update, we can iterate objects and reload for (FObjectIterator It; It; ++It) { UClass* Class = It->GetClass(); if (Class->HasAnyClassFlags(CLASS_Config)) { // Check to see if this class is in our list (yes, potentially n^2, but not in practice) for (int32 ClassIndex = 0; ClassIndex < Classes.Num(); ClassIndex++) { if (It->IsA(Classes[ClassIndex])) { // Force a reload of the config vars It->ReloadConfig(); NumObjectsReloaded++; break; } } } } } // Reload any PerObjectConfig objects that were affected for (auto ReloadObject : PerObjectConfigObjects) { ReloadObject->ReloadConfig(); NumObjectsReloaded++; } UE_LOG(LogHotfixManager, Log, TEXT("Updating config from %s took %f seconds and reloaded %d objects"), *FileName, FPlatformTime::Seconds() - StartTime, NumObjectsReloaded); return true; }