Hey all,
My setup is a boardgame designed for 4 Players, most functionality already exists in single player and now I am trying to add the multiplayer funcionality ( which I admit was stupid to wait until now ). Generally, my first idea is to have the server set up mostly everything, like generating card actors, etc. which will then be simply replicated on the client. This part works almost on itself as far as I can tell through the bReplicates boolean.
The second idea would be, that any action performed on a client should simply be instead called on the server through a simple RPC, and there it’s result will be broadcasted back automatically, through the replication process mentioned in idea #1. Luckily, there are many tutorials on using RPCs tagged as “server” which should mean they are called from a client but executed only on the server ( which would be perfect for my case ). Although I got this compiled and running, the RPC doesn’t call my server function.
In my understanding, calling this RPC should always call the function on the server:
// APuzzleBlankBlock.h
// int to test networking
UPROPERTY(replicated)
int32 networkId;
UFUNCTION(Server, Reliable, WithValidation)
void Server_BlockClickedBroadcast();
void Server_BlockClickedBroadcast_Implementation();
bool Server_BlockClickedBroadcast_Validate();
...
// APuzzleBlankBlock.cpp
// called when block is clicked, server just increments the replicated variable, client calls the server RPC to do the same on the server
void APuzzleBlankBlock::BlockClicked(UPrimitiveComponent* ClickedComp)
{
if (Role == ROLE_Authority)
{
IncreaseNetworkId();
}
else
{
// this call simply doesn't work, the function isn't being called.
Server_BlockClickedBroadcast();
// however Server_BlockClickedBroadcast_Implementation() only increments on the local client, not on the server
}
}
...
void APuzzleBlankBlock::IncreaseNetworkId(){
networkId++;
}
...
//networkId is replicated on clients
void APuzzleBlankBlock::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const
{
DOREPLIFETIME(APuzzleBlankBlock, networkId);
}
// this calls the function to increment networkId, which in turn should be replicated to all clients.
void APuzzleBlankBlock::Server_BlockClickedBroadcast_Implementation()
{
IncreaseNetworkId();
}
So with this code, clicking on the server perfectly replicates the value of networkId to all clients, however, I wouldn’t need an RPC for this. The same effect
works if the server simply increments the variable, since it is replicated through its UPROPERTY(). But I should be able to call the Server_BlockClickedBroadcast() function
from my clients and it should then do same. Any help or insight on this would be greatly appreciated!
To simplifly: I just want a way for my client to tell the server that it was clicked, and as a consequence have the server broadcast this information to the other two uninvolved clients.
################ EDIT:
So appearently server RPCs can only be called from Pawns that are owned by a local client PlayerController. So I simply change my PuzzleBlocks to be Pawns instead of Actors, but how can I assign them a playercontroller? SpawnDefaultController() causes a crash, and simply using GetWorld()->SpawnActor and then possess doesn’t work.
############# SOLUTION:
My solution now was to give my pawns a reference to the local Player controller like this:
// get local player controller
for (TObjectIterator<APuzzleBlankPlayerController> Itr; Itr; ++Itr)
{
APuzzleBlankPlayerController* pc = Cast<APuzzleBlankPlayerController>(*Itr);
if (pc && pc->IsLocalPlayerController()){
//UE_LOG(LogTemp, Warning, TEXT("Local Controller found!"));
PlayerController = pc;
}
}
and have my block on Click call a function in that PlayerController. That function is a RPC which then works exactly as I tried before, but now it is in the PlayerController. That function then passes the cards pointer on to my original Function on the server and almost everything works the same. All my Actor’s don’t have any replicated fields yet, so most functionality doesn’t work exactly, but for some reason with Client 2 (of 3) the pointer works as it does on the server, but not on the other two clients… The object’s field still aren’t replicated but the Server uses his own object when he is passed the pointer to replicated one ( like I said, only on Client 2, never on #1 or #3)… Anyhow, the RPC problem is solved then. Thanks again to all!