How can I ensure that GameState is available for clients?

I am trying to make a UI widget that allows the clients in a multiplayer game to see changes in AGameState (for learning purposes.) Below is a minimal example of my widget UMatchState, which inherits from UUserWidget. The widget is constructed in APlayerController::OnPossess, but it seems that the GameState is a nullptr at this point and so the delegate is never bound to. Where should I create the widget to ensure that the GameState exists on the client?

void UMatchState::NativeConstruct()
{
	Super::NativeConstruct();

	// Bind delegates
	UWorld* World = GetWorld();
	if (World)
	{
		AGameStateBase* GameState = World->GetGameState();
		AGameState_Core* GameStateCore = Cast<AGameState_Core>(GameState);
		if (GameStateCore)
		{
			GameStateCore->OnMatchStateChangeDelegate.BindUObject(this, &UMatchState::HandleMatchStateChange);
		}
	}
	if (MatchStateText)
	{
		MatchStateText->SetText(FText::FromString(TEXT("UNITIALIZED")));
	}
}

void UMatchState::HandleMatchStateChange()
{
	if (MatchStateText)
	{
		MatchStateText->SetText(FText::FromString(TEXT("MatchStateChange called")));
	}
}

I actually have figured this out and it can be handled elegantly with the delegate UWorld::GameStateSetEvent which is called when the game state is set in the world:

In summary, the client is guaranteed to have access to the game state once GameStateSetEvent is executed.

void UMatchState::NativeConstruct()
{
	Super::NativeConstruct();

	UWorld* World = GetWorld();
	World->GameStateSetEvent.AddUObject(this, &UMatchState::HandleGameStateSet);

	if (MatchStateText)
	{
		MatchStateText->SetText(FText::FromString(TEXT("UNITIALIZED")));
	}
}

void UMatchState::HandleMatchStateChange()
{
	if (MatchStateText)
	{
		MatchStateText->SetText(FText::FromString(TEXT("MatchStateChange called")));
	}
}

void UMatchState::HandleGameStateSet(AGameStateBase* GameStateBase)
{
	// Bind delegates
	AGameState_Core* GameStateCore = Cast<AGameState_Core>(GameStateBase);
	if (GameStateCore)
	{
		GameStateCore->OnMatchStateChangeDelegate.BindUObject(this, &UMatchState::HandleMatchStateChange);
	}
}

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.