RPC Issues / Questions

Hey Guys.

I have looked all over and read a lot of documentation (that I will post at the end of this) but cannot seem to get my server function to work! Thus, I turn to you for help.

My guess is that it has to do with the PlayerCharacter->Role, but I am unsure what other actor I would check it against though.


In blueprints


Thank you all again for the assistance.

https://docs.unrealengine.com/latest/INT/Gameplay/Networking/Example/index.html

I should have also added. It is always returning “Client”. Function called from a widget that is in the players viewport.

The first thing that stands out, is that you do not define the “_implementation” & “_Validate” functions in the header.

the engine will handle that for you via its own Macros & provided flags for your “ServerAddGold” function.

So I would start by taking out those two lines from header and recompile. In earlier engine versions, you wouldn’t have been able to compile with that current header setup.

Leave your CPP file as is, you are correct in your setup for those two.

Are you seeing this error in the game itself while connected to a dedicated server, or are you in Editor? If in Editor… do you have the Dedicated Server option enabled from the “Play” drop down?

What do you mean I didn’t define them? The first image is the header file the 2nd is the cpp.

Trying your header file suggestion.

The error is that it isn’t running on the server. It is only client side, and therefore doesn’t update the gold and broadcast the change.

I do have dedicated server ticked.

A server function will never not be ROLE_AUTHORITY. This means your condition that checks if its less than that will never be true because its called on the server.

This condition will only ever be useful if you call it from a function that can be called by either a server or a client, or authority or remote.

You could do something like:

void MyActor::GiveGold(int Amount)
{
    if(Role < ROLE_AUTHORITY)
    {
       // Client called this function, call server function
       ServerGiveGold(Amount);
    }
    else
    {
      // Always called from the authority here
      PlayerController->GiveGold(Amount);
    }
}

void MyActor::ServerGiveGold_Implmentation(int Amount)
{
    // Always server, when it calls GiveGold, it will be authority
    GiveGold(Amount);
}

Yep! I have that check to let me know if it’s running with or without authority. Thus the else statement with the “SERVER” text.

I am trying to run this with authority, so where should I call this? It was my understanding that since it’s labeled Server and Reliable that it would call from the server, thus printing SERVER to the screen right? I am just not understanding where to call this from in order for it to run on the server with authority.

Having that check in the server function wont do anything. It will always be authority in a server function. You do not need to check for it.

It shouldn’t matter where you call it, it should print, “SERVER”.

The only time this wont happen is if you are calling from the client side that doesnt have any owning actor that can replicate or if the actor you are calling it from is not replicated.

It was mainly for debugging purposes, but yea it shouldnt. It does return CLIENT though, that’s the weird part. I am going to give your snippet a try, thanks for the help.

I also just noticed that you are using OnClicked, which I am guessing is from a HUD class.

HUD is always client side, calling a server function from a HUD class might have some issue in what is and what isnt “Authority”. Remember, Authority is not always the server but that which is “in charge” that actor, in a way. HUD for example can have an authority check be true on the client because the client is the authority from the HUD.

Edit:

To clarify this a little:

HUD wont have permission to replicate anything to the server because the server doesnt have a copy of it. This means that if you try, it will treat the function differently, which probably means it will flat out fail to call.

Also, make sure you are in a networked environment by either running a dedicated server - set through the Play options - or by running more than 1 client, meaning one is a “listen server”, acting as the server.

HUD Actor doesn’t exist in the server.

You need to get a reference from your HUD to a class the server also has, such as the Player Controller or Pawn/Character.

So, OnClick gets the local pawn which can then get the local player controller, which then can call a server function, which will then replicate because the server and client both have a copy of the player controller.

Thank you very much for all this information! How would you suggest I go about completing this?

Thanks! What do you suggest I do to achieve the results I want?

This is off the top of my head:

UserWidget:

void MyUserWidget::OnClickedGoldButton( )
{
	AMyPlayerController *MyController = Cast<AMyPlayerController>(GetOwningPlayer( ));
	if(MyController)
	{
		MyController->AddGold( );
	}
}

Player Controller:

void MyPlayerController:AddGold( )
{
	// Assumption made here that AddGold will always be called by MyUserWidget, which is the client side
	if(Role < ROLE_Authority)
	{
		ServerAddGold( );
	}
}

bool MyPlayerController::ServerAddGold_Validate( )
{
	return true;
}

void MyPlayerController::ServerAddGold_Implementation( )
{
	Gold += 1;
}

UserWidget:

void MyUserWidget::OnClickedGoldButton( )
{
	AMyPlayerController *MyController = Cast<AMyPlayerController>(GetOwningPlayer( ));
	if(MyController)
	{
		MyController->AddGold( );
	}
}

Player Controller:

void MyPlayerController:AddGold( )
{
	if(Role < ROLE_Authority)
	{
		ServerAddGold( );
	}
	else
	{
		Gold += 1;
	}
}

bool MyPlayerController::ServerAddGold_Validate( )
{
	return true;
}

void MyPlayerController::ServerAddGold_Implementation( )
{
	AddGold( );
}

I am setting the reference to the player and controller on initialization. I am then calling a function from the PlayerState class. It is my understanding that these are handled by both the client and server. I have used the same function in other places, like adding gold when you kill an enemy. It is just from the widget that I can’t get it to work.

Right now I am only calling it on the widget using the replicated server function.

I wouldn’t call the replicated function directly from the widget. I would have the Widget call the PlayerController (not PlayerState). The PlayerController would then check to see what the Authority is and then either call the server function or if it is the authority, change the Gold value.

Look at my other answer above.