RPC not being called on server and player unique id is same for all clients

Hi,
First I’ll explain my project setup. I want to make a tile based environment and turn based multiplayer. Since i don’t need 1st person or 3rd person or any controller I created a blank project.

I use dedicated server with 2 clients (Settings which can be found under play button in editor). These are all the actors on the scene before I start the game.
world outliner.JPG
LevelCreator_BP is a c++ class that spawns replicated tile actors based on the level data (2D array). And it attach the UI in which i can name the player and select any character player wants to play and hit confirm.
3c7fac865bacc45060636f642a7111427520931b.jpeg
Once player enter the name select hero and click confirm I want this information should be sent to server and server is supposed to save this information with player name (or anything unique i can identify each client with). I set up a c++ function to be called when ever confirm button is called and I set up an RPC functions in LevelCreator(C++).

LevelCreator.h


UFUNCTION(Reliable, Server, WithValidation)
void Server_SetPlayerDetails(int32 pPlayerUniqueID, const FString &pPlayerName, const FString &pSelectedHero);
void Server_SetPlayerDetails_Implementation(int32 pPlayerUniqueID, const FString &pPlayerName, const FString &pSelectedHero);
bool Server_SetPlayerDetails_Validate(int32 pPlayerUniqueID, const FString &pPlayerName, const FString &pSelectedHero);


void SetPlayerDetails(const FString pPlayerName, const FString pSelectedHero);

LevelCreator.cpp


void ALevelCreator::SetPlayerDetails(const FString pPlayerName, const FString pSelectedHero) {
	if (!HasAuthority()) {
		int playerUniqueID = GetWorld()->GetGameState()->GetUniqueID();
		UE_LOG(LogTemp, Log, TEXT("%s unique id = %d"), *pPlayerName, playerUniqueID);
		Server_SetPlayerDetails(playerUniqueID, pPlayerName, pSelectedHero);
	}
}


void ALevelCreator::Server_SetPlayerDetails_Implementation(int32 pPlayerUniqueID, const FString &pPlayerName, const FString &pSelectedHero) {
	if (HasAuthority()) {
		// code to be excuted on server
		UE_LOG(LogTemp, Log, TEXT("Inside Implementation method on server"));
	}
}

bool ALevelCreator::Server_SetPlayerDetails_Validate(int32 pPlayerUniqueID, const FString &pPlayerName, const FString &pSelectedHero) {
	UE_LOG(LogTemp, Warning, TEXT("Validating the input sent to server."));
	return true;
}

SetPlayerDetails will be called when confirm button is clicked. I have read in documentation that every client will have a GameState actor and server will have a *GameMode *actor. So In SetPlayerDetails I check if its client and the get the GetUniqueId() and calling the Server_SetPlayerDetails function with those parameters.

Problem 1: I am getting unique ID as same value or both clients.

Problem 2: Initially when I ran this I got a warning like this.

So in level blueprint I got GetPlayerController and made it as owner to LevelCreator_BP actor in my level. (dragged and dropped the LevelCreator_BP actor from world outliner into blueprint)
ab065d7acfaf66c4093509b3bb2de3a18b1638ac.jpeg
After doing the warning stopped coming but the Server_SetPlayerDetails_Implementation or Server_SetPlayerDetails_Validate is never called.

This is the total log. The RPC is never called. I’m new to unreal and I must be doing multiple things wrong. What am I doing wrong? And how to fix it?

hey there,

im struggeling with this topic too. But i guess i can help you out in this case:

Once a Player successfully logged in on the server (GameMode::PostLogin) he has a UniqueNetID and other stuff which the server can use to identify a client.

However there are 2 values you can read from playercontroller:

  • Controller->PlayerState->PlayerID AND
  • Controller->PlayerState->UniqueID

Though im currently digging around and looking for the specific difference between those. However using PlayerID gives me different numbers for players after they logged in on the server.

Also i wouldnt mess around with changing ownership of actors.

Usually a level/map is owned by the server/host and is delivered to the clients, so they can join the map. Also this SetPlayerDetails is automatically done by the Gamemode (PreLogin, Login, PostLogin) and your client should be initialized after those events to participate in network sessions.

Cheers

Hi thanks for the reply.
I removed the connection in blueprint to SetOwner node. I logged HasNetOwner() value. It returns false. So i done have any owner to actor at all. How do I go around fixing that?
I see that the only way to get controller is


GetWorld()->GetGameState()->GetNetOwningPlayer()->PlayerController->PlayerState->PlayerId;

Since I dont have any owner, GetNetOwningPlayer() just return null.

You can also use


GetWorld()->GetFirstPlayerController()

Keep in mind this implementation won’t work well if you end up having multiple local clients.
Also you probably don’t want to trust the clients to send their UniqueID to the server and instead get the player’s UniqueID on the server after the RPC is received. This could be easily accomplished by moving the RPC to the PlayerController and then calling the RPC from your class.

Hey I tried what you said. Creating a custom controller extending APlayerController and moved the RPC calls into this custom controller and RPC are working now thanks a bunch :slight_smile:
In project settings i changed the default pawn to none and playercontroller to my custom playercontroller.Now RPCs are working and no pawn is being spawn so I can manually spawn the pawn which ever the player selects.
But does this mean that I need to have all my RPC calls inside the playercontroller? isn’t that bad designing?

After receiving RPC how can I know which client sent the RPC?

If the RPC is supposed to be called by a player it is good design to have it inside the PlayerController. It really depends on the functionality of the RPC.

On the Server side of the RPC inside the PlayerController you’ll have access to the PlayerState of that controller with its uniqueid and other information.

You always need a Player Controller, especially in Multiplayer. A player can call RPC’s on their Controller, Pawn, PlayerState, GameState by default, and any actor that you tell them they ‘Own’. However, the Server and Client both need to know that the player owns that item. Owner is replicated, so you call it server-side only.

The Server has a copy of all the Player Controllers, providing you just ‘join’ the servers’ game as normal. Don’t try to create them manually, same with Pawns. Override the way the GameMode creates pawns or you’ll be in for a bad time. I would strongly suggest studying AGameMode before going too far with this.

You won’t know which client sent the RPC, but obviously the Server knows which Player Controller it was and can determine if from that. You should never have to go as deep as needing the Unique Net ID though, this is the kind of stuff that the gameplay framework safely handles for you.