Download

Visual Studio 2019 LNK2001 Error with Replicated Properties and RPCs

Hello!
I have been running into a very strange problem with my SetUsername RPC. It is a server-side RPC, so it has to run an implementation of the function, but when I add _Implementation to the end of SetUsername in the .cpp file, it causes a compiler error because Visual Studio does not recognize it as a definition. I have looked everywhere for a solution, but I have not found any information on this problem. I have included screenshots of both files with the function and errors visible. Any input is appreciated.

Thank you!

First of all you can’t use the std string type it should be the Unreal FString.

It also has to be a const reference parameter since RPC’s are Read Only.

You should prefix all RPC’s with whatever type of RPC they are “Server”, “Client”, “NetMulticast” to make it clear that it is an RPC when calling it.

Finally you should consider adding WithValidation to validate any RPC’s from clients.


UFUNCTION(Server, Reliable)
void ServerSetUserName(const FString& UserName);


void AMyActor::ServerSetUserName_Implementation(const FString& UserName)
{

}

Thank you for sharing all of this. My background is in C# and I am not very experienced with C++ in Unreal yet, and I definitely did not know I should be using FString instead of string. However, this, unfortunately, did not solve my problem. I compared mine with yours to make sure their formats matched and replaced the string type, but Visual Studio still does not recognize the _Implementation of my RPC.

Visual Studio will not recognize generated code before you compile.
I don’t use the “squiggles panel” at all with Unreal.

I have tried Building and Rebuilding, but both of them fail because of this error.

Make sure your class has “GENERATED_BODY()” in your class definition, and that your header file includes “CustomThirdPersonCharacter2.generated.h”

It has both of those as well, but SetUsername_Implementation is still not recognized as a definition of SetUsername. Here are complete copies of both files to help. Thank you so much to everyone for working with me.

.h


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

#pragma once

#include "CoreMinimal.h"
#include "AurorisNetworkTest4Character.h"
#include "Containers/UnrealString.h"
#include "CustomThirdPersonCharacter2.generated.h"

UCLASS()
class AURORISNETWORKTEST4_API ACustomThirdPersonCharacter2 : public ACharacter
{
GENERATED_BODY()

public:
// Sets default values for this character's properties
ACustomThirdPersonCharacter2();

UPROPERTY(EditAnywhere)
bool IsLocalPlayer;

UPROPERTY(Replicated, EditAnywhere)
FString PlayerUsername;

UPROPERTY(EditAnywhere)
class ACustomThirdPersonCharacter2* LocalPlayer;

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;

// Called to Determine what player belongs to the local client
void LocalPlayer_GetStatus();

UFUNCTION(Server, Reliable)
void SetUsername(const FString& Username);

};


.cpp


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


#include "CustomThirdPersonCharacter2.h"
#include "Kismet/GameplayStatics.h"
#include "AurorisGameInstance.h"
#include "Containers/UnrealString.h"

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

}

// Called when the game starts or when spawned
void ACustomThirdPersonCharacter2::BeginPlay()
{ Super::BeginPlay();
  LocalPlayer_GetStatus();
  if (IsLocalPlayer == true) {
  [INDENT=2]UAurorisGameInstance* AurorisGameInstance = Cast<UAurorisGameInstance>(GetGameInstance());[/INDENT]
  [INDENT=2]SetUsername(AurorisGameInstance->ClientUsername);[/INDENT]
  }
 }

// Called every frame
void ACustomThirdPersonCharacter2::Tick(float DeltaTime)
{ Super::Tick(DeltaTime);
 
}

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

// Called to Determine what player belongs to the local client
void ACustomThirdPersonCharacter2::LocalPlayer_GetStatus() { if (IsLocallyControlled()) {
  [INDENT=2]IsLocalPlayer = true;[/INDENT]
  }
  else {
  [INDENT=2]IsLocalPlayer = false;[/INDENT]
  [INDENT=2]TArray<AActor*> FoundActors;[/INDENT]
  [INDENT=2]UGameplayStatics::GetAllActorsOfClass(GetWorld(), ACustomThirdPersonCharacter2::StaticClass(), FoundActors);[/INDENT]
  [INDENT=2]for (int i = 0; i < FoundActors.Num(); i++) {[/INDENT]
  [INDENT=3]ACustomThirdPersonCharacter2* actor = Cast<ACustomThirdPersonCharacter2>(FoundActors*->GetClass());[/INDENT]
  [INDENT=3]if (actor->IsLocalPlayer == true) {[/INDENT]
  [INDENT=4]LocalPlayer = actor;[/INDENT]
  [INDENT=3]}[/INDENT]
  [INDENT=2]}[/INDENT]
  }
 }

void ACustomThirdPersonCharacter2::SetUsername_Implementation(const FString& Username)
{ PlayerUsername = Username;
 }

Through my troubleshooting efforts, I have disabled my Visual Studio error list so only the Unreal errors in the output show, and after removing all other problems except for this one, I get this error when I build:

I then tried commenting out any references to SetUsername and SetUsername_Instance and tried to build it, but the error remained. I wonder if this is connected to the root of the problem. My research seems to show that GetLifetimeReplicatedProps should be generated when the UnrealHeaderTool finds replicated UPROPERTIEs and that I shouldn’t have to do anything with it, so this error confuses me. Hopefully whatever the fix is will solve my issues with RPCs as well.

Note: I did try adding #include “Net/UnrealNetwork.h” because it was recommended as a fix in a few places, but that did not solve it

I have also tried making a test actor with a very basic replicated function called TestRep and I get the same error number, but it references TestRep_Implementation instead of GetLifetimeReplicatedProps, and I believe this is the original error I was fighting to begin with. I have also discovered that I can’t build with any replicated UPROPERTIES present in my code either because it throws the error shown in my previous post. I will include the second error and my test code for help troubleshooting. I am at a complete loss as to where I should go from here… Could it be something wrong with Visual Studio?

Error:

.h


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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Net/UnrealNetwork.h"
#include "Engine/Engine.h"
#include "Test.generated.h"

UCLASS()
class AURORISNETWORKTEST4_API ATest : public AActor
{ GENERATED_BODY()
 
  public: // Sets default values for this actor's properties
ATest();
 

protected: // Called when the game starts or when spawned
virtual void BeginPlay() override;
 
  public: // Called every frame
virtual void Tick(float DeltaTime) override;

UFUNCTION(Server, Reliable)
void TestRep();
 

};

.cpp


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


#include "Test.h"
#include "Net/UnrealNetwork.h"
#include "Engine/Engine.h"

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

}

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

}

// Called every frame
void ATest::Tick(float DeltaTime)
{ Super::Tick(DeltaTime);
 

}

void TestRep_Implementation() {

}

I AM SO HAPPY! I have found solutions to both of my problems.

The fix for the RPCs was simply selecting File/Refresh Visual Studio Project in the editor when any new RPCs have been added.

The fix for the replicated UPROPERTIES was adding this to my .cpp file, including a separate DOREPLIFETIME for each replicated property:


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

Thanks again to everyone who shared their input.