bool FStructureEditorUtils::ChangeVariableDefaultValue(UUserDefinedStruct* Struct, FGuid VarGuid, const FString& NewDefaultValue) { auto ValidateDefaultValue = [](const FStructVariableDescription& VarDesc, const FString& InNewDefaultValue) -> bool { const UEdGraphSchema_K2* K2Schema = GetDefault<UEdGraphSchema_K2>(); const FEdGraphPinType PinType = VarDesc.ToPinType(); bool bResult = false; //TODO: validation for values, that are not passed by string if (PinType.PinCategory == K2Schema->PC_Text) { bResult = true; } else if ((PinType.PinCategory == K2Schema->PC_Object) || (PinType.PinCategory == K2Schema->PC_Interface) || (PinType.PinCategory == K2Schema->PC_Class) || (PinType.PinCategory == K2Schema->PC_AssetClass) || (PinType.PinCategory == K2Schema->PC_Asset)) { // K2Schema->DefaultValueSimpleValidation finds an object, passed by path, invalid bResult = true; } else { bResult = K2Schema->DefaultValueSimpleValidation(PinType, FString(), InNewDefaultValue, NULL, FText::GetEmpty()); } return bResult; }; auto VarDesc = GetVarDescByGuid(Struct, VarGuid); if (VarDesc && (NewDefaultValue != VarDesc->DefaultValue) && ValidateDefaultValue(*VarDesc, NewDefaultValue)) { bool bAdvancedValidation = true; if (!NewDefaultValue.IsEmpty()) { const auto Property = FindField<UProperty>(Struct, VarDesc->VarName); FStructOnScope StructDefaultMem(Struct); bAdvancedValidation = StructDefaultMem.IsValid() && Property && FBlueprintEditorUtils::PropertyValueFromString(Property, NewDefaultValue, StructDefaultMem.GetStructMemory()); } if (bAdvancedValidation) { const FScopedTransaction Transaction(LOCTEXT("ChangeVariableDefaultValue", "Change Variable Default Value")); TGuardValue<FStructureEditorUtils::EStructureEditorChangeInfo> ActiveChangeGuard(FStructureEditorUtils::FStructEditorManager::ActiveChange, EStructureEditorChangeInfo::DefaultValueChanged); ModifyStructData(Struct); VarDesc->DefaultValue = NewDefaultValue; OnStructureChanged(Struct, EStructureEditorChangeInfo::DefaultValueChanged); return true; } } return false; }
void UUserDefinedStruct::SerializeTaggedProperties(FArchive& Ar, uint8* Data, UStruct* DefaultsStruct, uint8* Defaults, const UObject* BreakRecursionIfFullyLoad) const { #if WITH_EDITOR /* The following code is responsible for UUserDefinedStruct's default values serialization. */ auto UDDefaultsStruct = Cast<UUserDefinedStruct>(DefaultsStruct); const bool bDuplicate = (0 != (Ar.GetPortFlags() & PPF_Duplicate)); /* When saving delta, we want the difference between current data and true structure's default values. When Defaults is NULL then zeroed data will be used for comparison.*/ const bool bUseNewDefaults = !Defaults && UDDefaultsStruct && Ar.DoDelta() && Ar.IsSaving() && !bDuplicate && !Ar.IsCooking(); /* Object serialized from delta will have missing properties filled with zeroed data, we want structure's default data instead */ const bool bLoadDefaultFirst = UDDefaultsStruct && !bDuplicate && Ar.IsLoading(); const bool bPrepareDefaultStruct = bUseNewDefaults || bLoadDefaultFirst; FStructOnScope StructDefaultMem(bPrepareDefaultStruct ? UDDefaultsStruct : NULL); if (bPrepareDefaultStruct) { FStructureEditorUtils::Fill_MakeStructureDefaultValue(UDDefaultsStruct, StructDefaultMem.GetStructMemory()); } if (bUseNewDefaults) { Defaults = StructDefaultMem.GetStructMemory(); } if (bLoadDefaultFirst) { if (Defaults == nullptr) { Defaults = StructDefaultMem.GetStructMemory(); } UDDefaultsStruct->CopyScriptStruct(Data, Defaults); } #endif // WITH_EDITOR Super::SerializeTaggedProperties(Ar, Data, DefaultsStruct, Defaults); }