I have a struct in a client’s GameInstance which I’ll call “CharacterDetails”, which contains purely cosmetic information about a user’s character. The game in question works for single player, multiplayer, and LAN. I understand that a PlayerState exists on both client and server, so I want to set CharacterDetails in the PlayerState from the server, so the value is replicated to all clients.
When I prototyped this in Blueprint, it seemed to work. Users connecting to the server would have all the details they input beforehand be replicated. Here are some images of what I was doing within BP:
I went to remake this in C++, but I don’t seem to be getting the same result. I’ve stripped this down to just what I’ve done to try and achieve the above:
GameModeRoot.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/GameModeBase.h"
#include "PlayerStates/PlayerStateBase.h"
#include "GameModeRoot.generated.h"
/**
*
*/
UCLASS()
class FORUMPOST_API AGameModeRoot : public AGameModeBase
{
GENERATED_BODY()
protected:
AGameModeRoot();
virtual void PostLogin(APlayerController * NewPlayer);
};
GameModeRoot.cpp
#include "GameModeRoot.h"
AGameModeRoot::AGameModeRoot()
{
PlayerStateClass = APlayerStateBase::StaticClass();
}
void AGameModeRoot::PostLogin(APlayerController * NewPlayer)
{
NewPlayer->GetPlayerState<APlayerStateBase>()->ClientGetCharacterDetails();
}
PlayerStateBase.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/PlayerState.h"
#include "Variables/Structures.h"
#include "Net/UnrealNetwork.h"
#include "GameInstanceBase.h"
#include "PlayerStateBase.generated.h"
/**
*
*/
UCLASS()
class FORUMPOST_API APlayerStateBase : public APlayerState
{
GENERATED_BODY()
protected:
virtual void GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const;
public:
// Structure containing all the details of a character.
UPROPERTY(Replicated, EditAnywhere, BlueprintReadWrite, Category = "Character Information")
FFullCharacterDetails FullCharacterDetails;
// Gets FullCharacterDetails from client's GameInstance
UFUNCTION(Client, Reliable)
void ClientGetCharacterDetails();
// Sets FullCharacterDetails on Server to replicate to clients.
UFUNCTION(Server, Reliable)
void ServerSetCharacterDetails(FFullCharacterDetails InCharacterDetails);
};
PlayerStateBase.cpp
#include "PlayerStateBase.h"
void APlayerStateBase::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(APlayerStateBase, FullCharacterDetails);
}
void APlayerStateBase::ClientGetCharacterDetails_Implementation()
{
ServerSetCharacterDetails( Cast<UGameInstanceBase>(GetGameInstance())->FullCharacterDetails );
}
void APlayerStateBase::ServerSetCharacterDetails_Implementation(FFullCharacterDetails InCharacterDetails)
{
FullCharacterDetails = InCharacterDetails;
}
A bit gross, but I’m attempting to execute “ClientGetCharacterDetails” on the client, which calls ServerSetCharacterDetails with the intention of the server running it instead. I couldn’t make ClientGetCharacterDetails return the CharacterDetails struct because I’m using the Server specifier. I also can’t run the ClientGetCharacterDetails function on the server, since I need the CharacterDetails struct from the client’s GameInstance.
I am under the impression that perhaps “UFUNCTION(Server, Reliable)” and “UFUNCTION(Client, Reliable)” may not work exactly the same way as I think it does in BP. If someone could tell me what I’m missing, I’d really appreciate it!