Download

How to call non-RPC function from a RPC to run in server

I have a UI that shows all character types in client. Client select character and when confirm is clicked a RPC is called on server. Since all RPCs have to be called from player controller, I have another function inside another actor called LevelCreator and the character spawning code is in the LevelCreator. I made LevelCreator a singleton class. so Inside the RPC on server


void ADemoHexaGamePlayerController::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"));

		ALevelCreator::getInstance()->PlayerChooseCharacter(pPlayerName, pSelectedHero);
	}
}

I get the LevelCreator instance and call the PlayerChooseCharacter function. This is PlayerChooseCharacter function inside level creator.


void ALevelCreator::PlayerChooseCharacter(const FString& p_PlayerName, const FString& p_CharacterType){
	if (HasAuthority()) {
		UE_LOG(LogTemp, Log, TEXT("Inside PlayerChooseCharacter"));
	}
}

But this function is never called. How can I call this function.

It looks like there may be an issue with your singleton setup. Is the function not being called at all or is it just not passing the authority check?

Its not passing the authority check. If i remove the authority check i can see the log being printed.
I did the singleton like all singleton classes.
Create a private static pointer of type ALevelCreator* thisInstance inside ALevelCreator.
Then created a public static function


static ALevelCreator* getInstance()

and inside the constructor of ALevelCreator I assigned the static thisInstance to this


ALevelCreator(){
   ALevelCreator::thisInstance = this;
}

and finally the getInstance function


ALevelCreator* ALevelCreator::getInstance(){
   return ALevelCreator::thisInstance;
}

Irrespective of server or client there has to be different instances stored for each client and server rit? I’m running 2 clients and a dedicated server on same machine. Does this effect singleton class? Does it save the same pointer to all the instances of client and server running since its on same machine?

Can you post the code where you define the RPCs in your header file?

This is the player controller in which the RPC is defined


class DEMOHEXAGAME_API ADemoHexaGamePlayerController : public APlayerController
{
	GENERATED_BODY()
	
public:
		void SetPlayerDetails(const FString pPlayerName, const FString pSelectedHero);
	
		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);
};

and the implementation


void ADemoHexaGamePlayerController::SetPlayerDetails(const FString pPlayerName, const FString pSelectedHero) {
	if (!HasAuthority()) {
		// called when confirm button is pressed on client
		int playerUniqueID = GetWorld()->GetFirstLocalPlayerFromController()->PlayerController->PlayerState->PlayerId;
		Server_SetPlayerDetails(playerUniqueID, pPlayerName, pSelectedHero);
	}
}


void ADemoHexaGamePlayerController::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"));

		ALevelCreator::getInstance()->PlayerChooseCharacter(pPlayerName, pSelectedHero);
	}
}

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

And there is a C++ class that extent AActor class called ALevelCreator


class DEMOHEXAGAME_API ALevelCreator : public AActor
{
	GENERATED_BODY()

public:	
	// Sets default values for this actor's properties
	ALevelCreator();
	
	// static function to make this class as singleton class
	static ALevelCreator* getInstance();
	void PlayerChooseCharacter(const FString& p_PlayerName, const FString& p_CharacterType);
};

and in LevelCreator.cpp



ALevelCreator * ALevelCreator::thisInstance;

// Sets default values
ALevelCreator::ALevelCreator()
{
	// assigning the instance to the static variable
	ALevelCreator::thisInstance = this;
}

ALevelCreator* ALevelCreator::getInstance() {
	return ALevelCreator::thisInstance;
}

void ALevelCreator::PlayerChooseCharacter_Implementation(const FString& p_PlayerName, const FString& p_CharacterType){
	if (HasAuthority()) {
		UE_LOG(LogTemp, Log, TEXT("%s selected %s hero type"), *p_PlayerName, *p_CharacterType);
	}
}

I included the singleton code also incase if i did anything wrong there.

Is there a reason why you are using a singleton? The actor won’t function properly if you are never actually spawning it. You can always spawn anot instance of the actor and then get a reference to it in the world. You can even replicate it to clients that way.

I already dragged and dropped the ALevelCreator actor into the world.

Really! I can do that? I don’t know how to do this which is why I’m using singleton to get the instance. As I mentioned earlier, I’m a noob in unreal and this is just learning phase :slight_smile:
How can I get reference from the world of an actor in C++? If this can be done then there is no reason for singleton class at all

EDIT: never mind. I found this

I’ll try this and update here what happened.

OMG thanks this worked. If anyone faces same problem in future, here is the answer


for (TActorIterator<ALevelCreator> Itr(GetWorld()); Itr; ++Itr)
{
	Itr->PlayerChooseCharacter(pPlayerName, pSelectedHero);	
}

EDIT: I wonder why singleton didn’t work. If there is any explanation for this, I would like to know :slight_smile:

The reason is because the actor is isn’t initialized properly. You are not actually spawning it when you access it the way you were.