My character not moving anymore (in automated test) since upgrading to 5.7

Hello here.
I ask for a bit help since i lost my night on this bug.

This is my situation : I have a functionnal testing file, who simulate input in my PlayerController to test movement functions.

Here an example :

// Inventory.spec.cpp
#include "InputActionValue.h"
#include "Components/CapsuleComponent.h"
#include "Misc/AutomationTest.h"
#include "santa_marias_echoes/Tests/Helpers/TestWorldHelper.h"
#include "Slate/SceneViewport.h"
#include "Widgets/SViewport.h"

BEGIN_DEFINE_SPEC(FSMEPlayerControllerSpec,
                  "Santa_Maria_Echoes.PlayerController.SMEPlayerController",
                  EAutomationTestFlags::ProductFilter | EAutomationTestFlags::EditorContext)

	TArray<int32> Items;

END_DEFINE_SPEC(FSMEPlayerControllerSpec)

void FSMEPlayerControllerSpec::Define()
{
    It("Should move player if PC StrafePress method called (Strafe Left and Right)", [this]()
	{
		//--------------------------------------------------------------------
		// Given
		//--------------------------------------------------------------------
		FTestWorldWrapper TW = FTestWorldHelper::InitTestWorld(this);
		ASMEGameMode* GM = FTestWorldHelper::GetGameMode(TW);
		FTestWorldHelper::SpawnTestFloor(TW);
		FTestWorldHelper::TickForSeconds(TW, 10);

		GM->SetMatchState(MatchState::InProgress);

		ASMEPlayerController* PC = Cast<ASMEPlayerController>(GM->SpawnPlayerController(ROLE_Authority, ""));
		TestTrue(TEXT("PlayerController is ATestSMEPlayerController"), PC != nullptr);
		if (!PC) return false;

		PC->InitPlayerState();
		GM->RestartPlayerAtTransform(PC, FTransform(FVector(0, 0, 100)));

		FTestWorldHelper::TickForSeconds(TW, 10);

		TestTrue("Pawn is possessed", PC->GetPawn() != nullptr);
		if (!PC->GetPawn()) return false;

		ASMECharacter* CHARACTER = Cast<ASMECharacter>(PC->GetPawn());
		TestTrue(TEXT("Character is ASMECharacter"), CHARACTER != nullptr);
		if (!CHARACTER) return false;

		FTestWorldHelper::TickForSeconds(TW, 60);

		TestTrue("Character have a PlayerController", CHARACTER->GetController() != nullptr);
		if (!CHARACTER->GetController()) return false;
		TestTrue("Character have a PlayerController of type ASMEPlayerController", CHARACTER->GetController()->IsA(ASMEPlayerController::StaticClass()));

		const FVector InitialLocation = CHARACTER->GetActorLocation();

		//--------------------------------------------------------------------
		// When
		//--------------------------------------------------------------------
		FInputActionValue ActionValue(1.f);
		PC->StrafePressed(ActionValue);
		FTestWorldHelper::TickForSeconds(TW, 60);

		const FVector AfterRightLocation = CHARACTER->GetActorLocation();

		ActionValue = FInputActionValue(-1.f);
		PC->StrafePressed(ActionValue);
		FTestWorldHelper::TickForSeconds(TW, 60);

		const FVector AfterLeftLocation = CHARACTER->GetActorLocation();

		//--------------------------------------------------------------------
		// Then
		//--------------------------------------------------------------------
		TestTrue(TEXT("Character has moved right when StrafePressed with value 1"), AfterRightLocation.Y > InitialLocation.Y);
		TestTrue(TEXT("Character has moved left when StrafePressed with value -1"), AfterLeftLocation.Y < AfterRightLocation.Y);
		return true;
	});
}

Here the FTestWorldHelper :

#pragma once
#include "Components/BoxComponent.h"
#include "santa_marias_echoes/Core/Character/SMECharacter.h"
#include "santa_marias_echoes/Core/GameMode/SMEGameMode.h"
#include "santa_marias_echoes/Core/GameState/SMEGameState.h"
#include "santa_marias_echoes/Core/PlayerController/SMEPlayerController.h"
#include "santa_marias_echoes/Core/PlayerState/SMEPlayerState.h"
#include "santa_marias_echoes/Menu/SMEGameHud.h"
#include "Misc/AutomationTest.h"
#include "santa_marias_echoes/HUD/SMEHUD.h"
#include "Tests/AutomationCommon.h"

class FTestWorldHelper
{
public:
	static void ApplyDefaultClassSettings(ASMEGameMode* GameMode)
	{
		GameMode->DefaultPawnClass = ASMECharacter::StaticClass();
		GameMode->PlayerControllerClass = ASMEPlayerController::StaticClass();
		GameMode->HUDClass = ASMEHUD::StaticClass();
		GameMode->PlayerStateClass = ASMEPlayerState::StaticClass();
		GameMode->GameStateClass = ASMEGameState::StaticClass();
	}

	static FTestWorldWrapper InitTestWorld(FAutomationSpecBase* Spec, bool BeginPlay = true, TFunction<void(ASMEGameMode*)> OverideClassSettings = nullptr)
	{
		FTestWorldWrapper TW;
		Spec->TestTrue(TEXT("CreateTestWorld(Game)"), TW.CreateTestWorld(EWorldType::Game));
		
		UWorld* W = TW.GetTestWorld();
		Spec->TestNotNull(TEXT("World valid"), W);

		if (W->GetWorldSettings())
		{
			W->GetWorldSettings()->DefaultGameMode = ASMEGameMode::StaticClass();
		}
		
		bool bGMSet = (W->SetGameMode(FURL()));
		Spec->TestTrue(TEXT("SetGameMode(ATestSMEGameMode)"), bGMSet);
		if (BeginPlay)
		{
			Spec->TestTrue(TEXT("BeginPlayInTestWorld()"), TW.BeginPlayInTestWorld());	
		}

		ASMEGameMode* GM = TW.GetTestWorld()->GetAuthGameMode<ASMEGameMode>();
		ApplyDefaultClassSettings(GM);
		if (OverideClassSettings) OverideClassSettings(GM);
		
		Spec->TestTrue(TEXT("GameMode is ATestSMEGameMode"), GM != nullptr);
		
		return TW;
	}

	static void TickForSeconds(FTestWorldWrapper& TW, int32 Ticks)
	{
		for (int i = 0; i < Ticks; ++i)
		{
			TW.TickTestWorld(1.f / 60.f);
		}
	}

	static void TickForSeconds(FTestWorldWrapper& TW, int32 Ticks, TFunction<void()> PreTick)
	{
		for (int i = 0; i < Ticks; ++i)
		{
			PreTick();
			TW.TickTestWorld(1.f / 60.f);
		}
	}

	static ASMEGameMode* GetGameMode(FTestWorldWrapper& TW)
	{
		if (!TW.GetTestWorld()) return nullptr;
		return TW.GetTestWorld()->GetAuthGameMode<ASMEGameMode>();
	}

	static void SpawnTestFloor(FTestWorldWrapper& TW)
	{
		UWorld* World = TW.GetTestWorld();
		if (!World) return;

		FActorSpawnParameters SpawnParams;
		SpawnParams.Name = TEXT("TestFloor");
		AActor* Floor = World->SpawnActor<AActor>(AActor::StaticClass(), FTransform(FVector(0.f, 0.f, -10.f)), SpawnParams);

		// Crée une boîte collision statique qui bloque tout (dont Pawn)
		UBoxComponent* Box = NewObject<UBoxComponent>(Floor, TEXT("FloorBox"));
		Box->InitBoxExtent(FVector(5000,5000,10));
		Box->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
		Box->SetCollisionProfileName(UCollisionProfile::BlockAll_ProfileName);
		Box->SetGenerateOverlapEvents(false);
		Box->SetMobility(EComponentMobility::Static);

		Floor->SetRootComponent(Box);
		Box->RegisterComponent(); // important pour que la collision existe
	}
	
};

And finally this is my Character/Player Controller Move Function :

void ASMEPlayerController::StrafePressed(const FInputActionValue& InputActionValue)
{
	if (SMECharacter)
	{
		SMECharacter->MoveRight(InputActionValue.Get<float>());
	}
}

void ASMECharacter::MoveRight(float Value)
{
	if (Controller != nullptr && Value != 0.f)
	{
		const FRotator YawRotation(0.f, Controller->GetControlRotation().Yaw, 0.f);
		const FVector Direction(FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y));
		AddMovementInput(Direction, Value);
	}
}

In Unreal Engine 5.6 all work perfectly and all my test are successful.


When i have upgrade to 5.7 all test based on movement (CharMovement) not working anymore.

All check of position returns the same spawn position 0.0.100.

Obviously i have check all ptr/nullptr. Everything looks fine. I also debug and i don’t see anything bad.

The only track i have is the apperance of two new properties on UCharacterMovement class (bEnableScopedMovementUpdates & bEnableServerDualMoveScopedMovementUpdates)

( UCharacterMoverComponent | Unreal Engine 5.7 Documentation | Epic Developer Community )

which seems to refer a new system to handle movement & movement replication but i can’t confirm.

I will continue to investigate later this week but if anybody have a clue or solution i’ll take it :smiley: