bReplicates Resets to False after Construction

I’m trying to implement a player inventory system in a networked game. I’m using a UActorComponent to do the inventory system and I’m having some issues with replication.

following this official unreal guide I have something like this (Note the log statements):


class AMyCharacter : public ACharacter {

    AMyCharacter() {

        ...

        Inventory = CreateDefaultSubobject<UInventoryComponent>(TEXT("Inventory"));

        if (Inventory) {

            Inventory->SetIsReplicated(true);

        }

        // Prints 1 (true) on server AND client

        UE_LOG(LogTemp, Warning, TEXT("Inventory replication %d"), Inventory->GetIsReplicated());

    }

    void BeginPlay() {

        // Prints 0 (false) on server AND client

        UE_LOG(LogTemp, Warning, TEXT("Inventory replication %d"), Inventory->GetIsReplicated());

    }

    ...

    private:

    UPROPERTY(Replicated)

    UInventoryComponent* Inventory;

};

class GAME_API UInventoryComponent : public UActorComponent {

    ...

    private:

    UPROPERTY(Replicated)

    uint16 Capacity;

    ...

};

The problem is that the Inventory member variables don’t replicate. I was able to narrow the problem down a little by putting those print statements in. As you can see GetIsReplicated() returns false after the constructor. Why does this happen?

I have also tried setting SetIsReplicated and/or SetIsReplicatedByDefault to true in Inventory constructor and that didn’t work.

Another piece of information that could be useful is that I believe inventory replication was working perfectly fine with this exact code (I use version control) and this is the second time such thing happens. The first time it magically fixed itself :slight_smile:

I’ve found a workaround since but I would like to know why this is happening. The workaround is to call SetIsReplicated(true) in BeginPlay() of character class on the server

I think this might be related https://answers.unrealengine.com/questions/661810/question-constructor-vs-beginplay.html

For Components, SetIsReplicatedByDefault() is the one to use at constructor time. For actors, you are supposed to set bReplicates directly.

The latter is a confusing and frankly silly implementation that skirts around issues caused by calling SetReplicates() in constructors, like adding uninitialized actors to net drivers before they’ve been fully serialized. There’s a tonne of better ways to do it, I’ve no idea why Epic chose this method.

Note that you do not need to replicate the “Inventory” pointer. It’s a default sub-object and is therefore stably named. There’s a good chance some existing blueprint serialization is overriding the value you set in the constructor. My advice would be to recreate the blueprint, or check it’s saved values.

1 Like