I have any issue with replicating property in Components.
Component Header:
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "SystemAbilityManagerComponent.generated.h"
UCLASS(meta = (BlueprintSpawnableComponent), hidecategories = (Object, LOD, Lighting, Transform, Sockets, TextureStreaming))
class USystemAbilityManagerComponent : public UActorComponent
{
GENERATED_UCLASS_BODY()
virtual void InitializeComponent() OVERRIDE;
UPROPERTY(EditAnywhere, Category = "Abilities")
TArray<TSubclassOf <class ASystemAbility> > AbilityTypes;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Replicated, Category = "Ability|Manager")
TArray<class ASystemAbility*> AbilityList;
/*
Stub function. Just for testing, probably will need change o removed, do not overuse it!
*/
UFUNCTION(BlueprintCallable, Category = "Ability|Manager")
void AddAbility(TSubclassOf<class ASystemAbility> ability, APawn* Owner);
UFUNCTION(Server, Reliable, WithValidation)
void ServerAddAbility(TSubclassOf<class ASystemAbility> ability, APawn* Owner);
public:
UFUNCTION(BlueprintCallable, Category = "Ability")
class ASystemAbility* GetButtonOne();
UFUNCTION()
class ASystemAbility* GetButtonTwo();
UFUNCTION()
void OnRep_AbilityButtonOne();
void SetActionButton(class ASystemAbility* AbilityIn);
//INPUT HANDLING:
UFUNCTION(Server, Reliable, WithValidation)
void ServerActionButtonOne();
UPROPERTY(BlueprintReadOnly, Transient, ReplicatedUsing = OnRep_LeftHandAction, Category = "Action Buttons")
class ASystemAbility* LeftHandAction;
UFUNCTION()
void OnRep_LeftHandAction(class ASystemAbility* LeftHandActionIn);
UFUNCTION()
void EquipAction(class ASystemAbility* Ability);
UFUNCTION(Server, Reliable, WithValidation)
void ServerEquipAction(class ASystemAbility* Ability);
void SetCurrentAction(class ASystemAbility* Ability);
protected:
UPROPERTY(BlueprintReadOnly, ReplicatedUsing=OnRep_AbilityButtonOne, Category = "Ability")
class ASystemAbility* AbilityButtonOneObj;
UPROPERTY(BlueprintReadOnly, Category = "Ability")
class ASystemAbility* AbilityButtonTwoObj;
};
And here is implementation:
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
#include "Game.h"
#include "../Abilities/SystemAbility.h"
#include "Net/UnrealNetwork.h"
#include "SystemAbilityManagerComponent.h"
USystemAbilityManagerComponent::USystemAbilityManagerComponent(const class FPostConstructInitializeProperties& PCIP)
: Super(PCIP)
{
SetIsReplicated(true);
bReplicates = true;
}
void USystemAbilityManagerComponent::GetLifetimeReplicatedProps(TArray< class FLifetimeProperty > & OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(USystemAbilityManagerComponent, AbilityButtonOneObj);
DOREPLIFETIME(USystemAbilityManagerComponent, LeftHandAction);
DOREPLIFETIME_CONDITION(USystemAbilityManagerComponent, AbilityList, COND_OwnerOnly);
}
void USystemAbilityManagerComponent::InitializeComponent()
{
}
void USystemAbilityManagerComponent::AddAbility(TSubclassOf<ASystemAbility> ability, APawn* Owner)
{
if (GetOwnerRole() < ROLE_Authority)
{
ServerAddAbility(ability, Owner);
return;
}
ServerAddAbility(ability, Owner);
}
void USystemAbilityManagerComponent::ServerAddAbility_Implementation(TSubclassOf<class ASystemAbility> ability, APawn* Owner)
{
//if pawn already have incoming ability, we don't need to spawn it, we simply return;
if (AbilityList.Num() > 0)
{
for (ASystemAbility* abilityI : AbilityList)
{
if (abilityI->IsA(ability))
return;
}
}
if (ability && Owner)
{
//URPGAbilityBase* abilityObj = ConstructObject<URPGAbilityBase>(ability);
//abilityObj->Initialize(Owner, Owner->Controller);
FActorSpawnParameters SpawnParams;
SpawnParams.Owner = Owner;
SpawnParams.bNoCollisionFail = true;
ASystemAbility* abilityTemp = GetWorld()->SpawnActor<ASystemAbility>(ability, SpawnParams);
abilityTemp->AbilityOwner = Owner;
abilityTemp->Initialize();
AbilityList.AddUnique(abilityTemp);
SetActionButton(abilityTemp);
//AbilityList.AddUnique(abilityObj);
/*
this should be handled by drag&drop UI
where user just drag ability from ability inventory to hot bar
in more elaborate scenario there can be more layers to it. Like dragging
Spells to spell slots (to prepare them)
and then dragging prepared spells to hotbar.
Either way this is just debug solution that should be changed.
*/
}
}
bool USystemAbilityManagerComponent::ServerAddAbility_Validate(TSubclassOf<class ASystemAbility> ability, APawn* Owner)
{
return true;
}
void USystemAbilityManagerComponent::SetActionButton(class ASystemAbility* AbilityIn)
{
if (!AbilityButtonOneObj || AbilityButtonOneObj->IsA(AbilityIn->GetClass()))
{
AbilityButtonOneObj = AbilityIn;
}
else if (!AbilityButtonTwoObj)
{
AbilityButtonTwoObj = AbilityIn;
}
}
void USystemAbilityManagerComponent::OnRep_AbilityButtonOne()
{
SetActionButton(AbilityButtonOneObj);
}
ASystemAbility* USystemAbilityManagerComponent::GetButtonOne()
{
if (AbilityButtonOneObj)
{
return AbilityButtonOneObj;
}
return NULL;
}
ASystemAbility* USystemAbilityManagerComponent::GetButtonTwo()
{
if (AbilityButtonTwoObj)
{
return AbilityButtonTwoObj;
}
return NULL;
}
void USystemAbilityManagerComponent::ServerActionButtonOne_Implementation()
{
EquipAction(AbilityButtonOneObj);
}
bool USystemAbilityManagerComponent::ServerActionButtonOne_Validate()
{
return true;
}
void USystemAbilityManagerComponent::EquipAction(class ASystemAbility* Ability)
{
if (Ability)
{
if (GetOwnerRole() == ROLE_Authority)
{
SetCurrentAction(Ability);
}
else
{
ServerEquipAction(Ability);
}
}
}
bool USystemAbilityManagerComponent::ServerEquipAction_Validate(class ASystemAbility* Ability)
{
return true;
}
void USystemAbilityManagerComponent::ServerEquipAction_Implementation(class ASystemAbility* Ability)
{
EquipAction(Ability);
}
void USystemAbilityManagerComponent::OnRep_LeftHandAction(class ASystemAbility* LeftHandActionIn)
{
SetCurrentAction(LeftHandAction);
}
void USystemAbilityManagerComponent::SetCurrentAction(class ASystemAbility* Ability)
{
LeftHandAction = Ability;
}
The issue is with LeftHandAction andAbilityButtonOneObj, they are simply not properly replicated to client.
And here is where I tried to use LeftHandAction
void AGameCharacter::RunLeftHand()
{
if (AbilityManager->LeftHandAction)
{
AbilityManager->LeftHandAction->InputPressed();
}
}
If I tried to do it this way, LeftHandAction is NULL, because it was not replicated.
So I changed it to work like this:
void AGameCharacter::RunLeftHand()
{
if (Role < ROLE_Authority)
{
ServerRunLeftHand();
}
}
void AGameCharacter::ServerRunLeftHand_Implementation()
{
if (AbilityManager->LeftHandAction)
{
AbilityManager->LeftHandAction->InputPressed();
}
}
bool AGameCharacter::ServerRunLeftHand_Validate()
{
return true;
}
And now it works. But, that doesn’t solve problem. Because I still need to replicte ability to client, to get some of it’s properties displayed on HUD (for example indicator if the ability is equiped at all).