void UK2Node_DynamicCast::NotifyPinConnectionListChanged(UEdGraphPin* Pin)
{
	Super::NotifyPinConnectionListChanged(Pin);

	if (Pin == GetCastSourcePin())
	{
		Pin->PinFriendlyName = FText::GetEmpty();

		FEdGraphPinType& InputPinType = Pin->PinType;
		if (Pin->LinkedTo.Num() == 0)
		{
			InputPinType.PinCategory = UEdGraphSchema_K2::PC_Wildcard;
			InputPinType.PinSubCategory.Empty();
			InputPinType.PinSubCategoryObject = nullptr;
		}
		else
		{
			const FEdGraphPinType& ConnectedPinType = Pin->LinkedTo[0]->PinType;
			if (ConnectedPinType.PinCategory == UEdGraphSchema_K2::PC_Interface)
			{
				Pin->PinFriendlyName = LOCTEXT("InterfaceInputName", "Interface");
				InputPinType.PinCategory = UEdGraphSchema_K2::PC_Interface;
				InputPinType.PinSubCategoryObject = ConnectedPinType.PinSubCategoryObject;
			}
			else if (ConnectedPinType.PinCategory == UEdGraphSchema_K2::PC_Object)
			{
				InputPinType.PinCategory = UEdGraphSchema_K2::PC_Object;
				InputPinType.PinSubCategoryObject = UObject::StaticClass();
			}
		}
	}
}
bool UK2Node_DynamicCast::IsConnectionDisallowed(const UEdGraphPin* MyPin, const UEdGraphPin* OtherPin, FString& OutReason) const
{
	bool bIsDisallowed = Super::IsConnectionDisallowed(MyPin, OtherPin, OutReason);

	if (MyPin == GetCastSourcePin())
	{
		const FEdGraphPinType& OtherPinType = OtherPin->PinType;
		const FText OtherPinName = OtherPin->PinFriendlyName.IsEmpty() ? FText::FromString(OtherPin->PinName) : OtherPin->PinFriendlyName;

		if (OtherPinType.IsContainer())
		{
			bIsDisallowed = true;
			OutReason = LOCTEXT("CannotContainerCast", "You cannot cast containers of objects.").ToString();
		}
		else if (TargetType == nullptr)
		{
			bIsDisallowed = true;
			OutReason = LOCTEXT("InvalidTargetType", "This cast has an invalid target type (was the class deleted without a redirect?).").ToString();
		}
		else if ((OtherPinType.PinCategory == UEdGraphSchema_K2::PC_Interface) || TargetType->HasAnyClassFlags(CLASS_Interface))
		{
			// allow all interface casts
		}
		else if (OtherPinType.PinCategory == UEdGraphSchema_K2::PC_Object)
		{
			// let's handle wasted cast inputs with warnings in ValidateNodeDuringCompilation() instead
		}
		else
		{
			bIsDisallowed = true;
			OutReason = LOCTEXT("NonObjectCast", "You can only cast objects/interfaces.").ToString();
		}
	}
	return bIsDisallowed;
}
bool UK2Node_DynamicCast::IsConnectionDisallowed(const UEdGraphPin* MyPin, const UEdGraphPin* OtherPin, FString& OutReason) const
{
	bool bIsDisallowed = Super::IsConnectionDisallowed(MyPin, OtherPin, OutReason);

	if (MyPin == GetCastSourcePin())
	{
		const FEdGraphPinType& OtherPinType = OtherPin->PinType;
		const FText OtherPinName = OtherPin->PinFriendlyName.IsEmpty() ? FText::FromString(OtherPin->PinName) : OtherPin->PinFriendlyName;

		if (OtherPinType.bIsArray)
		{
			bIsDisallowed = true;
			OutReason = LOCTEXT("CannotArrayCast", "You cannot cast arrays of objects.").ToString();
		}
		else if (TargetType == nullptr)
		{
			bIsDisallowed = true;
			OutReason = LOCTEXT("BadCastNode", "This cast has an invalid target type (was the class deleted without a redirect?).").ToString();
		}
		else if ((OtherPinType.PinCategory == UEdGraphSchema_K2::PC_Interface) || TargetType->HasAnyClassFlags(CLASS_Interface))
		{
			// allow all interface casts
		}
		else if (OtherPinType.PinCategory == UEdGraphSchema_K2::PC_Object)
		{
			UClass* ObjectClass = Cast<UClass>(OtherPinType.PinSubCategoryObject.Get());
			if ((ObjectClass == nullptr) && (OtherPinType.PinSubCategory == UEdGraphSchema_K2::PSC_Self))
			{
				if (UK2Node* K2Node = Cast<UK2Node>(OtherPin->GetOwningNode()))
				{
					ObjectClass = K2Node->GetBlueprint()->GeneratedClass;
				}
			}
			// if the ObjectClass is still null, assume it is a UObject, which 
			// will work with everything (so don't disallow it)
			
			if (ObjectClass != nullptr)
			{
				
				if (ObjectClass == TargetType)
				{
					bIsDisallowed = true;
					OutReason = FText::Format(LOCTEXT("EqualObjectCast", "'{0}' is already a '{1}', you don't need the cast."),
						OtherPinName, TargetType->GetDisplayNameText()).ToString();
				}
				else if (ObjectClass->IsChildOf(TargetType))
				{
					bIsDisallowed = true;
					OutReason = FText::Format(LOCTEXT("UnneededObjectCast", "'{0}' is already a '{1}' (which inherits from '{2}'), so you don't need the cast."),
						OtherPinName, ObjectClass->GetDisplayNameText(), TargetType->GetDisplayNameText()).ToString();
				}
				else if (!TargetType->IsChildOf(ObjectClass))
				{
					bIsDisallowed = true;
					OutReason = FText::Format(LOCTEXT("DisallowedObjectCast", "'{0}' does not inherit from '{1}' (the cast would always fail)."),
						TargetType->GetDisplayNameText(), ObjectClass->GetDisplayNameText()).ToString();
				}
			}
		}
		else
		{
			bIsDisallowed = true;
			OutReason = LOCTEXT("NonObjectCast", "You can only cast objects/interfaces.").ToString();
		}
	}
	return bIsDisallowed;
}
void UK2Node_DynamicCast::PostReconstructNode()
{
	Super::PostReconstructNode();
	// update the pin name (to "Interface" if an interface is connected)
	NotifyPinConnectionListChanged(GetCastSourcePin());
}
void UK2Node_DynamicCast::ValidateNodeDuringCompilation(FCompilerResultsLog& MessageLog) const
{
	Super::ValidateNodeDuringCompilation(MessageLog);

	UEdGraphPin* SourcePin = GetCastSourcePin();
	if (SourcePin->LinkedTo.Num() > 0)
	{
		const UClass* SourceType = *TargetType;
		if (SourceType == nullptr)
		{
			return;
		}

		for (UEdGraphPin* CastInput : SourcePin->LinkedTo)
		{
			const FEdGraphPinType& SourcePinType = CastInput->PinType;
			if (SourcePinType.PinCategory != UEdGraphSchema_K2::PC_Object)
			{
				// all other types should have been rejected by IsConnectionDisallowed()
				continue;
			}

			UClass* SourceClass = Cast<UClass>(SourcePinType.PinSubCategoryObject.Get());
			if ((SourceClass == nullptr) && (SourcePinType.PinSubCategory == UEdGraphSchema_K2::PSC_Self))
			{
				if (UK2Node* K2Node = Cast<UK2Node>(CastInput->GetOwningNode()))
				{
					SourceClass = K2Node->GetBlueprint()->GeneratedClass;
				}
			}

			if (SourceClass == nullptr)
			{
				const FString SourcePinName = CastInput->PinFriendlyName.IsEmpty() ? CastInput->PinName : CastInput->PinFriendlyName.ToString();

				FText const ErrorFormat = LOCTEXT("BadCastInput", "'%s' does not have a clear object type (invalid input into @@).");
				MessageLog.Error( *FString::Printf(*ErrorFormat.ToString(), *SourcePinName), this );

				continue;
			}

			if (SourceClass == SourceType)
			{
				const FString SourcePinName = CastInput->PinFriendlyName.IsEmpty() ? CastInput->PinName : CastInput->PinFriendlyName.ToString();

				FText const WarningFormat = LOCTEXT("EqualObjectCast", "'%s' is already a '%s', you don't need @@.");
				MessageLog.Warning( *FString::Printf(*WarningFormat.ToString(), *SourcePinName, *TargetType->GetDisplayNameText().ToString()), this );
			}
			else if (SourceClass->IsChildOf(SourceType))
			{
				const FString SourcePinName = CastInput->PinFriendlyName.IsEmpty() ? CastInput->PinName : CastInput->PinFriendlyName.ToString();

				FText const WarningFormat = LOCTEXT("UnneededObjectCast", "'%s' is already a '%s' (which inherits from '%s'), so you don't need @@.");
				MessageLog.Warning( *FString::Printf(*WarningFormat.ToString(), *SourcePinName, *SourceClass->GetDisplayNameText().ToString(), *TargetType->GetDisplayNameText().ToString()), this );
			}
			else if (!SourceType->IsChildOf(SourceClass) && !FKismetEditorUtilities::IsClassABlueprintInterface(SourceType))
			{
				FText const WarningFormat = LOCTEXT("DisallowedObjectCast", "'%s' does not inherit from '%s' (@@ would always fail).");
				MessageLog.Warning( *FString::Printf(*WarningFormat.ToString(), *TargetType->GetDisplayNameText().ToString(), *SourceClass->GetDisplayNameText().ToString()), this );
			}
		}
	}
}