Sure, need some refractoring but here what i have now
// Helpers.h
USTRUCT(BlueprintType)
struct FMyPlayerMember
{
GENERATED_BODY()
UPROPERTY(BlueprintReadOnly)
int32 TeamNumber = -1;
UPROPERTY(BlueprintReadOnly)
EMyPlayerRole PlayerRole = EMyPlayerRole::Unset;
UPROPERTY(BlueprintReadOnly)
TSoftClassPtr<AMyPlayerCharacter> CharacterClass;
UPROPERTY(BlueprintReadOnly)
bool bIsReady = false;
};
// MyPlayerState.h
UCLASS()
class AMyPlayerState : public APlayerState, public IAbilitySystemInterface
{
GENERATED_BODY()
public:
AMyPlayerState();
virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "GAS")
TObjectPtr<UMyAbilitySystemComponent> AbilitySystemComponent;
// ---- Team / Lobby State ----
UPROPERTY(ReplicatedUsing = OnRep_PlayerMember, BlueprintReadOnly)
FMyPlayerMember PlayerMember;
UFUNCTION()
void OnRep_PlayerMember(const FMyPlayerMember& OldMember);
// ---- Server setters ----
void SetPlayerMember(const FMyPlayerMember& NewMember);
void SetTeam(int32 Team);
void SetRole(EMyPlayerRole PlayerRole);
void SetReady(bool bReady);
void SetCharacterClass(TSoftClassPtr<AMyPlayerCharacter> NewClass);
// ---- Blueprint Events ----
UFUNCTION(BlueprintImplementableEvent)
void BP_OnTeamChanged(int OldTeam, int NewTeam, EMyPlayerRole PlayerRole);
UFUNCTION(BlueprintImplementableEvent)
void BP_OnRoleChanged(int Team, EMyPlayerRole PlayerRole);
UFUNCTION(BlueprintImplementableEvent)
void BP_OnCharacterChanged(
int Team,
EMyPlayerRole PlayerRole,
TSubclassOf<AMyPlayerCharacter> Character
);
UFUNCTION(BlueprintImplementableEvent)
void BP_OnReadyChanged(bool bReady);
private:
TSubclassOf<AMyPlayerCharacter> CachedLoadedCharacter;
};
AMyPlayerState.cpp
void AMyPlayerState::OnRep_PlayerMember(
const FMyPlayerMember& Old
)
{
FMyPlayerMember pm = PlayerMember;
/* ---------- Team ---------- */
if (Old.TeamNumber != PlayerMember.TeamNumber)
{
BP_OnTeamChanged(
Old.TeamNumber,
PlayerMember.TeamNumber,
PlayerMember.PlayerRole
);
}
/* ---------- Role ---------- */
if (Old.PlayerRole != PlayerMember.PlayerRole)
{
BP_OnRoleChanged(
PlayerMember.TeamNumber,
PlayerMember.PlayerRole
);
}
/* ---------- Character ---------- */
if (Old.CharacterClass != PlayerMember.CharacterClass)
{
CachedLoadedCharacter = nullptr;
if (PlayerMember.CharacterClass.IsNull())
{
BP_OnCharacterChanged(
PlayerMember.TeamNumber,
PlayerMember.PlayerRole,
nullptr
);
}
else
{
FStreamableManager& Streamable =
UAssetManager::GetStreamableManager();
const FSoftObjectPath ExpectedPath =
PlayerMember.CharacterClass.ToSoftObjectPath();
Streamable.RequestAsyncLoad(
ExpectedPath,
FStreamableDelegate::CreateWeakLambda(this, [this, ExpectedPath]()
{
if (
!IsValid(this) ||
PlayerMember.CharacterClass.ToSoftObjectPath() != ExpectedPath
)
{
return;
}
CachedLoadedCharacter =
PlayerMember.CharacterClass.Get();
ensureMsgf(
CachedLoadedCharacter,
TEXT("Failed to load character class: %s"),
*ExpectedPath.ToString()
);
BP_OnCharacterChanged(
PlayerMember.TeamNumber,
PlayerMember.PlayerRole,
CachedLoadedCharacter
);
})
);
}
}
/* ---------- Ready ---------- */
if (Old.bIsReady != PlayerMember.bIsReady)
{
BP_OnReadyChanged(PlayerMember.bIsReady);
}
}
like i said i automatically set the TeamNumber for the host to 0 instead of the default -1
and the playerrole to value other than the default wich is “unset”
then in BP
in the playerstate repnotify event
for example with 3 players , 1 host and 2 clients Team is Always 0 wich is the value of the host
same for the playerrole value