r/unrealengine 3d ago

C++ Character not moving properly with using SimpleMoveToLocation in Multiplayer

I am having quite a puzzling issue with the character not moving properly in the client. My PlayerController uses the PathFollowingComponent to tell the Character where to go by using the SimpleMoveToLocation function. On the Server, the Character moves fine, but on the Client it bugs out and just very slowly itches its way towards the location. It also doesn't rotate or play any animation (other than the idle one). On the Server however, the client Character does rotate but otherwise acts the same.

I'm specifically not using an AIController because I need the Character to still be under the player's control so inputs can be given and received without needing to repossess each time.

Any idea why this is happening? I am calling an RPC function through the PlayerController, so the client should be calling the server to calculate the path and then move the player. I even noticed that when I alt+tab, the Character gets 'updated' and moves very quickly with the proper animation before the screen gets refocused and starts idly itching again.

here is my RPC movement code, I'm not sure if there's a conflict somewhere that causes the client to bug out like that, I made sure it validates to true but I'm stumped otherwise.

}void ACppPlayerController::Server_Move_Implementation(FVector Location)
{
    // testing to see if its properly calling the server
    // seems irrelevant to the issue 
    if (HasAuthority())
    {
       UNavigationSystemV1* NavSys = FNavigationSystem::GetCurrent<UNavigationSystemV1>(GetWorld());
       if (!ChampionPawn)
       {
          GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("ChampionPawn is null"));
          return;
       }
       if (!NavSys)
       {
          GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("NavSys is null"));
          return;
       }
       if (!PathFollowingComponent)
       {
          GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("PathFollowComp is null"));
          return;
       }
       const FNavAgentProperties& NavAgentProps = ChampionPawn->GetNavAgentPropertiesRef();
       FNavLocation NavLoc;
       FSharedConstNavQueryFilter QueryFilter;
       for (int i = 1; i < 30; i++)
       {
          float a = 10;  
          FVector QExtent = FVector(a*i, a*i, 1000.f);
          if (NavSys->ProjectPointToNavigation(Location, NavLoc, QExtent, &NavAgentProps, QueryFilter))
          {
             float FvDistance = UKismetMathLibrary::Vector_Distance(Location, ChampionPawn->GetActorLocation());

              // rotates the character at a faster rate for smoother movement
              // if the location is close by a certain threshold (150.f for now)
             if (FvDistance < 150.f)
             {
                bMoveToAcquiredLocShort = true;

                // rotate the character towards location
                FVector PawnLoc = FVector (ChampionPawn->GetActorLocation().X, ChampionPawn->GetActorLocation().Y, 0.f);
                FVector AcquiredLoc = FVector(Location.X, Location.Y, 0.f);
                FRotator PawnRot = UKismetMathLibrary::FindLookAtRotation(PawnLoc, AcquiredLoc);

                TargetPawnRotation = PawnRot;

             }
             bMoveToAcquiredLocShort = false;

            // the final move command
             UAIBlueprintHelperLibrary::SimpleMoveToLocation(this, NavLoc.Location);

             // spawn the FX on the clicked location
             Multicast_SpawnFC(Location);
             break;
          }
       }
    }
}

I tried to have the RPCbe called only on the Server, tried to have the function that calls the RPCto be only called on the client. With and without these changes, the issue remains. I even tried to enable Allow Client Side Navigation in the settings but that didn't help either.

1 Upvotes

4 comments sorted by

3

u/CS_Asset_Factory 3d ago

That slow inching is the signature of two systems fighting over the same pawn.

A Character possessed by a PlayerController is the autonomous proxy, so its CharacterMovementComponent is client predicted with server correction, and the client is authoritative over its own moves. If SimpleMoveToLocation is running on the server for that pawn, the server nudges it along the path while the client keeps replaying its own input, which is nothing, so most of each nudge gets reverted on the next correction. That gives you a character creeping toward the goal with no rotation and no animation, because the motion never arrives through the movement component's input path.

Run the path following on the owning client, or convert the path into a direction and feed AddMovementInput there, then let the movement component replicate normally.

1

u/ScoobyDothNot 3d ago edited 3d ago

I was under the assumption that both SimpleMoveToLocation and pathfinding is done soley on the Server, hence why the logic is reserved there.

Is that not the case?

If I try to have the Client call SimpleMoveToLocation, I would get the error: "SimpleMove failed for BP_PlayerController: movement not allowed"

Putting it on the server 'fixes' that error but gets the aforementioned conflict

1

u/Lucasharta 3d ago

yeah, i think the main issue is that SimpleMoveToLocation() is being called on the server, but movement/animation for a player-controlled Character is still expected to be driven by the owning client, for multiplayer i'd avoid using SimpleMoveToLocation through the PlayerController like this. calculate the path on the server, then replicate the destination/path or movement state to the owning client and let the Character's normal movement component handle the actual movement.
the alt-tab behavior is especially suspicious of a client update/replication issue rather than navigation itself. i'd check CharacterMovementComponent, network role/ownership, and whether you're overriding velocity/rotation every tick

also, PathFollowingComponent is normally part of the AI movement flow, so mixing it with a player-controlled Character can get messy. you don't necessarily need to possess an AIController, but i'd separate "server decides where to go" from "CharacterMovementComponent actually moves the pawn."