Server does not call client's animation blueprint tick when Replicate Movement is off

Steps to replicate this:

  1. Create a project using the ThirdPerson feature pack
  2. Remove the player pawn in the map and add a player start
  3. Change the game mode to ThirdPersonGameMode
  4. Set number of players in the multiplayer options to 2 (under play)
  5. Go to ThirdPerson_AnimBP and add a print right after the update animation call (see img below)
  6. Run the project and you should see 4 prints: two server side, two client side
  7. Go to ThirdPersonCharacter blueprint and untick Replicate Movement
  8. Run the project again and there are 3 prints: one server side, two client side

Sorry if this is an intended function of replicates movement, but it is confusing as only the server has this problem. If you set it to 3 players you can see that all clients run each other’s animation blueprints (including the server).

][1]

Hi fpwong,

I have confirmed that “Update Animation” is not firing in the Client Characters on the server with “Replicate Movement” disabled. I have an email out to one of our engineers to see if this is expected or not.

-.

Hi fpwong,

We have not heard back from you in a few days, so we are marking this post as Resolved for tracking purposes. If you are still experiencing the issue you reported, please respond to this message with additional information and we will offer further assistance.

-.

Bumping this as I had given up on multiplayer soon after I posted the original question. Currently using 4.14 and I’m experiencing the same issue.

I looked through the source code and I believe it is in the PossessedBy function (lines 796-800) of Character.cpp:

// If we are controlled remotely, set animation timing to be driven by client’s network updates. So timing and events remain in sync.
if (Mesh && (GetRemoteRole() == ROLE_AutonomousProxy && GetNetConnection() != nullptr))
{
Mesh->bAutonomousTickPose = true;
}

I believe there is something wrong with the checks in the if statement. When replicate movement is off, bAutonomousTickPose is set to true on any clients, which shouldn’t be happening.

I made a class that inherited from Character in C++ and overrode the PossessedBy function to include a check for bReplicateMovement and this worked:

Super::PossessedBy(NewController);

// If we are controlled remotely, set animation timing to be driven by client's network updates. So timing and events remain in sync.
if (GetMesh() && (GetRemoteRole() == ROLE_AutonomousProxy && GetNetConnection() != nullptr) && bReplicateMovement)
{
	GetMesh()->bAutonomousTickPose = true;
}
else
{
	GetMesh()->bAutonomousTickPose = false;
}

Anyway I don’t know if there are any implications that may occur from doing this but it seems to have fixed what I wanted to do. So the requests to fix this either:

  1. Expose bAutonomousTickPose to blueprints
  2. Edit the if statement in PossessedBy in Character.cpp to:

if (GetMesh() && (GetRemoteRole() == ROLE_AutonomousProxy && GetNetConnection() != nullptr) && bReplicateMovement)

Hey fpwong,

I’ve entered UE-39346 for this and have noted your potential fixes. Thanks for reporting this.

-.

Thank you for sharing your solution. It works like a charm!

Oh man… so it’s really a bug =( and 4.17 is soo far away

fpwong is there a tutorial on how to do the things you suggested for the fix? Have no Idea how to expose to blueprints…

You have to make a c++ class to fix this. Very simple addition though.

  1. Make a character in C++ call it like MyCharacter
  2. Add the PossesedBy function to the .h file
  3. Add the code below to the .cpp file

Make PossessedBy function in MyCharacter.h

virtual void PossessedBy(AController* NewController) override;

Add to MyCharacter.cpp

void MyCharacter::PossessedBy(AController* NewController)
{
	Super::PossessedBy(NewController);

	// If we are controlled remotely, set animation timing to be driven by client's network updates. So timing and events remain in sync.
	if (GetMesh() && (GetRemoteRole() == ROLE_AutonomousProxy && GetNetConnection() != nullptr) && bReplicateMovement)
	{
		GetMesh()->bOnlyAllowAutonomousTickPose = true;
	}
	else
	{
		GetMesh()->bOnlyAllowAutonomousTickPose = false;
	}
}

dude, you are awesome. Thank you so much for the tutorial. IT WORKS!! \o/o//o/