FString AGameModeBase::InitNewPlayer(APlayerController* NewPlayerController, const FUniqueNetIdRepl& UniqueId, const FString& Options, const FString& Portal)
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS
	// Try calling deprecated version first
	FString DeprecatedError = InitNewPlayer(NewPlayerController, UniqueId.GetUniqueNetId(), Options, Portal);
	if (DeprecatedError != TEXT("DEPRECATED"))
	{
		// This means it was implemented in subclass
		return DeprecatedError;
	}
PRAGMA_ENABLE_DEPRECATION_WARNINGS

	check(NewPlayerController);

	FString ErrorMessage;

	// Register the player with the session
	GameSession->RegisterPlayer(NewPlayerController, UniqueId.GetUniqueNetId(), UGameplayStatics::HasOption(Options, TEXT("bIsFromInvite")));

	// Find a starting spot
	AActor* const StartSpot = FindPlayerStart(NewPlayerController, Portal);
	if (StartSpot != nullptr)
	{
		// Set the player controller / camera in this new location
		FRotator InitialControllerRot = StartSpot->GetActorRotation();
		InitialControllerRot.Roll = 0.f;
		NewPlayerController->SetInitialLocationAndRotation(StartSpot->GetActorLocation(), InitialControllerRot);
		NewPlayerController->StartSpot = StartSpot;
	}
	else
	{
		ErrorMessage = FString::Printf(TEXT("Failed to find PlayerStart"));
	}

	// Set up spectating
	bool bSpectator = FCString::Stricmp(*UGameplayStatics::ParseOption(Options, TEXT("SpectatorOnly")), TEXT("1")) == 0;
	if (bSpectator || MustSpectate(NewPlayerController))
	{
		NewPlayerController->StartSpectatingOnly();
	}

	// Init player's name
	FString InName = UGameplayStatics::ParseOption(Options, TEXT("Name")).Left(20);
	if (InName.IsEmpty())
	{
		InName = FString::Printf(TEXT("%s%i"), *DefaultPlayerName.ToString(), NewPlayerController->PlayerState->PlayerId);
	}

	ChangeName(NewPlayerController, InName, false);

	return ErrorMessage;
}
void FPlayerMuteList::ServerMutePlayer(APlayerController* OwningPC, const FUniqueNetIdRepl& MuteId)
{
	UWorld* World = OwningPC->GetWorld();

	const TSharedPtr<const FUniqueNetId>& PlayerIdToMute = MuteId.GetUniqueNetId();

	// Don't reprocess if they are already muted
	AddIdToMuteList(VoiceMuteList, PlayerIdToMute);

	// Add them to the packet filter list if not already on it
	AddIdToMuteList(VoicePacketFilter, PlayerIdToMute);

	// Replicate mute state to client
	OwningPC->ClientMutePlayer(MuteId);

	// Find the muted player's player controller so it can be notified
	APlayerController* OtherPC = GetPlayerControllerFromNetId(World, *PlayerIdToMute);
	if (OtherPC != NULL)
	{
		// Update their packet filter list too
		OtherPC->MuteList.ClientMutePlayer(OtherPC, OwningPC->PlayerState->UniqueId);

		// Tell the other PC to mute this one
		OtherPC->ClientMutePlayer(OwningPC->PlayerState->UniqueId);
	}
}
void FPlayerMuteList::GameplayUnmutePlayer(APlayerController* OwningPC, const FUniqueNetIdRepl& UnmuteId)
{
	UWorld* World = OwningPC->GetWorld();

	const TSharedPtr<const FUniqueNetId>& PlayerIdToUnmute = UnmuteId.GetUniqueNetId();

	// Remove from the gameplay mute list
	RemoveIdFromMuteList(GameplayVoiceMuteList, PlayerIdToUnmute);

	// Find the muted player's player controller so it can be notified
	APlayerController* OtherPC = GetPlayerControllerFromNetId(World, *PlayerIdToUnmute);
	if (OtherPC != NULL)
	{
		FUniqueNetIdMatcher PlayerIdToUnmuteMatch(*PlayerIdToUnmute);
		FUniqueNetIdMatcher OwningPlayerIdMatch(*OwningPC->PlayerState->UniqueId);

		// Make sure this player isn't explicitly muted
		if (VoiceMuteList.IndexOfByPredicate(PlayerIdToUnmuteMatch) == INDEX_NONE &&
			// And make sure they didn't mute us
			OtherPC->MuteList.VoiceMuteList.IndexOfByPredicate(OwningPlayerIdMatch) == INDEX_NONE)
		{
			RemoveIdFromMuteList(VoicePacketFilter, PlayerIdToUnmute);

			// Now process on the client
			OwningPC->ClientUnmutePlayer(UnmuteId);	
		}
	}
}
void FPlayerMuteList::GameplayMutePlayer(APlayerController* OwningPC, const FUniqueNetIdRepl& MuteId)
{
	const TSharedPtr<const FUniqueNetId>& PlayerIdToMute = MuteId.GetUniqueNetId();

	// Don't add if already muted
	AddIdToMuteList(GameplayVoiceMuteList, PlayerIdToMute);

	// Add to the filter list, if missing
	AddIdToMuteList(VoicePacketFilter, PlayerIdToMute);

	// Now process on the client
	OwningPC->ClientMutePlayer(MuteId);
}
void AGameModeBase::PreLogin(const FString& Options, const FString& Address, const FUniqueNetIdRepl& UniqueId, FString& ErrorMessage)
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS
	// Try calling deprecated version first
	PreLogin(Options, Address, UniqueId.GetUniqueNetId(), ErrorMessage);
	if (!ErrorMessage.IsEmpty())
	{
		return;
	}
PRAGMA_ENABLE_DEPRECATION_WARNINGS

	ErrorMessage = GameSession->ApproveLogin(Options);
}
void FPlayerMuteList::ClientMutePlayer(APlayerController* OwningPC, const FUniqueNetIdRepl& MuteId)
{
	const TSharedPtr<const FUniqueNetId>& PlayerIdToMute = MuteId.GetUniqueNetId();

	// Add to the filter list on clients (used for peer to peer voice)
	AddIdToMuteList(VoicePacketFilter, PlayerIdToMute);

	// Use the local player to determine the controller id
	ULocalPlayer* LP = Cast<ULocalPlayer>(OwningPC->Player);
	if (LP != NULL)
	{
		UWorld* World = OwningPC->GetWorld();
		IOnlineVoicePtr VoiceInt = Online::GetVoiceInterface(World);
		if (VoiceInt.IsValid())
		{
			// Have the voice subsystem mute this player
			VoiceInt->MuteRemoteTalker(LP->GetControllerId(), *PlayerIdToMute, false);
		}
	}
}
void FPlayerMuteList::ServerUnmutePlayer(APlayerController* OwningPC, const FUniqueNetIdRepl& UnmuteId)
{
	UWorld* World = OwningPC->GetWorld();

	const TSharedPtr<const FUniqueNetId>& PlayerIdToUnmute = UnmuteId.GetUniqueNetId();

	// If the player was found, remove them from our explicit list
	RemoveIdFromMuteList(VoiceMuteList, PlayerIdToUnmute);

	// Find the muted player's player controller so it can be notified
	APlayerController* OtherPC = GetPlayerControllerFromNetId(World, *PlayerIdToUnmute);
	if (OtherPC != NULL)
	{
		FUniqueNetIdMatcher PlayerIdToUnmuteMatch(*PlayerIdToUnmute);
		FUniqueNetIdMatcher OwningPlayerIdMatch(*OwningPC->PlayerState->UniqueId);

		// Make sure this player isn't muted for gameplay reasons
		if (GameplayVoiceMuteList.IndexOfByPredicate(PlayerIdToUnmuteMatch) == INDEX_NONE &&
			// And make sure they didn't mute us
			OtherPC->MuteList.VoiceMuteList.IndexOfByPredicate(OwningPlayerIdMatch) == INDEX_NONE)
		{
			OwningPC->ClientUnmutePlayer(UnmuteId);
		}

		// If the other player doesn't have this player muted
		if (OtherPC->MuteList.VoiceMuteList.IndexOfByPredicate(OwningPlayerIdMatch) == INDEX_NONE &&
			OtherPC->MuteList.GameplayVoiceMuteList.IndexOfByPredicate(OwningPlayerIdMatch) == INDEX_NONE)
		{
			// Remove them from the packet filter list
			RemoveIdFromMuteList(VoicePacketFilter, PlayerIdToUnmute);

			// If found, remove so packets flow to that client too
			RemoveIdFromMuteList(OtherPC->MuteList.VoicePacketFilter, OwningPC->PlayerState->UniqueId.GetUniqueNetId());

			// Tell the other PC to unmute this one
			OtherPC->ClientUnmutePlayer(OwningPC->PlayerState->UniqueId);
		}
	}
}
void TestUniqueIdRepl(UWorld* InWorld)
{
#if !UE_BUILD_SHIPPING
	bool bSuccess = true;

	TSharedPtr<const FUniqueNetId> UserId = UOnlineEngineInterface::Get()->GetUniquePlayerId(InWorld, 0);

	FUniqueNetIdRepl EmptyIdIn;
	if (EmptyIdIn.IsValid())
	{
		UE_LOG(LogNet, Warning, TEXT("EmptyId is valid."), *EmptyIdIn->ToString());
		bSuccess = false;
	}

	FUniqueNetIdRepl ValidIdIn(UserId);
	if (!ValidIdIn.IsValid() || UserId != ValidIdIn.GetUniqueNetId() || *UserId != *ValidIdIn)
	{
		UE_LOG(LogNet, Warning, TEXT("UserId input %s != UserId output %s"), *UserId->ToString(), *ValidIdIn->ToString());
		bSuccess = false;
	}

	if (bSuccess)
	{
		TArray<uint8> Buffer;
		for (int32 i = 0; i < 2; i++)
		{
			Buffer.Empty();
			FMemoryWriter TestWriteUniqueId(Buffer);

			if (i == 0)
			{
				// Normal serialize
				TestWriteUniqueId << EmptyIdIn;
				TestWriteUniqueId << ValidIdIn;
			}
			else
			{
				// Net serialize
				bool bOutSuccess = false;
				EmptyIdIn.NetSerialize(TestWriteUniqueId, NULL, bOutSuccess);
				ValidIdIn.NetSerialize(TestWriteUniqueId, NULL, bOutSuccess);
			}

			FMemoryReader TestReadUniqueId(Buffer);

			FUniqueNetIdRepl EmptyIdOut;
			TestReadUniqueId << EmptyIdOut;
			if (EmptyIdOut.GetUniqueNetId().IsValid())
			{
				UE_LOG(LogNet, Warning, TEXT("EmptyId %s should have been invalid"), *EmptyIdOut->ToString());
				bSuccess = false;
			}

			FUniqueNetIdRepl ValidIdOut;
			TestReadUniqueId << ValidIdOut;
			if (*UserId != *ValidIdOut.GetUniqueNetId())
			{
				UE_LOG(LogNet, Warning, TEXT("UserId input %s != UserId output %s"), *ValidIdIn->ToString(), *ValidIdOut->ToString());
				bSuccess = false;
			}
		}
	}

	if (bSuccess)
	{
		FString OutString;
		TSharedRef<FJsonValue> JsonValue = ValidIdIn.ToJson();
		bSuccess = JsonValue->TryGetString(OutString);
		if (bSuccess)
		{
			FUniqueNetIdRepl NewIdOut;
			NewIdOut.FromJson(OutString);
			bSuccess = NewIdOut.IsValid();
		}
	}


	if (!bSuccess)
	{
		UE_LOG(LogNet, Warning, TEXT("TestUniqueIdRepl test failure!"));
	}
#endif
}
void TestUniqueIdRepl(UWorld* InWorld)
{
	bool bSuccess = true;

	IOnlineIdentityPtr IdentityPtr = Online::GetIdentityInterface(InWorld);
	if (IdentityPtr.IsValid())
	{
		TSharedPtr<FUniqueNetId> UserId = IdentityPtr->GetUniquePlayerId(0);

		FUniqueNetIdRepl EmptyIdIn;
		if (EmptyIdIn.IsValid())
		{
			UE_LOG(LogNet, Warning, TEXT("EmptyId is valid."), *EmptyIdIn->ToString());
			bSuccess = false;
		}

		FUniqueNetIdRepl ValidIdIn(UserId);
		if (!ValidIdIn.IsValid() || UserId != ValidIdIn.GetUniqueNetId())
		{
			UE_LOG(LogNet, Warning, TEXT("UserId input %s != UserId output %s"), *UserId->ToString(), *ValidIdIn->ToString());
			bSuccess = false;
		}

		if (bSuccess)
		{
			TArray<uint8> Buffer;
			for (int32 i=0; i<2; i++)
			{
				Buffer.Empty();
				FMemoryWriter TestWriteUniqueId(Buffer);

				if (i == 0)
				{
					// Normal serialize
					TestWriteUniqueId << EmptyIdIn;
					TestWriteUniqueId << ValidIdIn;
				}
				else
				{
					// Net serialize
					bool bSuccess = false;
					EmptyIdIn.NetSerialize(TestWriteUniqueId, NULL, bSuccess);
					ValidIdIn.NetSerialize(TestWriteUniqueId, NULL, bSuccess);
				}

				FMemoryReader TestReadUniqueId(Buffer);

				FUniqueNetIdRepl EmptyIdOut;
				TestReadUniqueId << EmptyIdOut;
				if (EmptyIdOut.GetUniqueNetId().IsValid())
				{
					UE_LOG(LogNet, Warning, TEXT("EmptyId %s should have been invalid"), *EmptyIdOut->ToString());
					bSuccess = false;
				}

				FUniqueNetIdRepl ValidIdOut;
				TestReadUniqueId << ValidIdOut;
				if (*UserId != *ValidIdOut.GetUniqueNetId())
				{
					UE_LOG(LogNet, Warning, TEXT("UserId input %s != UserId output %s"), *ValidIdIn->ToString(), *ValidIdOut->ToString());
					bSuccess = false;
				}
			}
		}
	}

	if (!bSuccess)
	{
		UE_LOG(LogNet, Warning, TEXT("TestUniqueIdRepl test failure!"));
	}
}