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;
}