Download

Compiler gone wild

Game of mine worked perfectly before. Now it cannot even compile. It gives me compile errors in places where I think everything is correct.
Output:


CarBase.h:

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Pawn.h"
#include "CarMovementComponent.h"
#include "CarBase.generated.h"

USTRUCT()
struct FCarState
{
	GENERATED_BODY()


		UPROPERTY()
		FRotator Rotation;

	UPROPERTY()
		FVector Location;

	UPROPERTY()
		FVector Velocity;

	UPROPERTY()
		FCarMove LastMove;
};

UCLASS()
class SPEED_API ACarBase : public APawn
{
	GENERATED_BODY()

public:
	// Sets default values for this pawn's properties
	ACarBase();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	 
	// Called every frame
	virtual void Tick(float DeltaTime) override;

	

	// Called to bind functionality to input
	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

	UFUNCTION(BlueprintCallable)
		void SetMeshOffsetRoot(USceneComponent* Root) { MeshOffsetRoot = Root; }

	UPROPERTY(EditAnywhere)
		USkeletalMeshComponent* Mesh;
private:
	void MoveForward(float Val);
	void MoveRight(float Val);
	UPROPERTY()
		USceneComponent* MeshOffsetRoot;

	UPROPERTY(VisibleAnywhere)
		UCarMovementComponent* MovementComponent;

	void ClearAckonowledgedMoves(FCarMove LastMove);

	UFUNCTION(Server, Reliable, WithValidation)
		void Server_SendMove(FCarMove Move);

	UPROPERTY(ReplicatedUsing = OnRep_ServerState)
		FCarState ServerState;

	UFUNCTION()
		void OnRep_ServerState();
	void SimulatedProxy_OnRep_ServerState();
	void AutonomousProxy_OnRep_ServerState();

	TArray<FCarMove> UnackonowledgedMoves;

	float ClientTimeSinceUpdate;
	float ClientTimeBetweenLastUpdates;
	FTransform ClientStartTransform;
	FVector ClientStartVelocity;

	float ClientSimulatedTime;

	void ClientTick(float DeltaTime);


};
CarBase.cpp
// Fill out your copyright notice in the Description page of Project Settings.


#include "CarBase.h"

#include "Engine/World.h"
#include "DrawDebugHelpers.h"
//#include "GameFrameWork/GameState.h"
#include "Net/UnrealNetwork.h"
#include "Engine/CollisionProfile.h"

// Sets default values
ACarBase::ACarBase()
{
 	// Set this pawn to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	bReplicates = true;
	
	MovementComponent = CreateDefaultSubobject<UCarMovementComponent>(TEXT("MovementComponent"));
	//ReplicationComponent = CreateDefaultSubobject<UCarReplicationComponent>(TEXT("ReplicationComponent"));
	Mesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Car"));
	Mesh->SetCollisionProfileName(UCollisionProfile::Vehicle_ProfileName);
	Mesh->BodyInstance.bSimulatePhysics = true;

	RootComponent = Mesh;
}



// Called when the game starts or when spawned
void ACarBase::BeginPlay()
{
	Super::BeginPlay();

	SetReplicateMovement(false);

	if (HasAuthority())
	{
		NetUpdateFrequency = 5;
	}
}

void ACarBase::GetLifetimeReplicatedProps(TArray< FLifetimeProperty >& OutLifetimeProps) const
{
	Super::GetLifetimeReplicatedProps(OutLifetimeProps);
	DOREPLIFETIME(ACarBase, ServerState);
}

FString GetEnumText(ENetRole Role)
{
	switch (Role)
	{
	case ROLE_None:
		return "None";
	case ROLE_SimulatedProxy:
		return "SimulatedProxy";
	case ROLE_AutonomousProxy:
		return "AutonomousProxy";
	case ROLE_Authority:
		return "Authority";
	default:
		return "ERROR";
	}
}
// Called every frame
void ACarBase::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	if (MovementComponent == nullptr)
	{
		UE_LOG(LogTemp, Error, TEXT("MovementComponent failed in %s"), *GetName());
	}

	if (GetLocalRole() == ROLE_AutonomousProxy)
	{
		FCarMove Move = MovementComponent->CreateMove(DeltaTime);
		MovementComponent->SimulateMove(Move);

		UnackonowledgedMoves.Add(Move);
		Server_SendMove(Move);

		//UE_LOG(LogTemp, Warning, TEXT("Queue length %d"), UnackonowledgedMoves.Num());
	}

	if (GetLocalRole() == ROLE_Authority && GetRemoteRole() == ROLE_SimulatedProxy)
	{
		FCarMove Move = MovementComponent->CreateMove(DeltaTime);
		Server_SendMove(Move);
	}

	if (GetLocalRole() == ROLE_SimulatedProxy)
	{
		ClientTick(DeltaTime);
	}

	DrawDebugString(GetWorld(), FVector(0, 0, 100), GetEnumText(GetLocalRole()), this, FColor::White, DeltaTime);
}




// Called to bind functionality to input
void ACarBase::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	PlayerInputComponent->BindAxis("MoveForward", this, &ACarBase::MoveForward);
	PlayerInputComponent->BindAxis("MoveRight", this, &ACarBase::MoveRight);
}

void ACarBase::MoveForward(float Val)
{
	if (MovementComponent == nullptr) return;
	MovementComponent->SetThrottle(Val);
}

void ACarBase::MoveRight(float Val)
{
	if (MovementComponent == nullptr) return;
	MovementComponent->SetSteeringForce(Val);
}

void ACarBase::OnRep_ServerState()
{
	if (GetLocalRole() == ROLE_AutonomousProxy)
	{
		AutonomousProxy_OnRep_ServerState();
	}
	if (GetLocalRole() == ROLE_SimulatedProxy)
	{
		SimulatedProxy_OnRep_ServerState();
	}
	

}
void ACarBase::SimulatedProxy_OnRep_ServerState()
{
	if (MovementComponent == nullptr) return;
	ClientTimeBetweenLastUpdates = ClientTimeSinceUpdate;
	ClientTimeSinceUpdate = 0;
	if (MeshOffsetRoot != nullptr)
	{
		ClientStartTransform.SetLocation(MeshOffsetRoot->GetComponentLocation());
		ClientStartTransform.SetRotation(MeshOffsetRoot->GetComponentQuat());
	}

	ClientStartVelocity = MovementComponent->GetVelocity();
	SetActorLocation(ServerState.Location);
	SetActorRotation(ServerState.Rotation);
}
void ACarBase::AutonomousProxy_OnRep_ServerState()
{
	if (MovementComponent == nullptr) return;

	UE_LOG(LogTemp, Error, TEXT("Sranie"));
	SetActorLocation(ServerState.Location);
	SetActorRotation(ServerState.Rotation);
	MovementComponent->SetVelocity(ServerState.Velocity);

	ClearAckonowledgedMoves(ServerState.LastMove);

	for (const FCarMove& Move : UnackonowledgedMoves)
	{
		MovementComponent->SimulateMove(Move);
	}
}

void ACarBase::ClientTick(float DeltaTime)
{
	ClientTimeSinceUpdate += DeltaTime;
	if (ClientTimeBetweenLastUpdates < KINDA_SMALL_NUMBER) return;
	if (MovementComponent == nullptr) return;

	FVector TargetLocation = ServerState.Location;
	float LerpRatio = ClientTimeSinceUpdate / ClientTimeBetweenLastUpdates;
	float VelocityToDerivative = ClientTimeBetweenLastUpdates * 100;
	FVector StartDerivative = ClientStartVelocity * VelocityToDerivative;
	FVector TargetDerivative = ServerState.Velocity * VelocityToDerivative;
	FVector NextLocation = FMath::CubicInterp(ClientStartTransform.GetLocation(), StartDerivative,  TargetLocation, TargetDerivative, LerpRatio);
	if (MeshOffsetRoot != nullptr)
	{
		MeshOffsetRoot->SetWorldLocation(NextLocation);
	}


	FVector NewDerivative = FMath::CubicInterpDerivative(ClientStartTransform.GetLocation(), StartDerivative, TargetLocation, TargetDerivative, LerpRatio);
	FVector NewVelocity = NewDerivative / VelocityToDerivative;
	MovementComponent->SetVelocity(NewVelocity);

	FQuat TargetRotation = ServerState.Rotation.Quaternion();
	FQuat NextRotation = FQuat::Slerp(ClientStartTransform.GetRotation(), TargetRotation, LerpRatio);
	if (MeshOffsetRoot != nullptr)
	{
		MeshOffsetRoot->SetWorldRotation(NextRotation);
	}
}

void ACarBase::Server_SendMove_Implementation(FCarMove Move)
{
	if (MovementComponent == nullptr) return;
	//UE_LOG(LogTemp, Error, TEXT("SussyBalls"));
	ClientSimulatedTime += Move.DeltaTime;
	MovementComponent->SimulateMove(Move);

	ServerState.LastMove = Move;
	ServerState.Location = GetActorLocation();
	ServerState.Rotation = GetActorRotation();
	ServerState.Velocity = MovementComponent->GetVelocity();
}

bool ACarBase::Server_SendMove_Validate(FCarMove Move)
{
	float ProposedSimulatedTime = ClientSimulatedTime + Move.DeltaTime;
	bool RunningAhead = ProposedSimulatedTime > GetWorld()->TimeSeconds;
	if (RunningAhead || FMath::Abs(Move.Throttle) > 1 || FMath::Abs(Move.SteeringForce) > 1)
	{
		return false;
		UE_LOG(LogTemp, Error, TEXT("Sraczka"));
	}
	
	return true;
}

void ACarBase::ClearAckonowledgedMoves(FCarMove LastMove)
{
	TArray<FCarMove> NewMoves;

	for (const FCarMove& Move : UnackonowledgedMoves)
	{
		if (Move.Time > LastMove.Time)
		{
			NewMoves.Add(Move);
		}
	}

	UnackonowledgedMoves = NewMoves;
}

Usually the first compiler error is the only one you really have to worry about. That error is pretty clear that the FCarMove structure is undefined at the point where you’re trying to create an instance in your FCarState structure.

It should never have compiled, but if I had to guess it’s because of the unity build process that mashes up multiple source files into a single file to actually compile. Sometimes this means that a file will pick up definitions from the other files it’s mashed up with and if it has then compiler errors can happen when it’s mashed up with different files. Usually files you’re working on should be excluded from this process so that they’re compiled in an isolated manner. I know it will do it for files that are checked out of Perforce, but I’m not sure how it works with no source control or other source control systems like git.

At work we have an automated process that runs overnight to compile the project with the unity build option disabled. There was an Epic talk by someone on the Fortnite team and they do the same thing. I don’t recommend doing it for local builds as it can increase build times dramatically.

FCarMove is defined in another class. What can I do?

Include the header in which FCarMove is defined

@FinalRockstar is correct, you would include the proper header.

However based on the question, it sounds like you may want to spend a little time learning C++ outside the context of Unreal.

I did that already. It is included in CarMovementComponent.h.

Then you’ll need to post the code for that header as well.

Right, sorry
here it is:

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "CarBase.h"
#include "CarMovementComponent.generated.h"

USTRUCT()
struct FCarMove
{
	GENERATED_BODY()


		UPROPERTY()
		float Throttle;

	UPROPERTY()
		float SteeringForce;

	UPROPERTY()
		float DeltaTime;

	UPROPERTY()
		float Time;

};

UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class SPEED_API UCarMovementComponent : public UActorComponent
{
	GENERATED_BODY()

public:	
	// Sets default values for this component's properties
	UCarMovementComponent();

protected:
	// Called when the game starts
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;

	void SimulateMove(const FCarMove& Move);
	FCarMove CreateMove(float DeltaTime);

	void SetVelocity(FVector Val) { Velocity = Val; };
	FVector GetVelocity() { return Velocity; };

	void SetThrottle(float Val) { Throttle = Val; };
	void SetSteeringForce(float Val) { SteeringForce = Val; };

private:
	
	ACarBase* Car;

	FVector Velocity;
	void UpdateLocation(float DeltaTime);
	void UpdateRotation(float DeltaTime, float SteeringForceLocal);

	FVector GetAirResistance();
	FVector GetRollResistance();

	UPROPERTY(EditAnywhere)
	float Mass = 1000; // in Kg
	UPROPERTY(EditAnywhere)
	float MaxGrindSet = 9000; // in N
	UPROPERTY(EditAnywhere)
	float MinTurnRadius = 10; // in M

	UPROPERTY(EditAnywhere)
	float DragCoefficient = 12; 

	UPROPERTY(EditAnywhere)
	float RollingResistanceCoefficient = 0.01;

	float Throttle;
	float SteeringForce;
};

Oh, you’ve got a circular include! CarComponent.h includes CarBase.h which includes CarComponent.h. So it was probably compiling fine until you added the CarBase include to the component header. This is something that is not allowed/supported in C++ generally (as opposed to just in UE4).

I assume you did that when you added the ACarBase* Car member of the component?

The thing that you’ll need to do is remove the include of CarBase.h and instead use a forward declaration of class ACarBase; towards the top of your header (generally these are placed immediately after includes and before any type declarations like the one for FCarMove). Then you would include CarBase.h in CarComponent.cpp so that it compiles properly.

Generally you only want to include the things that you absolutely have to. And if you’re only using a type as a pointer or reference, you don’t have to. When you need to know more than just “the type exists” (as when you include the FCarMove in FCarState) you have to do the include. It gets a bit muddier in UE4 because of the generated code it makes for reflection/blueprints, but that’s the general gist of it. Again, a solid grounding in general C++ can help here a lot.

Thank you! I thought it won’t make any difference.