Download

Property in replicated component is NULL when trying to access it.

Disclaimer. I have little idea of what I’m doing, so please be patient!

I have setup simple 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()

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, 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()
		class ASystemAbility* GetButtonOne();
	UFUNCTION()
		class ASystemAbility* GetButtonTwo();
protected:
	UPROPERTY(BlueprintReadOnly, Replicated, Category = "Ability")
		class ASystemAbility* AbilityButtonOneObj;
	UPROPERTY(BlueprintReadOnly, Category = "Ability")
		class ASystemAbility* AbilityButtonTwoObj;

};


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)
{
	bReplicates = true;
}

void USystemAbilityManagerComponent::GetLifetimeReplicatedProps(TArray< class FLifetimeProperty > & OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);

	DOREPLIFETIME(USystemAbilityManagerComponent, AbilityButtonOneObj);
}

void USystemAbilityManagerComponent::AddAbility(TSubclassOf<ASystemAbility> ability, APawn* Owner)
{
	if (GetOwnerRole() < ROLE_Authority)
	{
		return;
	}

	ServerAddAbility(ability, Owner);
}


void USystemAbilityManagerComponent::ServerAddAbility_Implementation(TSubclassOf<class ASystemAbility> ability, APawn* Owner)
{
	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);
		//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.
		*/
		if (!AbilityButtonOneObj)
		{
			AbilityButtonOneObj = abilityTemp;
		}
		else if (!AbilityButtonTwoObj)
		{
			AbilityButtonTwoObj = abilityTemp;
		}
	}
}
bool USystemAbilityManagerComponent::ServerAddAbility_Validate(TSubclassOf<class ASystemAbility> ability, APawn* Owner)
{
	return true;
}

ASystemAbility* USystemAbilityManagerComponent::GetButtonOne()
{
	if (AbilityButtonOneObj)
	{
		return AbilityButtonOneObj;
	}
	return NULL;
}

ASystemAbility* USystemAbilityManagerComponent::GetButtonTwo()
{
	if (AbilityButtonTwoObj)
	{
		return AbilityButtonTwoObj;
	}
	return NULL;
}


AddAbility() function is called from Character Blueprint after BeginPlay event.

The properties are setup correctly to this point.

Then I have my Character:




AGameCharacter::AGameCharacter(const class FPostConstructInitializeProperties& PCIP)
	: Super(PCIP)
{
	bReplicates = true;
	//Manager Component Initialization:
	AbilityManager = PCIP.CreateDefaultSubobject<USystemAbilityManagerComponent>(this, TEXT("AbilityManager"));
	AbilityManager->SetNetAddressable();
	AbilityManager->SetIsReplicated(true);
}

void AGameCharacter::ActionButtonOne()
{
	EquipAction(AbilityManager->GetButtonOne());
}

void AGameCharacter::EquipAction(class ASystemAbility* Ability)
{
	if (Ability)
	{
		if (Role == ROLE_Authority)
		{
			SetCurrentAction(Ability);
		}
		else
		{
			ServerEquipAction(Ability);
		}
	}
}

bool AGameCharacter::ServerEquipAction_Validate(class ASystemAbility* Ability)
{
	return true;
}

void AGameCharacter::ServerEquipAction_Implementation(class ASystemAbility* Ability)
{
	EquipAction(Ability);
}

void AGameCharacter::OnRep_LeftHandAction(class ASystemAbility* LeftHandActionIn)
{
	SetCurrentAction(LeftHandAction);
}

void AGameCharacter::SetCurrentAction(class ASystemAbility* Ability)
{
	LeftHandAction = Ability;
}

void AGameCharacter::RunLeftHand()
{
	if (AbilityManager->LeftHandAction)
	{
		AbilityManager->LeftHandAction->InputPressed();
	}
}


ActionButtonOne is bound to Input, but that is no important part. The Important part is when I inspect in Debugger AbilityManager property all, properties that were set previously are NULL.

I’m total noob in networking. So any advice of what I’m doing wrong will be really helpful.

thanks for cncl2 on irc. He helped me solve issue. Basiccally poperty was not properly replicated. Createding another server function in chain, fixed it.