We’re implementing a new model for our movement component and while it works in single player it appears to have some replication issues in multiplayer. When using the setup below online the pawn appears to skip for other users and spectators while moving as if the movement component is not being used and the underlying replication code is teleporting the pawn after it moves by some distance.
`UCLASS(Abstract)
class UMovementComponentBase : public UPawnMovementComponent
{
…
}
UCLASS(Blueprintable, BlueprintType, ClassGroup = (Custom), meta = (BlueprintSpawnableComponent))
class UMovementComponentBaseV1 : public UMovementComponentBase
{
UPROPERTY(Replicated)
FVehicleState ReplicatedState;
…
}
UCLASS(Blueprintable, BlueprintType, ClassGroup = (Custom), meta = (BlueprintSpawnableComponent))
class UMovementComponentBaseV2 : public UMovementComponentBase
{
UPROPERTY(Replicated)
FVehicleState ReplicatedState;
…
}
class AOurPawn : public APawn
{
…
UPROPERTY(Transient, Category = VehiclePhysics, VisibleAnywhere, BlueprintReadOnly)
class UMxVehicleMovementComponentBase* MovementComponent = nullptr;
…
}
//This gets called after PostInitializeComponents() but before BeginPlay()
void AOurPawn::ProcessMovementComponent()
{
…
UClass* LoadedClass = Cast(VehicleCDO->MovementComponentClass.TryLoad());
FString movementComponentName = FString::Printf(TEXT(“%s”), *LoadedClass->GetName());
MovementComponent = NewObject(this, LoadedClass, *movementComponentName, RF_Transient, NULL);
MovementComponent->SetUpdatedComponent(RootComponent);
…
}`
I’ve added some additional logging in LogNetSerialization and LogNetPackageMap but I don’t see any warnings or errors. I’ve also verified that the UMovementComponentBaseV1 and UMovementComponentBaseV2 are receiving network updates to the components RPC functions and replicated variables (e.g. ReplicatedState) on all clients and server. Is there something we are doing incorrectly setting up the MovementComponent in the above code? Our previous working movement component was created using CreateDefaultSubobject in the pawn’s constructor but because we want to the class defined in the CDO this isn’t an option for this model. Any help is greatly appreciated.
Hi,
To get a better idea of the problem, I have a couple of questions.
First, just to clarify, you mentioned that the movement components are receiving network updates. Is this data being received as expected on both versions, or are there gaps, missing updates, or any other differences between V1 and V2?
Next, you mentioned that your older movement component, which is a default subobject, is working. If you create this new movement component as a default subobject, do you still see the same issues or does movement replicate as expected?
Also, does your pawn override the ReplicateSubobjects function to do anything custom there?
Finally, just for context, how are you testing this? Is this in single process PIE, standalone editor instances, etc?
Thanks,
Alex
Hey Alex,
Yes, the data being received as expected on both versions and they behave the same way.
The new movement component couldn’t be defined as a default subobject because when we try to load the class from the CDO it’s null. I believe this is because using the CDO within constructor isn’t allowed because the CDO isn’t fully constructed yet. Also, trying to create a default subobject outside of the constructor yielded errors. Is there a way to either create the movement component as a default subobject using the CDO outside the constructor or creating a default subobject outside the constructor?
We aren’t overriding ReplicateSubobjects for our pawn.
We’ve tested this in a standalone client connecting to a local windows dedicated server as well as many standalone clients connecting to our cloud servers with the same outcome.
Hey Andrew, I have a few questions and things to double check.
1. Is your movement component (only) created by the server and (only) replicated to the client?
Your ProcessMovementComponent() function constructs a new object. I would expect that the server is the only game instance creating the component as a dynamic replicated subobject. The object would then replicate to clients and the client somehow stores it as a reference. So are the following all true?
- Only the server should create the component, is this the case?
- Your AOurPawn class’s MovementComponent UPROPERTY isn’t replicated. How does the client resolve a reference to the replicated movement component?
2. Does your use case allow constructing the movement component in the constructor, after all?
I see that the movement component class isn’t known beforehand. When is it known and does it change during gameplay?
“Our previous working movement component was created using CreateDefaultSubobject in the pawn’s constructor but because we want to the class defined in the CDO this isn’t an option for this model.”
Do you mean you want the component class to be configurable in blueprints of this actor class? You can already do this in the blueprint by selecting the component and changing the Component Class. The screenshot below shows how to change the character movement component class. I know yours is a more generic pawn movement component, but that can also be changed in the BP editor. If the class is not known yet in the editor (i.e. your runtime code decides it, or some data asset sets it) then this approach doesn’t work.
[Image Removed]