void UARAttributeBaseComponent::ChangeAttribute(float ModValue, FName AttributeName, TEnumAsByte<EAttrOp> OpType)
{
	float attrValue = GetFloatValue(AttributeName);
	ModifiedAttribute.ActuallDamage = ModValue;
	ModifiedAttribute.AttributeName = AttributeName;
	SetAttributeModified(ModValue, AttributeName);
	SetFloatValue(AttributeOp(ModValue, attrValue, OpType), AttributeName);
}
void UARAttributeBaseComponent::ChangeAttribute(FName AttributeName, float ModValue, TEnumAsByte<EAttrOp> OperationType)
{
	SetFloatValue(AttributeOp(ModValue, GetFloatValue(AttributeName), OperationType), AttributeName);
}
//this could be split into multiple functions actially.
//maybe that would not be OOP, but could be cleaner and do not invovlve casting.
void UARAttributeBaseComponent::DamageAttribute(FARDamageEvent const& DamageEvent, AActor* EventInstigator, AActor* DamageCauser)
{
	if (DamageEvent.IsOfType(FARDamageEvent::ClassID))
	{
		SetFloatValue(AttributeOp(DamageEvent.Attribute.ModValue, GetFloatValue(DamageEvent.Attribute.AttributeName), DamageEvent.Attribute.OperationType), DamageEvent.Attribute.AttributeName);
		UDamageType* Damage = nullptr;
		if (DamageEvent.DamageTypeClass)
		{
			Damage = ConstructObject<UDamageType>(DamageEvent.DamageTypeClass);
		}
		UARAttributeBaseComponent* attr = EventInstigator->FindComponentByClass<UARAttributeBaseComponent>();
		/*
			TODO!!!
			Part about setting up damage events and data is in need of serious rework!
			1. Better organize what data is send.
			2. Add more specialized function for Radial Damage
			3. Split Damage Info (hit location, radius, damage type) from what was damaged.
		*/
		SetAttributeChange(DamageEvent.Attribute, DamageEvent.HitInfo.Location, GetOwner(), DamageCauser, EventInstigator, Damage, DamageEvent.DamageTag);
		//handle death.
		IIAttribute* attrInt = InterfaceCast<IIAttribute>(GetOwner());
		if (attrInt)
		{
			attrInt->Execute_OnRecivedDamage(GetOwner(), ChangedAttribute, DamageEvent, DamageEvent.DamageTag);
			if (DamageEvent.Attribute.AttributeName == attrInt->GetDeathAttribute())
			{
				if (GetFloatValue(DamageEvent.Attribute.AttributeName) <= 0 && DamageEvent.Attribute.ModValue > 0) //prolly want to move to interface as well. Different actor might want 
					//different thresholds.
				{
					attrInt->Died();
				}
			}
		}

		if (attr)
		{
			attr->InstigatorAttributeDamageCaused(DamageEvent.Attribute, DamageEvent.HitInfo.Location, GetOwner(), DamageCauser, EventInstigator, Damage, DamageEvent.DamageTag);
		}
		
		OnAttributeDamage.Broadcast(ChangedAttribute, DamageEvent.DamageTag);
	}
	else if (DamageEvent.IsOfType(FARPointDamageEvent::ClassID))
	{
		FARPointDamageEvent* const Point = (FARPointDamageEvent*)&DamageEvent;
		SetFloatValue(AttributeOp(Point->Attribute.ModValue, GetFloatValue(Point->Attribute.AttributeName), Point->Attribute.OperationType), Point->Attribute.AttributeName);
		UDamageType* Damage = nullptr;
		if (Point->DamageTypeClass)
		{
			Damage = ConstructObject<UDamageType>(Point->DamageTypeClass);
		}
		UARAttributeBaseComponent* attr = EventInstigator->FindComponentByClass<UARAttributeBaseComponent>();
		SetAttributeChange(Point->Attribute, DamageEvent.HitInfo.Location, GetOwner(), DamageCauser, EventInstigator, Damage, Point->DamageTag);
		
		IIAttribute* attrInt = InterfaceCast<IIAttribute>(GetOwner());
		if (attrInt)
		{
			attrInt->Execute_OnRecivedDamage(GetOwner(), ChangedAttribute, DamageEvent, DamageEvent.DamageTag);
			if (DamageEvent.Attribute.AttributeName == attrInt->GetDeathAttribute())
			{
				if (GetFloatValue(DamageEvent.Attribute.AttributeName) <= 0 && DamageEvent.Attribute.ModValue > 0) //prolly want to move to interface as well. Different actor might want 
					//different thresholds.
				{
					attrInt->Died();
				}
			}
		}

		if (attr)
		{
			attr->InstigatorAttributeDamageCaused(Point->Attribute, DamageEvent.HitInfo.Location, GetOwner(), DamageCauser, EventInstigator, Damage, Point->DamageTag);
		}

		OnAttributeDamage.Broadcast(ChangedAttribute, Point->DamageTag);
		OnPointAttributeDamage.Broadcast(Point->Attribute, EventInstigator, Point->HitInfo.ImpactPoint, Point->HitInfo.Component.Get(), Point->HitInfo.BoneName, Point->ShotDirection, Damage, DamageCauser);
	}
	else if (DamageEvent.IsOfType(FARRadialDamageEvent::ClassID))
	{
		FARRadialDamageEvent* const Point = (FARRadialDamageEvent*)&DamageEvent;
		SetFloatValue(AttributeOp(Point->Attribute.ModValue, GetFloatValue(Point->Attribute.AttributeName), Point->Attribute.OperationType), Point->Attribute.AttributeName);
		UDamageType* Damage = nullptr;
		if (Point->DamageTypeClass)
		{
			Damage = ConstructObject<UDamageType>(Point->DamageTypeClass);
		}
		UARAttributeBaseComponent* attr = EventInstigator->FindComponentByClass<UARAttributeBaseComponent>();
		SetAttributeChange(Point->Attribute, DamageEvent.HitInfo.Location, GetOwner(), DamageCauser, EventInstigator, Damage, Point->DamageTag);

		IIAttribute* attrInt = InterfaceCast<IIAttribute>(GetOwner());
		if (attrInt)
		{
			attrInt->Execute_OnRecivedRadialDamage(GetOwner(), ChangedAttribute, *Point, DamageEvent.DamageTag);
			attrInt->Execute_OnRecivedDamage(GetOwner(), ChangedAttribute, DamageEvent, DamageEvent.DamageTag);
			if (DamageEvent.Attribute.AttributeName == attrInt->GetDeathAttribute())
			{
				if (GetFloatValue(DamageEvent.Attribute.AttributeName) <= 0 && DamageEvent.Attribute.ModValue > 0) //prolly want to move to interface as well. Different actor might want 
					//different thresholds.
				{
					attrInt->Died();
				}
			}
		}

		if (attr)
		{
			attr->InstigatorAttributeDamageCaused(Point->Attribute, DamageEvent.HitInfo.Location, GetOwner(), DamageCauser, EventInstigator, Damage, Point->DamageTag);
		}

		OnAttributeDamage.Broadcast(ChangedAttribute, Point->DamageTag);
		
		//OnPointAttributeDamage.Broadcast(Point->Attribute, EventInstigator, Point->HitInfo.ImpactPoint, Point->HitInfo.Component.Get(), Point->HitInfo.BoneName, Point->ShotDirection, Damage, DamageCauser);
	}
}