How do I replicate a UProceduralMeshComponent?

I am trying to wrap my head around replication (networking) in ue4 but it is just not clicking. I have created yet another basic voxel world and want to replicate each chunk as it is changed by clients. My first attempt was to replicate only the UProceduralMeshComponent in the hopes that it was somehow serialized and would just work.

AChunk.h




UCLASS()
class AChunk : public AActor
{
	GENERATED_BODY()

public:	

	AChunk(const FObjectInitializer& objectInitializer);

	void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const;

	void CreateSurface();

private:

	UPROPERTY(Replicated, meta = (AllowPrivateAccess = "true"))
	UBoxComponent* boundary;

	UPROPERTY(Replicated, meta = (AllowPrivateAccess = "true"))
	UProceduralMeshComponent* surface;


};



AChunk.cpp Constructor




AChunk::AChunk(const FObjectInitializer& objectInitializer)
	: Super(objectInitializer)
{
	bReplicates = true;
	bReplicateMovement = true;

	boundary = objectInitializer.CreateDefaultSubobject<UBoxComponent>(this, TEXT("Boundary"));
	boundary->SetNetAddressable();
	boundary->SetIsReplicated(true);
	RootComponent = boundary;

	surface = objectInitializer.CreateDefaultSubobject<UProceduralMeshComponent>(this, TEXT("Surface"));
	surface->SetNetAddressable();
	surface->SetIsReplicated(true);
	surface->AttachTo(boundary);
}

void AChunk::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
	DOREPLIFETIME(AChunk, boundary);
	DOREPLIFETIME(AChunk, surface);
}

void AChunk::CreateSurface()
{
	if (!HasAuthority())
		return;

	// code to update the procedural mesh
}



This did not work as I had hoped and I cannot find enough information to know why. Both of the two major resources I have found (linked below) only explain the general concepts and emphasize how things work like magic, rather than explaining the gritty details and limitations you must consider.

For example:

  1. Does the actor that spawned this actor need to be replicated for the spawning of this actor to replicated to each client?
  2. Do replicated properties need to be public?
  3. Does UPROPERTY(Replicated) only work on primitive types?

I am really confused by this whole replication process and it is made even more difficult by the fact that it is invisible and so much stuff happens automatically that can either be true replication or just look like it (simultaneous object creation on client & server).

The direction I am thinking about trying next is to just try and replicate a “TMap<FIntVector, int32> voxelMap” for each AChunk and rebuild UProceduralMeshComponent on each client when AChunk is replicated but I don’t know if this is a work around or the correct way to approach this.

Thanks in advance for anyone who at least read this :).

Resources:

Hopefully someone can give some insight to this.

I can tell you that replicated properties do not need to be public at least.

Most of the time components are not replicated at all (with the notable exception of the character movement component). So you will have to manually send the information so the client can build its own copy of the procedural mesh component.

I don’t think you can just add the component to the replicated properties list and have it work… But I haven’t tried!

Even if you could however, sending vertex data over the network can cause allot of traffic! So it’s probably best to send something smaller, like config information, so the client can generate its own identical copy instead.

  1. Actor that called SpawnActor() doesn’t need to be replicated, however this spawning has to happen on server (or on Authorative client that is currently acting as server)
  2. Replicated properties don’t have to be public; replication works when property is updated on the server, and will be sent to all connected clients (and clients that connect later).
  3. UPROPERTY(Replicated) works on replicated actors and replicated components. Say if Actor is replicated but component isn’t, component’s property will not be replicated regardless of how its declared.

ProceduralMeshComponent, however, doesn’t have built-in replication. You’ll need to code it yourself. Even if you mark component as replicated, ProcMeshSections array inside of it is not marked as replicated. Further complication is that you can’t replicate arrays larger than about 1000 elements. UDP is not very friendly towards sending large chunks of data.

Your declaration within actor is correct, and replication would correctly create a new blank ProceduralMeshComponent that needs to be initialized separately on each client. Effectively, replication would be useless.

Your best bet would be to replicate instructions that will cause ProceduralMeshComponent to be created the same way on all connected clients.

Good luck!