Hello, I am fairly new to network programming and unreal network. I am able to apply damage from the server but not the client. I have a monster character but I use an actor component for a health component. I looked all over the place, but mostly find instruction with blueprint or what I wrote. I must be missing something. I have attached the code for the HealthComponent and the Weapon that does the damage. I am sorry about the ugly indentation, I could not figure out how to format this.
HealthComponent.cpp
// Sets default values for this component's properties
UHealthComponent::UHealthComponent()
{
MaxHealth = 100.f;
SetIsReplicated(true);
}
// Called when the game starts
void UHealthComponent::BeginPlay()
{
Super::BeginPlay();
Health = MaxHealth;
if (GetOwnerRole() == ROLE_Authority)
{
AActor* MyOwner = GetOwner();
if (MyOwner)
{
MyOwner->OnTakeAnyDamage.AddDynamic(this, &UHealthComponent::HandleTakeAnyDamage);
}
}
}
void UHealthComponent::OnRep_Health(float OldHealth)
{
float Damage = Health - OldHealth;
OnHealthChanged.Broadcast(this, Health, Damage, nullptr, nullptr, nullptr);
}
float UHealthComponent::GetHealth() const
{
return Health;
}
/**
* Handle damage done to actor
*/
void UHealthComponent::HandleTakeAnyDamage(AActor* DamagedActor, float Damage, const UDamageType* DamageType,
AController* InstigatedBy, AActor* DamageCauser)
{
if (Damage <= 0)
{
return;
}
Health = FMath::Clamp(Health-Damage, 0.f, MaxHealth);
if (Health == 0)
{
if (GetOwner())
{
UE_LOG(LogTemp, Warning, TEXT("%s is dead."), *GetOwner()->GetName());
}
}
OnHealthChanged.Broadcast(this, Health, Damage, DamageType, InstigatedBy, DamageCauser);
}
void UHealthComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(UHealthComponent, Health);
}
HealthComponent.h
// OnHealthChanged Event
DECLARE_DYNAMIC_MULTICAST_DELEGATE_SixParams(FOnHealthChangedSignature, UHealthComponent*, HealthComp, float, Health, float, HealthDelta, const class UDamageType*, DamageType, class AController*, InstigatedBy, AActor*, DamageCauser);
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class MONSTERS_API UHealthComponent : public UActorComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
UHealthComponent();
// Use this to call the sound effect and blood splatter
UPROPERTY(BlueprintAssignable, Category="Events")
FOnHealthChangedSignature OnHealthChanged;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Health Component")
float MaxHealth;
UPROPERTY(ReplicatedUsing=OnRep_Health, EditDefaultsOnly, BlueprintReadOnly, Category="Health Component")
float Health;
UFUNCTION()
void OnRep_Health(float OldHealth);
float GetHealth() const;
protected:
// Called when the game starts
virtual void BeginPlay() override;
UFUNCTION()
void HandleTakeAnyDamage(AActor* DamagedActor, float Damage, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser);
};
Weapon.cpp
AWeapon::AWeapon() {
// Creating Collision Component
BaseCollision = CreateDefaultSubobject<USphereComponent>(TEXT("CollisionVolume"));
SetRootComponent(BaseCollision);
CombatCollision = CreateDefaultSubobject<UBoxComponent>(TEXT("CombatCollision"));
CombatCollision->SetupAttachment(GetRootComponent());
CombatCollision->SetRelativeScale3D(FVector(1,1,2));
CombatCollision->SetRelativeLocation(FVector(0,0,30));
if (HasAuthority())
{
CombatCollision->OnComponentBeginOverlap.AddDynamic(this, &AWeapon::CombatOnOverlapBegin);
CombatCollision->OnComponentEndOverlap.AddDynamic(this, &AWeapon::CombatOnOverlapEnd);
}
// Creating Mesh Component
Mesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
Mesh->SetupAttachment(GetRootComponent());
Mesh->SetRelativeScale3D(FVector(1.2,1.2,1.2));
Mesh->SetRelativeLocation(FVector(0,0,6));
Damage = 20.f;
DamageTypeClass = UDamageType::StaticClass();
bReplicates = true;
bNetUseOwnerRelevancy = true;
}
void AWeapon::BeginPlay() {
Super::BeginPlay();
// Handles Collision Parameters
CombatCollision->SetCollisionEnabled(ECollisionEnabled::NoCollision);
CombatCollision->SetCollisionObjectType(ECollisionChannel::ECC_WorldDynamic);
CombatCollision->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
CombatCollision->SetCollisionResponseToChannel(ECollisionChannel::ECC_Pawn, ECollisionResponse::ECR_Overlap);
}
void AWeapon::EquipWeapon(ACharacter* Char) {
if (Char) {
Mesh->SetCollisionResponseToChannel(ECollisionChannel::ECC_Camera, ECollisionResponse::ECR_Ignore);
Mesh->SetCollisionResponseToChannel(ECollisionChannel::ECC_Pawn, ECollisionResponse::ECR_Ignore);
Mesh->SetSimulatePhysics(false);
const USkeletalMeshSocket* RightHandSocket = Char->GetMesh()->GetSocketByName(TEXT("WeaponHand"));
if (RightHandSocket) {
RightHandSocket->AttachActor(this, Char->GetMesh());
}
}
}
void AWeapon::DamageMonster(AActor* OtherActor)
{
AMonsterCharacter* Monster = Cast<AMonsterCharacter>(OtherActor);
if (Monster)
{
UE_LOG(LogTemp, Warning, TEXT("Beef Central"));
if (DamageTypeClass)
{
UGameplayStatics::ApplyDamage(Monster, Damage, WeaponInstigator, this, DamageTypeClass);
UE_LOG(LogTemp, Warning, TEXT("After ApplyDamage"));
}
}
}
void AWeapon::CombatOnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult) {
if (OtherActor)
{
DamageMonster(OtherActor);
}
}
void AWeapon::CombatOnOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex) {
}
void AWeapon::ActivateCollision() {
CombatCollision->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
UE_LOG(LogTemp, Warning, TEXT("Activating Collision"));
}
void AWeapon::DeactivateCollision() {
CombatCollision->SetCollisionEnabled(ECollisionEnabled::NoCollision);
UE_LOG(LogTemp, Warning, TEXT("Dectivating Collision"));
}
void AWeapon::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const {
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(AWeapon, DamageTypeClass);
DOREPLIFETIME(AWeapon, Damage);
}
Weapon.h
UCLASS()
class MONSTERS_API AWeapon : public AActor
{
GENERATED_BODY()
public:
AWeapon();
/** Base shape collision */
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Item | Collision")
class USphereComponent* BaseCollision;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Item | Combat")
class UBoxComponent* CombatCollision;
// Base Mesh Component
UPROPERTY(VisibleAnywhere, BlueprintReadWrite, Category = "Item | Mesh")
class UStaticMeshComponent* Mesh;
UPROPERTY(Replicated, EditAnywhere, BlueprintReadWrite, Category = "Item | Combat")
float Damage;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item | Sound")
class USoundCue* SwingSound1;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item | Sound")
class USoundCue* SwingSound2;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Item | Sound")
class USoundCue* SwingSound3;
// Edited right here
UFUNCTION()
void CombatOnOverlapBegin(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
UFUNCTION()
void CombatOnOverlapEnd(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);
void EquipWeapon(class ACharacter* Char);
void DamageMonster(AActor* OtherActor); // Edited
UFUNCTION(BlueprintCallable)
void ActivateCollision();
UFUNCTION(BlueprintCallable)
void DeactivateCollision();
UPROPERTY(Replicated, EditAnywhere, BlueprintReadWrite, Category = "Combat")
TSubclassOf<UDamageType> DamageTypeClass;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Combat")
AController* WeaponInstigator;
FORCEINLINE void SetInstigator(AController* Inst) { WeaponInstigator = Inst; }
protected:
virtual void BeginPlay() override;