Cannot call server RPC from clients

I have a class that does not respond to RPC calls when called from a client. However, there’s no problems when called from the server.

I have a Board object in my level (that is, dragged and dropped into the level) that creates a bunch of Piece objects during its BeginPlay()call, but only when HasAuthority() is true, so the pieces are only created in the server. I can verify that the pieces are being replicated properly in the clients, as they are instantiated and updated correctly whenever a change in the server occurs. bReplicates = true is set in both Board and Piece.

The function I’m attempting to call is located in the board, the pieces being its callers.

The order of actions is as follows:

  1. A Piece object calls ClientSelect().
  2. ClientSelect() calls ServerSelect(). ServerSelect()has the macro properties Reliable, Server, WithValidationdefined. To my understanding, this should delegate the execution from the client to the server.
  3. ServerSelect_Implementation(), contained and called in the server calls Select(), which contains the selection logic.

Board.h:

void ClientSelect(int32 Row, int32 Col);
UFUNCTION(Reliable, Server, WithValidation)
void ServerSelect(int32 Row, int32 Col);
virtual bool ServerSelect_Validate(int32 Row, int32 Col);
virtual void ServerSelect_Implementation(int32 Row, int32 Col);

Board.cpp:

void Board::ClientSelect(int32 Row, int32 Col)
{
	UE_LOG(LogTemp, Warning, TEXT("Client is attempting to select Piece at %d,%d A:%d"), Row, Col, HasAuthority());
	ServerSelect(Row, Col);
}

bool Board::ServerSelect_Validate(int32 Row, int32 Col)
{
	UE_LOG(LogTemp, Warning, TEXT("Validating"));
	return true;
}

void Board::ServerSelect_Implementation(int32 Row, int32 Col)
{
	UE_LOG(LogTemp, Warning, TEXT("Server is attempting to select Piece at %d,%d A:%d"), Row, Col, HasAuthority());
	if (State == GAME)
	{
		if (Grid[Row][Col]->Piece == nullptr)
		{
			UE_LOG(LogTemp, Warning, TEXT("Client attempted to select a nonexisting Piece at %d,%d"), Row, Col);
			return;
		}

		AProjectPiece* Piece = Grid[Row][Col]->Piece;
		Select(Piece);
	}
}

Output from server:

LogTemp:Warning: Client is attempting to select Piece at 6,2 A:1
LogTemp:Warning: Validating
LogTemp:Warning: Server is attempting to select Piece at 6,2 A:1
LogTemp:Warning: Selecting piece at 6,2

Output from client:

LogTemp:Warning: Client is attempting to select Piece at 6,2 A:0

Things I have tried, to no avail:

  • Setting SetOwner(GetWorld->GetFirstPlayerController())of the board in the server. However, without this HasAuthority() already properly returns truewhen called from the server and falsewhen called from a client.
  • Moving all of the RPC calls to the Piece objects.

I have the same issue.

I have exactly the same issue (on 4.8.2), i cannot setup a Connection to the Server. There is no warning or error, it simply dosent work. In BeginPlay() or Init Functions the exaclty same RPC call works. Where is the problem? Thank you for any answers.

same problem

So the issue ends up being that the object you’re calling the function on has no “owner” set since it’s just being dropped into the level. If the object has no owner then any network functions wont work. Also, if you set the owner to the server’s player controller it will appear as NULL on a client’s machine because each client only knows about their own player controller.

The way I was able to get around this is to set the owner to the player controller who is currently interacting with that object. The tricky thing is that you have to call SetOwner ON the server side. Hopefully the steps bellow will explain better.

The following would be a case if a client uses the mouse to select an object in the scene to call a network function on.

// This function happens on the client and would be a callback for input
MyPlayerController::ProcessMouseDown(x, y)
{
   // Since we're in the player controller network functions will work just fine
   SelectObject_Server(x, y);
}

// This function gets called on the server's version of the same player controller
MyPlayerController::SelectObject_Server(x, y)
{
   // Find object below mouse cursor
   obj = RayCast(x, y);
   
   obj->SetOwner(this);

   // At this point we can call both server and client functions on the object
   obj->ClientSelect();
}

Let me know if this is unclear and I can include an actual code sample. I’m just being lazy for now :slight_smile:
Also this might be wrong for future versions of Unreal… this was my hacky solution in 4.8.3.

Also note the behavior of RPC’s functions on clients for server owned versions: 虚幻引擎中的RPC | 虚幻引擎5.2文档

I didn’t understand your solution. I am trying to call server event from Widget how can i do this?