Hi Again
I’m trying to do something fairly simple, spawn an actor on the server, and get the clients to receive a local copy (which I’ll tear off once I get the !#£$ spawn bit working). I have an class that extends from AActor. Its abstract, and I create the actual class in a blueprint, and the blueprint gets added to my character class as a “BloodTrailClass”.
Everything I’ve read says that if I set the bReplicates or SetReplicates(true) then it should replicate. I’ve put bAlwaysRelevant so that it should go to every client.
No matter what I try, the actor only spawns on the server and is never replicated to the client. Any advice on what I’ve done wrong or how to debug it (would spawn failures get logged somewhere?) would be great.
.h file
#pragma once
#include "FFBloodTrailGib.generated.h"
/**
*
*/
UCLASS(Abstract, BlueprintType)
class FIREFIGHT_API AFFBloodTrailGib : public AActor
{
GENERATED_UCLASS_BODY()
/** gib mesh */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Gib)
UStaticMeshComponent* Mesh;
/** Sphere collision component */
UPROPERTY(VisibleDefaultsOnly, Category = Projectile)
USphereComponent* CollisionComp;
/** Projectile movement component */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Movement)
class UProjectileMovementComponent* ProjectileMovement;
/** particle effect generated as a a trail for this gib*/
UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Effects)
UParticleSystem* TrailEffect;
void BeginPlay();
UFUNCTION()
void EffectTimer();
UFUNCTION(BlueprintImplementableEvent, meta = (FriendlyName = "Create Trail effect"))
void CreateTrailEffect();
UFUNCTION()
void OnPhysicsCollision(AActor* OtherActor, UPrimitiveComponent* HitComponent, FVector NormalImpulse, const FHitResult& Hit);
};
.cpp file
// Fill out your copyright notice in the Description page of Project Settings.
#include "FireFight.h"
#include "FFProjectileMovementComponent.h"
#include "FFBloodTrailGib.h"
AFFBloodTrailGib::AFFBloodTrailGib(const FObjectInitializer& PCIP)
: Super(PCIP)
{
//Replication
bAlwaysRelevant = true;
SetReplicates(true);
bReplicates = true;
PrimaryActorTick.bCanEverTick = true;
Mesh = PCIP.CreateOptionalDefaultSubobject<UStaticMeshComponent>(this, FName(TEXT("Mesh")));
if (Mesh != NULL)
{
Mesh->bReceivesDecals = false;
Mesh->SetCollisionProfileName(FName(TEXT("CharacterMesh")));
Mesh->SetCollisionObjectType(ECC_PhysicsBody);
Mesh->SetCollisionResponseToChannel(ECC_Visibility, ECR_Ignore);
Mesh->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
Mesh->SetNotifyRigidBodyCollision(true);
Mesh->OnComponentHit.AddDynamic(this, &AFFBloodTrailGib::OnPhysicsCollision);
Mesh->SetIsReplicated(true);
}
RootComponent = Mesh;
CollisionComp = PCIP.CreateOptionalDefaultSubobject<USphereComponent>(this, TEXT("SphereComp"));
if (CollisionComp != NULL)
{
CollisionComp->InitSphereRadius(0.0f);
CollisionComp->BodyInstance.SetCollisionProfileName("Projectile"); // Collision profiles are defined in DefaultEngine.ini
CollisionComp->OnComponentHit.AddDynamic(this, &AFFBloodTrailGib::OnPhysicsCollision);
CollisionComp->bTraceComplexOnMove = true;
RootComponent = CollisionComp;
CollisionComp->SetIsReplicated(true);
}
InitialLifeSpan = 3.0f;
// Use a ProjectileMovementComponent to govern this projectile's movement
ProjectileMovement = PCIP.CreateDefaultSubobject<UFFProjectileMovementComponent>(this, TEXT("ProjectileComp"));
ProjectileMovement->UpdatedComponent = CollisionComp;
ProjectileMovement->InitialSpeed = 3000.f;
ProjectileMovement->MaxSpeed = 3000.f;
ProjectileMovement->bRotationFollowsVelocity = true;
ProjectileMovement->bShouldBounce = false;
ProjectileMovement->SetIsReplicated(true);
}
void AFFBloodTrailGib::BeginPlay()
{
GetWorldTimerManager().SetTimer(this, &AFFBloodTrailGib::EffectTimer, (FMath::FRand() * 0.4f) + 0.02f, true);
}
void AFFBloodTrailGib::EffectTimer()
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, FString::Printf(TEXT("Blood Trail Tick")));
CreateTrailEffect();
// TODO: Add a decal on the floor each time this tick happens.
}
void AFFBloodTrailGib::OnPhysicsCollision(AActor* OtherActor, UPrimitiveComponent* HitComponent, FVector NormalImpulse, const FHitResult& Hit)
{
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Blue, FString::Printf(TEXT(" Blood Trail collide - %s"), *OtherActor->GetHumanReadableName()));
}
The spawn call
if (Role == ROLE_Authority)
{
checkSlow(BloodTrailClass != NULL);
// try and fire a projectile
const FVector SpawnLocation = Weapon->GetFireStartLoc();//GetActorLocation();// +NewRelHitLocation;
const FRotator SpawnRotation = ShotRot;
FActorSpawnParameters SpawnParams;
SpawnParams.bNoCollisionFail = true;
SpawnParams.Owner = this->GetOwner();
AFFBloodTrailGib* Gib = GetWorld()->SpawnActor<AFFBloodTrailGib>(BloodTrailClass, SpawnLocation, SpawnRotation, SpawnParams);
}