How to implement COD:WWII style join-in-progress lobby?

I’ve been working on this a couple days now and I think I really need a pointer (pun intended) in the right direction.

What I mean by COD:WWII style lobby is how they have players join into a map where they can see other connected players complete with their chosen cosmetics. I’m having difficulty finding a way to make it so that clients joining the lobby can see the cosmetics on the listen server and other clients who have already joined.

Right now, I have it so that a player can customize the character from the main menu and the chosen meshes are stored in a local Save Game file as string references. Then when they load into the lobby, I call a LoadGame() function to load the cosmetics:

void AMGLobbyPawn::LoadGame()
{
	UMGSaveGame* SaveGameInst = Cast<UMGSaveGame>(UGameplayStatics::CreateSaveGameObject(UMGSaveGame::StaticClass()));
	SaveGameInst = Cast<UMGSaveGame>(UGameplayStatics::LoadGameFromSlot(SaveGameInst->SlotName, 0));

	if (SaveGameInst)
	{
		if (HasAuthority())
		{
			Multicast_LoadGame(SaveGameInst->HairRef, SaveGameInst->HairAccessoryRef, SaveGameInst->TopRef, SaveGameInst->BottomRef, SaveGameInst->LegRef, SaveGameInst->ShoesRef);
		}

		if (!HasAuthority())
		{
			SRV_LoadGame(SaveGameInst->HairRef, SaveGameInst->HairAccessoryRef, SaveGameInst->TopRef, SaveGameInst->BottomRef, SaveGameInst->LegRef, SaveGameInst->ShoesRef);
		}
	}
}

The server function calls the multicast function, which sets the associated skeletal meshes using LoadObject() and the string reference passed in. Basically like this:

Hair->SetSkeletalMesh(LoadObject<USkeletalMesh>(NULL, *HRef, NULL, LOAD_None, NULL));

This works fine to display the connecting player’s cosmetics to players who are already joined in the lobby, but obviously the connecting player can’t see any of the cosmetics on players already connected because they would have to run the function again. I guess I’m a bit lost on how best to do that, though.

Has anyone been able to do something like this before? If so, how did you go about it? If not, any ideas I can try would still be appreciated.

If you want clients to be aware of state from the server that happened via RPCs at some point in the past before they joined in progress. Then you need to inform those clients in some way. Either by sending RPCs to those clients at some defined point after they join, or by storing that state in replicated variables.

Personally the way I’d do this is to store each player’s customisation state in their PlayerState as replicated variables. Preferably in some kind of format that’s really cheap to replicate (like, for example a set of string hashes that other machines can then use to lookup and reconstruct the set of assets on their side).

I’d stick a RepNotify on the replicated variables so that whenever we receive a new set of customisation data from the server, we can load assets and rebuild customisation for the relevant character locally.

The reason I’d store it in the PlayerState specifically, is that since you’re likely to want to load and possibly build a more optimised representation of that descriptor, you probably don’t want to have to redo that work every time your character respawns.