//TODO: Move to blueprint utils void FStructureEditorUtils::RemoveInvalidStructureMemberVariableFromBlueprint(UBlueprint* Blueprint) { if (Blueprint) { const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>(); const UScriptStruct* FallbackStruct = GetFallbackStruct(); FString DislpayList; TArray<FName> ZombieMemberNames; for (int32 VarIndex = 0; VarIndex < Blueprint->NewVariables.Num(); ++VarIndex) { const FBPVariableDescription& Var = Blueprint->NewVariables[VarIndex]; if (Var.VarType.PinCategory == K2Schema->PC_Struct) { const UScriptStruct* ScriptStruct = Cast<const UScriptStruct>(Var.VarType.PinSubCategoryObject.Get()); const bool bInvalidStruct = (NULL == ScriptStruct) || (FallbackStruct == ScriptStruct); if (bInvalidStruct) { DislpayList += Var.FriendlyName.IsEmpty() ? Var.VarName.ToString() : Var.FriendlyName; DislpayList += TEXT("\n"); ZombieMemberNames.Add(Var.VarName); } } } if (ZombieMemberNames.Num()) { auto Response = FMessageDialog::Open( EAppMsgType::OkCancel, FText::Format( LOCTEXT("RemoveInvalidStructureMemberVariable_Msg", "The following member variables in blueprint '{0}' have invalid type. Would you like to remove them? \n\n{1}"), FText::FromString(Blueprint->GetFullName()), FText::FromString(DislpayList) )); check((EAppReturnType::Ok == Response) || (EAppReturnType::Cancel == Response)); if (EAppReturnType::Ok == Response) { Blueprint->Modify(); for (auto NameIter = ZombieMemberNames.CreateConstIterator(); NameIter; ++NameIter) { const FName Name = *NameIter; Blueprint->NewVariables.RemoveAll(FFindByNameHelper<FBPVariableDescription>(Name)); //TODO: Add RemoveFirst to TArray FBlueprintEditorUtils::RemoveVariableNodes(Blueprint, Name); } } } } }
void UStructProperty::LinkInternal(FArchive& Ar) { // We potentially have to preload the property itself here, if we were the inner of an array property if(HasAnyFlags(RF_NeedLoad)) { GetLinker()->Preload(this); } #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) if (Struct == NULL) { UE_LOG(LogProperty, Error, TEXT("Struct type unknown for property '%s'; perhaps the USTRUCT() was renamed or deleted?"), *GetFullName()); } #endif // Preload is required here in order to load the value of Struct->PropertiesSize Ar.Preload(Struct); if ( !ensure(Struct) ) { Struct = GetFallbackStruct(); } PreloadInnerStructMembers(this); ElementSize = Align(Struct->PropertiesSize, Struct->GetMinAlignment()); if (Struct->StructFlags & STRUCT_IsPlainOldData) // if there is nothing to construct or the struct is known to be memcpy-able, then allow memcpy { PropertyFlags |= CPF_IsPlainOldData; } if (Struct->StructFlags & STRUCT_NoDestructor) { PropertyFlags |= CPF_NoDestructor; } if (Struct->StructFlags & STRUCT_ZeroConstructor) { PropertyFlags |= CPF_ZeroConstructor; } }
void UStructProperty::Serialize( FArchive& Ar ) { Super::Serialize( Ar ); static UScriptStruct* FallbackStruct = GetFallbackStruct(); if (Ar.IsPersistent() && Ar.GetLinker() && Ar.IsLoading() && !Struct) { // It's necessary to solve circular dependency problems, when serializing the Struct causes linking of the Property. Struct = FallbackStruct; } Ar << Struct; #if WITH_EDITOR if (Ar.IsPersistent() && Ar.GetLinker()) { if (!Struct && Ar.IsLoading()) { UE_LOG(LogProperty, Error, TEXT("UStructProperty::Serialize Loading: Property '%s'. Unknown structure."), *GetFullName()); Struct = FallbackStruct; } else if ((FallbackStruct == Struct) && Ar.IsSaving()) { UE_LOG(LogProperty, Error, TEXT("UStructProperty::Serialize Saving: Property '%s'. FallbackStruct structure."), *GetFullName()); } } #endif // WITH_EDITOR if (Struct) { PreloadInnerStructMembers(this); } else { ensure(true); } }
FStructureEditorUtils::EStructureError FStructureEditorUtils::IsStructureValid(const UScriptStruct* Struct, const UStruct* RecursionParent, FString* OutMsg) { check(Struct); if (Struct == RecursionParent) { if (OutMsg) { *OutMsg = FString::Printf(*LOCTEXT("StructureRecursion", "Recursion: Struct cannot have itself as a member variable. Struct '%s', recursive parent '%s'").ToString(), *Struct->GetFullName(), *RecursionParent->GetFullName()); } return EStructureError::Recursion; } const UScriptStruct* FallbackStruct = GetFallbackStruct(); if (Struct == FallbackStruct) { if (OutMsg) { *OutMsg = LOCTEXT("StructureUnknown", "Struct unknown (deleted?)").ToString(); } return EStructureError::FallbackStruct; } if (Struct->GetStructureSize() <= 0) { if (OutMsg) { *OutMsg = FString::Printf(*LOCTEXT("StructureSizeIsZero", "Struct '%s' is empty").ToString(), *Struct->GetFullName()); } return EStructureError::EmptyStructure; } if (const UUserDefinedStruct* UDStruct = Cast<const UUserDefinedStruct>(Struct)) { if (UDStruct->Status != EUserDefinedStructureStatus::UDSS_UpToDate) { if (OutMsg) { *OutMsg = FString::Printf(*LOCTEXT("StructureNotCompiled", "Struct '%s' is not compiled").ToString(), *Struct->GetFullName()); } return EStructureError::NotCompiled; } for (const UProperty* P = Struct->PropertyLink; P; P = P->PropertyLinkNext) { const UStructProperty* StructProp = Cast<const UStructProperty>(P); if (NULL == StructProp) { if (const UArrayProperty* ArrayProp = Cast<const UArrayProperty>(P)) { StructProp = Cast<const UStructProperty>(ArrayProp->Inner); } } if (StructProp) { if ((NULL == StructProp->Struct) || (FallbackStruct == StructProp->Struct)) { if (OutMsg) { *OutMsg = FString::Printf(*LOCTEXT("StructureUnknownProperty", "Struct unknown (deleted?). Parent '%s' Property: '%s'").ToString(), *Struct->GetFullName(), *StructProp->GetName()); } return EStructureError::FallbackStruct; } FString OutMsgInner; const EStructureError Result = IsStructureValid( StructProp->Struct, RecursionParent ? RecursionParent : Struct, OutMsg ? &OutMsgInner : NULL); if (EStructureError::Ok != Result) { if (OutMsg) { *OutMsg = FString::Printf(*LOCTEXT("StructurePropertyErrorTemplate", "Struct '%s' Property '%s' Error ( %s )").ToString(), *Struct->GetFullName(), *StructProp->GetName(), *OutMsgInner); } return Result; } } } } return EStructureError::Ok; }
FStructureEditorUtils::EStructureError FStructureEditorUtils::IsStructureValid(const UScriptStruct* Struct, const UStruct* RecursionParent, FString* OutMsg) { check(Struct); if (Struct == RecursionParent) { if (OutMsg) { *OutMsg = FString::Printf(*LOCTEXT("StructureRecursion", "Recursion: Struct cannot have itself as a member variable. Struct '%s', recursive parent '%s'").ToString(), *Struct->GetFullName(), *RecursionParent->GetFullName()); } return EStructureError::Recursion; } const UScriptStruct* FallbackStruct = GetFallbackStruct(); if (Struct == FallbackStruct) { if (OutMsg) { *OutMsg = LOCTEXT("StructureUnknown", "Struct unknown (deleted?)").ToString(); } return EStructureError::FallbackStruct; } if (const UBlueprintGeneratedStruct* BPGStruct = Cast<const UBlueprintGeneratedStruct>(Struct)) { static const FName BlueprintTypeName(TEXT("BlueprintType")); if (!Struct->GetBoolMetaData(BlueprintTypeName)) { if (OutMsg) { *OutMsg = FString::Printf(*LOCTEXT("StructureNotBlueprintType", "Struct '%s' is not BlueprintType").ToString(), *Struct->GetFullName()); } return EStructureError::NotBlueprintType; } if (BPGStruct->Status != EBlueprintStructureStatus::BSS_UpToDate) { if (OutMsg) { *OutMsg = FString::Printf(*LOCTEXT("StructureNotCompiled", "Struct '%s' is not compiled").ToString(), *Struct->GetFullName()); } return EStructureError::NotCompiled; } for (const UProperty * P = Struct->PropertyLink; P; P = P->PropertyLinkNext) { const UStructProperty* StructProp = Cast<const UStructProperty>(P); if (NULL == StructProp) { if (const UArrayProperty* ArrayProp = Cast<const UArrayProperty>(P)) { StructProp = Cast<const UStructProperty>(ArrayProp->Inner); } } if (StructProp) { if ((NULL == StructProp->Struct) || (FallbackStruct == StructProp->Struct)) { if (OutMsg) { *OutMsg = FString::Printf(*LOCTEXT("StructureUnknownProperty", "Struct unknown (deleted?). Parent '%s' Property: '%s").ToString(), *Struct->GetFullName(), *StructProp->GetName()); } return EStructureError::FallbackStruct; } const EStructureError Result = IsStructureValid(StructProp->Struct, RecursionParent ? RecursionParent : Struct, OutMsg); if (EStructureError::Ok != Result) { return Result; } } } } return EStructureError::Ok; }