In this document page https://docs.unrealengine.com/en-US/Gameplay/Networking/Actors/Components/index.html , it said:
“Dynamic components are components spawned on the server at runtime and whose creation and deletion replicate down to clients. They work very much in the same way Actors do. Unlike static components, dynamic components need to replicate to exist on all clients.”
The following is my code snaps:
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class FPSONLINE_API UAttributesSetComponent : public UActorComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
UAttributesSetComponent();
protected:
// Called when the game starts
virtual void BeginPlay() override;
public:
// Called every frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
/* Property replication */
void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
/* current health */
UPROPERTY(replicated)
float CurrentHealth;
/* current bullets */
UPROPERTY(replicated)
int32 CurrentBullets;
};
void UAttributesSetComponent::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
// Replicate current health
DOREPLIFETIME(UAttributesSetComponent, CurrentHealth);
DOREPLIFETIME(UAttributesSetComponent, CurrentBullets);
}
// Projectile class
UCLASS()
class FPSONLINE_API AFPSOnlineProjectile : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
AFPSOnlineProjectile();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
virtual void Destroyed() override;
UFUNCTION(Category = "Projectile")
void OnProjectileImpact(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit);
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
/* Property replication */
void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
protected:
// Sphere component used to test collision
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Components")
class USphereComponent* SphereComponent;
// Static Mesh used to provide a visual representation of the object
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
class UStaticMeshComponent* StaticMesh;
// Movement
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
class UProjectileMovementComponent* ProjectileMovementComponent;
// explodes particles
UPROPERTY(EditAnywhere, Category = "Effects")
class UParticleSystem* ExplosionEffect;
// the damage type used by projectile
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Damage")
TSubclassOf<class UDamageType> DamageType;
// the damage dealt by this projectile
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Damage")
float Damage;
public:
UPROPERTY(replicated)
UAttributesSetComponent* AttributesSet;
};
// Sets default values
AFPSOnlineProjectile::AFPSOnlineProjectile()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
bReplicates = true;
// scene components
SphereComponent = CreateDefaultSubobject<USphereComponent>(TEXT("RootComponent"));
SphereComponent->InitSphereRadius(37.5f);
SphereComponent->SetCollisionProfileName(TEXT("BlockAllDynamic"));
RootComponent = SphereComponent;
// register hit event
if (GetLocalRole() == ROLE_Authority)
{
SphereComponent->OnComponentHit.AddDynamic(this, &AFPSOnlineProjectile::OnProjectileImpact);
}
// mesh
static ConstructorHelpers::FObjectFinder<UStaticMesh> DefaultMesh(TEXT("/Game/StarterContent/Shapes/Shape_Sphere.Shape_Sphere"));
StaticMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Mesh"));
StaticMesh->SetupAttachment(RootComponent);
// Set the Static Mesh and its position/scale if we successfully found a mesh asset to use.
if (DefaultMesh.Succeeded())
{
StaticMesh->SetStaticMesh(DefaultMesh.Object);
StaticMesh->SetRelativeLocation(FVector(0.f, 0.f, -37.5f));
StaticMesh->SetRelativeScale3D(FVector(0.75f, 0.75f, 0.75f));
}
// particles
static ConstructorHelpers::FObjectFinder<UParticleSystem> DefaultExplosionEffect(TEXT("/Game/StarterContent/Particles/P_Explosion.P_Explosion"));
if (DefaultExplosionEffect.Succeeded())
{
ExplosionEffect = DefaultExplosionEffect.Object;
}
// Movement Component
ProjectileMovementComponent = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("ProjectileMovement"));
ProjectileMovementComponent->SetUpdatedComponent(SphereComponent);
ProjectileMovementComponent->InitialSpeed = 1500.f;
ProjectileMovementComponent->MaxSpeed = 1500.f;
ProjectileMovementComponent->bRotationFollowsVelocity = true;
ProjectileMovementComponent->ProjectileGravityScale = 0.f;
// Damage
DamageType = UDamageType::StaticClass();
Damage = 10.f;
}
void AFPSOnlineProjectile::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
// Replicate
DOREPLIFETIME(AFPSOnlineProjectile, AttributesSet);
}
// AFPSOnlineCharacter class
// this function run on server side
void AFPSOnlineCharacter::HandleFire_Implementation()
{
FVector SpawnLocation = GetActorLocation() + (GetControlRotation().Vector() * 100.f) + GetActorUpVector() * 50.f;
FRotator SpawnRotation = GetControlRotation();
FActorSpawnParameters SpawnParameters;
SpawnParameters.Instigator = GetInstigator();
SpawnParameters.Owner = this;
AFPSOnlineProjectile* SpawnedProjectile = ()->SpawnActor<AFPSOnlineProjectile>(SpawnLocation, SpawnRotation, SpawnParameters);
SpawnedProjectile->AttributesSet = NewObject<UAttributesSetComponent>(SpawnedProjectile, TEXT("ProjectileAttributes"));
if (SpawnedProjectile->AttributesSet)
{
SpawnedProjectile->AttributesSet->SetNetAddressable(); // Make DSO components net addressable
SpawnedProjectile->AttributesSet->SetIsReplicated(true); // Enable replication by default
SpawnedProjectile->AttributesSet->RegisterComponentWithWorld(());
}
}
Now, When I press fire button in game, the HanleFire_Implementation() will run on server, and then a projectile actor is replicated to client, but the class data memeber AttributesSet can’t be replicated to client。
What’s wrong with me? Thanks.