View Issue Details

IDProjectCategoryView StatusLast Update
0002613NoesisGUIUnrealpublic2023-07-11 11:57
Reporterhcpizzi Assigned Tohcpizzi  
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionfixed 
Product Version3.2.1 
Target Version3.2.2Fixed in Version3.2.2 
Summary0002613: Set with NotifyChanged node doesn't work with Text properties
DescriptionIf Set with NotifyChanged is used with a Text property, Blueprint compilation fails with error:

The current value (/Script/Engine.Default__KismetStringLibrary) of the ' Target ' pin is invalid: /Script/Engine.Default__KismetStringLibrary isn't a KismetTextLibrary (specified on pin self)
TagsNo tags attached.
PlatformAny

Activities

hcpizzi

hcpizzi

2023-05-30 21:26

developer   ~0008519

The Set with NotifyChanged node works by expanding the node to a network of nodes that: get the current value of the property, compare it to the value to be set and, if different, set the new value and notify the change.

Most of the network is the same, regardless of the type of the property. However, the comparison is type dependent.

The error in questios was caused because the wrong object was being set in the Self pin of the compare node.

But, after fixing this problem, I realized that the Text comparison function only takes references to objects, which caused problems when trying to set them to a literan in the node's pin itself.

Given how convoluted this all was, I've taken this opportunity to revamp the whole thing. Now the node just calls a function that does everything natively. This should be more efficient, and also easier to maintain moving forward.

I've attached a patch with the changes.
SetWithNotify.patch (19,302 bytes)   
Index: NoesisBlueprint/Private/K2Node_NoesisAssignAndNotify.cpp
===================================================================
--- NoesisBlueprint/Private/K2Node_NoesisAssignAndNotify.cpp	(revision 12539)
+++ NoesisBlueprint/Private/K2Node_NoesisAssignAndNotify.cpp	(working copy)
@@ -351,258 +351,40 @@
 			UEdGraphPin* VariableSetPin = FindPin(GetVarNameString());
 			UEdGraphPin* VariableGetPin = FindPin(GetVariableOutputPinName());
 
-			// Set node
-			UK2Node_VariableSet* SetNode = CompilerContext.SpawnIntermediateNode<UK2Node_VariableSet>(this, SourceGraph);
-			SetNode->VariableReference = VariableReference;
-			SetNode->AllocateDefaultPins();
-			UEdGraphPin* SetNodeExecPin = SetNode->GetExecPin();
-			UEdGraphPin* SetNodeThenPin = SetNode->FindPin(K2Schema->PN_Then);
-			UEdGraphPin* SetNodeSelfPin = K2Schema->FindSelfPin(*SetNode, EGPD_Input);
-			UEdGraphPin* SetNodeVariableSetPin = SetNode->FindPin(GetVarNameString());
-			UEdGraphPin* SetNodeVariableGetPin = SetNode->FindPin(GetVariableOutputPinName());
+			// CallFunction node
+			UK2Node_CallFunction* CallFunctionNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph);
+			CallFunctionNode->FunctionReference.SetExternalMember(TEXT("NoesisSetWithNotify"), UNoesisFunctionLibrary::StaticClass());
+			CallFunctionNode->AllocateDefaultPins();
+			UEdGraphPin* CallFunctionNodeExecPin = CallFunctionNode->GetExecPin();
+			UEdGraphPin* CallFunctionNodeThenPin = CallFunctionNode->FindPin(K2Schema->PN_Then);
+			UEdGraphPin* CallFunctionNodeSelfPin = K2Schema->FindSelfPin(*CallFunctionNode, EGPD_Input);
+			CallFunctionNodeSelfPin->DefaultObject = UNoesisFunctionLibrary::StaticClass()->GetDefaultObject();
+			UEdGraphPin* CallFunctionNodePropertyPin = CallFunctionNode->FindPin(TEXT("Property"));
+			UEdGraphPin* CallFunctionNodeValuePin = CallFunctionNode->FindPin(TEXT("Value"));
 
-			// Notify node
-			UK2Node_CallFunction* NotifyNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph);
-			if (VariableProperty->IsA<FArrayProperty>())
-			{
-				NotifyNode->FunctionReference.SetExternalMember(TEXT("NotifyArrayChanged"), UNoesisFunctionLibrary::StaticClass());
-			}
-			else
-			{
-				NotifyNode->FunctionReference.SetExternalMember(TEXT("NotifyChanged"), UNoesisFunctionLibrary::StaticClass());
-			}
-			NotifyNode->AllocateDefaultPins();
-			UEdGraphPin* NotifyNodeExecPin = NotifyNode->GetExecPin();
-			UEdGraphPin* NotifyNodeThenPin = NotifyNode->FindPin(K2Schema->PN_Then);
-			UEdGraphPin* NotifyNodeSelfPin = K2Schema->FindSelfPin(*NotifyNode, EGPD_Input);
-			NotifyNodeSelfPin->DefaultObject = UNoesisFunctionLibrary::StaticClass()->GetDefaultObject();
-			UEdGraphPin* NotifyNodeOwnerPin = NotifyNode->FindPin(TEXT("Owner"));
-			UEdGraphPin* NotifyNodePropertyNamePin = NotifyNode->FindPin(TEXT("PropertyName"));
+			// VariableGet node
+			UK2Node_VariableGet* VariableGetNode = CompilerContext.SpawnIntermediateNode<UK2Node_VariableGet>(this, SourceGraph);
+			VariableGetNode->VariableReference = VariableReference;
+			VariableGetNode->AllocateDefaultPins();
+			UEdGraphPin* VariableGetNodeSelfPin = K2Schema->FindSelfPin(*VariableGetNode, EGPD_Input);
+			UEdGraphPin* VariableGetNodeVariablePin = VariableGetNode->FindPin(GetVarNameString());
 
-			// Compare node
-			UK2Node_CallFunction* CompareNode = nullptr;
-			UEdGraphPin* CompareNodeExecPin = nullptr;
-			UEdGraphPin* CompareNodeThenPin = nullptr;
-			UEdGraphPin* CompareNodeFirstInputPin = nullptr;
-			UEdGraphPin* CompareNodeSecondInputPin = nullptr;
-			UEdGraphPin* CompareNodeReturnValuePin = nullptr;
-			if (VariableProperty->IsA<FIntProperty>())
-			{
-				CompareNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph);
-				CompareNode->FunctionReference.SetExternalMember(TEXT("NotEqual_IntInt"), UKismetMathLibrary::StaticClass());
-				CompareNode->AllocateDefaultPins();
-				CompareNodeExecPin = CompareNode->GetExecPin();
-				CompareNodeThenPin = CompareNode->FindPin(K2Schema->PN_Then);
-				UEdGraphPin* CompareNodeSelfPin = K2Schema->FindSelfPin(*CompareNode, EGPD_Input);
-				CompareNodeSelfPin->DefaultObject = UKismetMathLibrary::StaticClass()->GetDefaultObject();
-				CompareNodeFirstInputPin = CompareNode->FindPin(TEXT("A"));
-				CompareNodeSecondInputPin = CompareNode->FindPin(TEXT("B"));
-				CompareNodeReturnValuePin = CompareNode->FindPin(TEXT("ReturnValue"));
-			}
-			else if (VariableProperty->IsA<FFloatProperty>())
-			{
-				CompareNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph);
-				CompareNode->FunctionReference.SetExternalMember(TEXT("NotEqual_FloatFloat"), UKismetMathLibrary::StaticClass());
-				CompareNode->AllocateDefaultPins();
-				CompareNodeExecPin = CompareNode->GetExecPin();
-				CompareNodeThenPin = CompareNode->FindPin(K2Schema->PN_Then);
-				UEdGraphPin* CompareNodeSelfPin = K2Schema->FindSelfPin(*CompareNode, EGPD_Input);
-				CompareNodeSelfPin->DefaultObject = UKismetMathLibrary::StaticClass()->GetDefaultObject();
-				CompareNodeFirstInputPin = CompareNode->FindPin(TEXT("A"));
-				CompareNodeSecondInputPin = CompareNode->FindPin(TEXT("B"));
-				CompareNodeReturnValuePin = CompareNode->FindPin(TEXT("ReturnValue"));
-			}
-			else if (VariableProperty->IsA<FBoolProperty>())
-			{
-				CompareNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph);
-				CompareNode->FunctionReference.SetExternalMember(TEXT("NotEqual_BoolBool"), UKismetMathLibrary::StaticClass());
-				CompareNode->AllocateDefaultPins();
-				CompareNodeExecPin = CompareNode->GetExecPin();
-				CompareNodeThenPin = CompareNode->FindPin(K2Schema->PN_Then);
-				UEdGraphPin* CompareNodeSelfPin = K2Schema->FindSelfPin(*CompareNode, EGPD_Input);
-				CompareNodeSelfPin->DefaultObject = UKismetMathLibrary::StaticClass()->GetDefaultObject();
-				CompareNodeFirstInputPin = CompareNode->FindPin(TEXT("A"));
-				CompareNodeSecondInputPin = CompareNode->FindPin(TEXT("B"));
-				CompareNodeReturnValuePin = CompareNode->FindPin(TEXT("ReturnValue"));
-			}
-			else if (VariableProperty->IsA<FStrProperty>())
-			{
-				CompareNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph);
-				CompareNode->FunctionReference.SetExternalMember(TEXT("NotEqual_StrStr"), UKismetStringLibrary::StaticClass());
-				CompareNode->AllocateDefaultPins();
-				CompareNodeExecPin = CompareNode->GetExecPin();
-				CompareNodeThenPin = CompareNode->FindPin(K2Schema->PN_Then);
-				UEdGraphPin* CompareNodeSelfPin = K2Schema->FindSelfPin(*CompareNode, EGPD_Input);
-				CompareNodeSelfPin->DefaultObject = UKismetStringLibrary::StaticClass()->GetDefaultObject();
-				CompareNodeFirstInputPin = CompareNode->FindPin(TEXT("A"));
-				CompareNodeSecondInputPin = CompareNode->FindPin(TEXT("B"));
-				CompareNodeReturnValuePin = CompareNode->FindPin(TEXT("ReturnValue"));
-			}
-			else if (VariableProperty->IsA<FTextProperty>())
-			{
-				CompareNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph);
-				CompareNode->FunctionReference.SetExternalMember(TEXT("NotEqual_TextText"), UKismetTextLibrary::StaticClass());
-				CompareNode->AllocateDefaultPins();
-				CompareNodeExecPin = CompareNode->GetExecPin();
-				CompareNodeThenPin = CompareNode->FindPin(K2Schema->PN_Then);
-				UEdGraphPin* CompareNodeSelfPin = K2Schema->FindSelfPin(*CompareNode, EGPD_Input);
-				CompareNodeSelfPin->DefaultObject = UKismetStringLibrary::StaticClass()->GetDefaultObject();
-				CompareNodeFirstInputPin = CompareNode->FindPin(TEXT("A"));
-				CompareNodeSecondInputPin = CompareNode->FindPin(TEXT("B"));
-				CompareNodeReturnValuePin = CompareNode->FindPin(TEXT("ReturnValue"));
-			}
-			else if (VariableProperty->IsA<FObjectProperty>())
-			{
-				CompareNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph);
-				CompareNode->FunctionReference.SetExternalMember(TEXT("NotEqual_ObjectObject"), UKismetMathLibrary::StaticClass());
-				CompareNode->AllocateDefaultPins();
-				CompareNodeExecPin = CompareNode->GetExecPin();
-				CompareNodeThenPin = CompareNode->FindPin(K2Schema->PN_Then);
-				UEdGraphPin* CompareNodeSelfPin = K2Schema->FindSelfPin(*CompareNode, EGPD_Input);
-				CompareNodeSelfPin->DefaultObject = UKismetMathLibrary::StaticClass()->GetDefaultObject();
-				CompareNodeFirstInputPin = CompareNode->FindPin(TEXT("A"));
-				CompareNodeSecondInputPin = CompareNode->FindPin(TEXT("B"));
-				CompareNodeReturnValuePin = CompareNode->FindPin(TEXT("ReturnValue"));
-			}
-			else if (FStructProperty* StructProperty = CastField<FStructProperty>(VariableProperty))
-			{
-				CompareNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph);
-				CompareNode->FunctionReference.SetExternalMember(TEXT("NoesisStruct_NotEqual"), UNoesisFunctionLibrary::StaticClass());
-				CompareNode->AllocateDefaultPins();
-				CompareNodeExecPin = CompareNode->GetExecPin();
-				CompareNodeThenPin = CompareNode->FindPin(K2Schema->PN_Then);
-				UEdGraphPin* CompareNodeSelfPin = K2Schema->FindSelfPin(*CompareNode, EGPD_Input);
-				CompareNodeSelfPin->DefaultObject = UNoesisFunctionLibrary::StaticClass()->GetDefaultObject();
-				CompareNodeFirstInputPin = CompareNode->FindPin(TEXT("A"));
-				CompareNodeSecondInputPin = CompareNode->FindPin(TEXT("B"));
-				CompareNodeReturnValuePin = CompareNode->FindPin(TEXT("ReturnValue"));
+			// Connect the Get and Call Function nodes
+			VariableGetNodeVariablePin->MakeLinkTo(CallFunctionNodePropertyPin);
 
-				CompareNodeFirstInputPin->PinType = VariableSetPin->PinType;
-				CompareNodeSecondInputPin->PinType = VariableSetPin->PinType;
-			}
-			else if (FByteProperty* ByteProperty = CastField<FByteProperty>(VariableProperty))
-			{
-				CompareNode = CompilerContext.SpawnIntermediateNode<UK2Node_CallFunction>(this, SourceGraph);
-				CompareNode->FunctionReference.SetExternalMember(TEXT("NotEqual_ByteByte"), UKismetMathLibrary::StaticClass());
-				CompareNode->AllocateDefaultPins();
-				CompareNodeExecPin = CompareNode->GetExecPin();
-				CompareNodeThenPin = CompareNode->FindPin(K2Schema->PN_Then);
-				UEdGraphPin* CompareNodeSelfPin = K2Schema->FindSelfPin(*CompareNode, EGPD_Input);
-				CompareNodeSelfPin->DefaultObject = UKismetMathLibrary::StaticClass()->GetDefaultObject();
-				CompareNodeFirstInputPin = CompareNode->FindPin(TEXT("A"));
-				CompareNodeSecondInputPin = CompareNode->FindPin(TEXT("B"));
-				CompareNodeReturnValuePin = CompareNode->FindPin(TEXT("ReturnValue"));
+			// Input pin types
+			K2Schema->ConvertPropertyToPinType(VariableProperty, CallFunctionNodePropertyPin->PinType);
+			K2Schema->ConvertPropertyToPinType(VariableProperty, CallFunctionNodeValuePin->PinType);
 
-				if (ByteProperty->Enum)
-				{
-					CompareNodeFirstInputPin->PinType = VariableSetPin->PinType;
-					CompareNodeSecondInputPin->PinType = VariableSetPin->PinType;
-				}
-			}
-			else if (FArrayProperty* ArrayProperty = CastField<FArrayProperty>(VariableProperty))
-			{
+			// Execution routing
+			CompilerContext.MovePinLinksToIntermediate(*ExecPin, *CallFunctionNodeExecPin);
+			CompilerContext.MovePinLinksToIntermediate(*ThenPin, *CallFunctionNodeThenPin);
 
-			}
+			// Input and output routing
+			CompilerContext.MovePinLinksToIntermediate(*SelfPin, *VariableGetNodeSelfPin);
+			CompilerContext.MovePinLinksToIntermediate(*VariableGetPin, *VariableGetNodeVariablePin);
+			CompilerContext.MovePinLinksToIntermediate(*VariableSetPin, *CallFunctionNodeValuePin);
 
-			if (CompareNode)
-			{
-				// Get node
-				UK2Node_VariableGet* GetNode = CompilerContext.SpawnIntermediateNode<UK2Node_VariableGet>(this, SourceGraph);
-				GetNode->VariableReference = VariableReference;
-				GetNode->AllocateDefaultPins();
-				UEdGraphPin* GetNodeExecPin = GetNode->GetExecPin();
-				UEdGraphPin* GetNodeThenPin = GetNode->FindPin(K2Schema->PN_Then);
-				UEdGraphPin* GetNodeSelfPin = K2Schema->FindSelfPin(*GetNode, EGPD_Input);
-				UEdGraphPin* GetNodeVariableGetPin = GetNode->FindPin(GetVarNameString());
-
-				// Branch node
-				UK2Node_IfThenElse* BranchNode = CompilerContext.SpawnIntermediateNode<UK2Node_IfThenElse>(this, SourceGraph);
-				BranchNode->AllocateDefaultPins();
-				UEdGraphPin* BranchNodeExecPin = BranchNode->GetExecPin();
-				UEdGraphPin* BranchNodeThenPin = BranchNode->GetThenPin();
-				UEdGraphPin* BranchNodeElsePin = BranchNode->GetElsePin();
-				UEdGraphPin* BranchNodeConditionPin = BranchNode->GetConditionPin();
-
-				// Execution routing
-				if (GetNodeExecPin)
-				{
-					CompilerContext.MovePinLinksToIntermediate(*ExecPin, *GetNodeExecPin);
-					if (CompareNodeExecPin)
-					{
-						GetNodeThenPin->MakeLinkTo(CompareNodeExecPin);
-						CompareNodeThenPin->MakeLinkTo(BranchNodeExecPin);
-					}
-					else
-					{
-						GetNodeThenPin->MakeLinkTo(BranchNodeExecPin);
-					}
-				}
-				else if (CompareNodeExecPin)
-				{
-					CompilerContext.MovePinLinksToIntermediate(*ExecPin, *CompareNodeExecPin);
-					CompareNodeThenPin->MakeLinkTo(BranchNodeExecPin);
-				}
-				else
-				{
-					CompilerContext.MovePinLinksToIntermediate(*ExecPin, *BranchNodeExecPin);
-				}
-				BranchNodeThenPin->MakeLinkTo(SetNodeExecPin);
-				CompilerContext.CopyPinLinksToIntermediate(*ThenPin, *BranchNodeElsePin);
-				SetNodeThenPin->MakeLinkTo(NotifyNodeExecPin);
-				CompilerContext.CopyPinLinksToIntermediate(*ThenPin, *NotifyNodeThenPin);
-
-				// Data routing
-				CompilerContext.CopyPinLinksToIntermediate(*VariableSetPin, *CompareNodeFirstInputPin);
-				GetNodeVariableGetPin->MakeLinkTo(CompareNodeSecondInputPin);
-				CompareNodeReturnValuePin->MakeLinkTo(BranchNodeConditionPin);
-				CompilerContext.CopyPinLinksToIntermediate(*VariableSetPin, *SetNodeVariableSetPin);
-				CompilerContext.MovePinLinksToIntermediate(*VariableGetPin, *SetNodeVariableGetPin);
-				NotifyNodePropertyNamePin->DefaultValue = GetVarNameString();
-
-				// Self assignment
-				CompilerContext.CopyPinLinksToIntermediate(*SelfPin, *GetNodeSelfPin);
-				CompilerContext.CopyPinLinksToIntermediate(*SelfPin, *SetNodeSelfPin);
-				if (SelfPin->LinkedTo.Num())
-				{
-					CompilerContext.CopyPinLinksToIntermediate(*SelfPin, *NotifyNodeOwnerPin);
-				}
-				else
-				{
-					// Self node
-					UK2Node_Self* SelfNode = CompilerContext.SpawnIntermediateNode<UK2Node_Self>(this, SourceGraph);
-					SelfNode->AllocateDefaultPins();
-					UEdGraphPin* SelfNodeSelfPin = K2Schema->FindSelfPin(*SelfNode, EGPD_Output);
-					SelfNodeSelfPin->MakeLinkTo(NotifyNodeOwnerPin);
-				}
-			}
-			else
-			{
-				// Execution routing
-				CompilerContext.MovePinLinksToIntermediate(*ExecPin, *SetNodeExecPin);
-				SetNodeThenPin->MakeLinkTo(NotifyNodeExecPin);
-				CompilerContext.CopyPinLinksToIntermediate(*ThenPin, *NotifyNodeThenPin);
-
-				// Data routing
-				CompilerContext.CopyPinLinksToIntermediate(*VariableSetPin, *SetNodeVariableSetPin);
-				CompilerContext.MovePinLinksToIntermediate(*VariableGetPin, *SetNodeVariableGetPin);
-				NotifyNodePropertyNamePin->DefaultValue = GetVarNameString();
-
-				// Self assignment
-				CompilerContext.CopyPinLinksToIntermediate(*SelfPin, *SetNodeSelfPin);
-				if (SelfPin->LinkedTo.Num())
-				{
-					CompilerContext.CopyPinLinksToIntermediate(*SelfPin, *NotifyNodeOwnerPin);
-				}
-				else
-				{
-					// Self node
-					UK2Node_Self* SelfNode = CompilerContext.SpawnIntermediateNode<UK2Node_Self>(this, SourceGraph);
-					SelfNode->AllocateDefaultPins();
-					UEdGraphPin* SelfNodeSelfPin = K2Schema->FindSelfPin(*SelfNode, EGPD_Output);
-					SelfNodeSelfPin->MakeLinkTo(NotifyNodeOwnerPin);
-				}
-			}
-
 			BreakAllNodeLinks();
 		}
 	}
Index: NoesisRuntime/Classes/NoesisFunctionLibrary.h
===================================================================
--- NoesisRuntime/Classes/NoesisFunctionLibrary.h	(revision 12539)
+++ NoesisRuntime/Classes/NoesisFunctionLibrary.h	(working copy)
@@ -41,6 +41,11 @@
 	UFUNCTION(BlueprintCallable, Category = "NoesisGUI", meta = (HidePin = "Target"))
 	static UObject* LoadXaml(class UNoesisXaml* Xaml);
 
+	UFUNCTION(BlueprintCallable, CustomThunk, meta = (BlueprintInternalUseOnly = "true", CustomStructureParam = "Property,Value"), Category = "Noesis")
+	static void NoesisSetWithNotify(const int32& Property, const int32& Value);
+
+	DECLARE_FUNCTION(execNoesisSetWithNotify);
+
 	UFUNCTION(BlueprintCallable, CustomThunk, meta = (BlueprintInternalUseOnly = "true", CustomStructureParam = "A,B"), Category = "Noesis|Struct")
 	static bool NoesisStruct_NotEqual(const FGenericStruct& A, const FGenericStruct& B);
 
Index: NoesisRuntime/Private/NoesisFunctionLibrary.cpp
===================================================================
--- NoesisRuntime/Private/NoesisFunctionLibrary.cpp	(revision 12539)
+++ NoesisRuntime/Private/NoesisFunctionLibrary.cpp	(working copy)
@@ -87,6 +87,61 @@
 	return nullptr;
 }
 
+DEFINE_FUNCTION(UNoesisFunctionLibrary::execNoesisSetWithNotify)
+{
+	// Step to get the property
+	Stack.MostRecentProperty = nullptr;
+	Stack.MostRecentPropertyAddress = nullptr;
+	Stack.StepCompiledIn<FProperty>(NULL);
+	UObject* Object = (UObject*)Stack.MostRecentPropertyContainer;
+	FProperty* Property = Stack.MostRecentProperty;
+	void* PropertyAddress = Stack.MostRecentPropertyAddress;
+
+	// Sanity checks
+	check(Object != nullptr);
+	check(Property != nullptr);
+	check(PropertyAddress != nullptr);
+	check(Property->ContainerPtrToValuePtr<void>(Object) == PropertyAddress);
+
+	// Allocate and initialize the return value
+	const int32 PropertySize = Property->GetSize();
+	void* StorageSpace = FMemory_Alloca(PropertySize);
+	Property->InitializeValue(StorageSpace);
+
+	// Step to get the value
+	Stack.MostRecentProperty = nullptr;
+	Stack.MostRecentPropertyAddress = nullptr;
+	Stack.StepCompiledIn<FProperty>(StorageSpace);
+	FProperty* ValueProperty = Stack.MostRecentProperty;
+	void* ValueAddress = Stack.MostRecentPropertyAddress;
+
+	// More sanity checks
+	check(ValueProperty == nullptr || ValueProperty->IsA(Property->GetClass()));
+	check(ValueAddress == nullptr || Property->Identical(StorageSpace, ValueAddress));
+
+	P_FINISH;
+	P_NATIVE_BEGIN;
+	if (!Property->Identical(PropertyAddress, StorageSpace, PPF_None))
+	{
+		Property->SetValue_InContainer(Object, StorageSpace);
+		if (Property->IsA<FArrayProperty>())
+		{
+			NoesisNotifyArrayPropertyPostReset(PropertyAddress);
+		}
+		else if (Property->IsA<FMapProperty>())
+		{
+			NoesisNotifyMapPropertyPostReset(PropertyAddress);
+		}
+		else
+		{
+			NoesisNotifyPropertyChanged(Object, Property->GetFName());
+		}
+	}
+	P_NATIVE_END;
+
+	Property->DestroyValue(StorageSpace);
+}
+
 DEFINE_FUNCTION(UNoesisFunctionLibrary::execNoesisStruct_NotEqual)
 {
 	Stack.StepCompiledIn<FStructProperty>(NULL);
SetWithNotify.patch (19,302 bytes)   

Issue History

Date Modified Username Field Change
2023-05-30 20:26 hcpizzi New Issue
2023-05-30 20:26 hcpizzi Assigned To => hcpizzi
2023-05-30 20:26 hcpizzi Status new => assigned
2023-05-30 21:26 hcpizzi Note Added: 0008519
2023-05-30 21:26 hcpizzi File Added: SetWithNotify.patch
2023-05-31 14:12 jsantos Target Version => 3.2.2
2023-07-11 11:57 hcpizzi Status assigned => resolved
2023-07-11 11:57 hcpizzi Resolution open => fixed
2023-07-11 11:57 hcpizzi Fixed in Version => 3.2.2