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:

Update : I’ve try a clean empty project with just one test (Move Forward) using only base class from engine (ACharacter, APlayerController, etc) and I reproduced the same behavior. Test work well in 5.6 and not work in 5.7.

I made a zip with the source file If anybody want to try.

I think I will report any investigation and wait some weeks or maybe 5.7.1.

TestTestFunctMove.zip (6.8 KB)

I just get errors when I try to open the file. It tells me that it needs to recompile and doesn’t open. The file is built with a different engine version.

It looks like it wasn’t packaged and exported properly.

It’s just 2 cpp file to add to any cpp project from IDE or file system. I dont exported it from Unreal Engine Editor. Open extracted folder with Visual Studio or Rider and start the engine from it.

Next open Session fronted tools, go to Automation tabs and run the SMEController test

It literally will not allow me to do that. I get a compiling error message every time I try.

Which IDE did you use ?

If I made project files and posted a copy of them here they will open in any version of the editor.

I guess I’ll try your steps with Visual Studio later because I haven’t needed to work with the code that way. Or I’ll see if the code can be copied into a project file.

Sorry for all the edits. I’m not at my computer right now. I was not familiar with using another editor to write and compile code for UE

I’ll try checking it in a few hours.

They made so many weird changes for 5.7 it’s a wonder how we can get anything done between versions.

1 Like

I had a bit of success getting it to load. This is the error log generated.

Test ‘Santa_Maria_Echoes.PlayerController.SMEPlayerController.Should move player if PC WalkPressed method called (Forward and Backward)’ completed with result ‘Fail’

LogGameMode: Match State Changed from EnteringMap to WaitingToStart [log]
LogGameMode: Match State Changed from WaitingToStart to InProgress [log]

Expected ‘Character has moved forward when WalkPressed with value 1’ to be true.

Stuff\TestTestFunctMove\Source\TestTestFuctMove\Test\SMEPlayerController.spec.cpp(67)

Here is the 5.7 character movement documentation. It’s the exact same code as the 5.6 documentation.

Indeed and this is the problem.

If you run the same test with 5.6 engine the test will be successful :confused:

So maybe its a bug with functionnal test environment launch by the editor when running tests suite.

Is there not a way to copy or export parameters from a working pawn? My pawn from the last version is still working. It was made within the editor and not manually scripted.

You can load any UAsset file (including Pawn blueprint) with LoadObject() function.

Here an example with an USkeletalMesh but can be adapted to use APawn base class

USkeletalMesh* BatteryMesh = LoadObject<USkeletalMesh>(nullptr, TEXT("/Game/Mesh/Props/Battery/SKM_Battery.SKM_Battery"));
		if (BatteryMesh)
		{
			Battery->BatteryMesh->SetSkeletalMesh(BatteryMesh);
		}

The TEXT params is the Copy Reference action from Right Click on Content Browser

But you can’t call blueprint method if you have the intention.

1 Like

Hello guys,
Quick update, even in 5.7.2 the problem is present.

So there are two possibilities :

  • (Breaking) change was really wanted by developpers and i must change my solution (or delete the test if i dont find anything) OR
  • I do things (full testing) that so few person does (even AAA studio ::joy: ) that nobody even open ticket

I think i keep an eye on the next patch but for now i staying on 5.6

good day