void AOnlineBeaconHost::NotifyControlMessage(UNetConnection* Connection, uint8 MessageType, class FInBunch& Bunch)
{
    if(NetDriver->ServerConnection == NULL)
    {
        bool bCloseConnection = false;

        // We are the server.
#if !(UE_BUILD_SHIPPING && WITH_EDITOR)
        UE_LOG(LogNet, Verbose, TEXT("Beacon: Host received: %s"), FNetControlMessageInfo::GetName(MessageType));
#endif
        switch (MessageType)
        {
        case NMT_Hello:
        {
            UE_LOG(LogNet, Log, TEXT("Beacon Hello"));
            uint8 IsLittleEndian;
            int32 RemoteMinVer, RemoteVer;
            FGuid RemoteGameGUID;
            FNetControlMessage<NMT_Hello>::Receive(Bunch, IsLittleEndian, RemoteMinVer, RemoteVer, RemoteGameGUID);

            if (!IsNetworkCompatible(Connection->Driver->RequireEngineVersionMatch, RemoteVer, RemoteMinVer))
            {
                FNetControlMessage<NMT_Upgrade>::Send(Connection, GEngineMinNetVersion, GEngineNetVersion);
                bCloseConnection = true;
            }
            else
            {
                Connection->NegotiatedVer = FMath::Min(RemoteVer, GEngineNetVersion);

                // Make sure the server has the same GameGUID as we do
                if( RemoteGameGUID != GetDefault<UGeneralProjectSettings>()->ProjectID )
                {
                    FString ErrorMsg = NSLOCTEXT("NetworkErrors", "ServerHostingDifferentGame", "Incompatible game connection.").ToString();
                    FNetControlMessage<NMT_Failure>::Send(Connection, ErrorMsg);
                    bCloseConnection = true;
                    break;
                }

                Connection->Challenge = FString::Printf(TEXT("%08X"), FPlatformTime::Cycles());
                FNetControlMessage<NMT_BeaconWelcome>::Send(Connection);
                Connection->FlushNet();
            }
            break;
        }
        case NMT_Netspeed:
        {
            int32 Rate;
            FNetControlMessage<NMT_Netspeed>::Receive(Bunch, Rate);
            Connection->CurrentNetSpeed = FMath::Clamp(Rate, 1800, NetDriver->MaxClientRate);
            UE_LOG(LogNet, Log, TEXT("Beacon: Client netspeed is %i"), Connection->CurrentNetSpeed);
            break;
        }
        case NMT_BeaconJoin:
        {
            FString ErrorMsg;
            FString BeaconType;
            FNetControlMessage<NMT_BeaconJoin>::Receive(Bunch, BeaconType);
            UE_LOG(LogNet, Log, TEXT("Beacon Join %s"), *BeaconType);

            if (Connection->ClientWorldPackageName == NAME_None)
            {
                AOnlineBeaconClient* ClientActor = GetClientActor(Connection);
                if (ClientActor == NULL)
                {
                    UWorld* World = GetWorld();
                    Connection->ClientWorldPackageName = World->GetOutermost()->GetFName();

                    AOnlineBeaconClient* NewClientActor = SpawnBeaconActor();
                    if (NewClientActor && BeaconType == NewClientActor->GetBeaconType())
                    {
                        FNetworkGUID NetGUID = Connection->PackageMap->AssignNewNetGUID(NewClientActor);
                        NewClientActor->SetNetConnection(Connection);
                        Connection->OwningActor = NewClientActor;
                        NewClientActor->Role = ROLE_None;
                        NewClientActor->SetReplicates(false);
                        ClientActors.Add(NewClientActor);
                        FNetControlMessage<NMT_BeaconAssignGUID>::Send(Connection, NetGUID);
                    }
                    else
                    {
                        ErrorMsg = NSLOCTEXT("NetworkErrors", "BeaconSpawnFailureError", "Join failure, Couldn't spawn beacon.").ToString();
                    }
                }
                else
                {
                    ErrorMsg = NSLOCTEXT("NetworkErrors", "BeaconSpawnExistingActorError", "Join failure, existing beacon actor.").ToString();;
                }
            }
            else
            {
                ErrorMsg = NSLOCTEXT("NetworkErrors", "BeaconSpawnClientWorldPackageNameError", "Join failure, existing ClientWorldPackageName.").ToString();;
            }

            if (!ErrorMsg.IsEmpty())
            {
                UE_LOG(LogNet, Log, TEXT("%s"), *ErrorMsg);
                FNetControlMessage<NMT_Failure>::Send(Connection, ErrorMsg);
                bCloseConnection = true;
            }

            break;
        }
        case NMT_BeaconNetGUIDAck:
        {
            FString BeaconType;
            FNetControlMessage<NMT_BeaconNetGUIDAck>::Receive(Bunch, BeaconType);

            AOnlineBeaconClient* ClientActor = GetClientActor(Connection);
            if (ClientActor && BeaconType == ClientActor->GetBeaconType())
            {
                ClientActor->Role = ROLE_Authority;
                ClientActor->SetReplicates(true);
                ClientActor->SetAutonomousProxy(true);
                // Send an RPC to the client to open the actor channel and guarantee RPCs will work
                ClientActor->ClientOnConnected();
                UE_LOG(LogNet, Log, TEXT("Beacon Handshake complete!"));
                FOnBeaconConnected* OnBeaconConnectedDelegate = OnBeaconConnectedMapping.Find(FName(*BeaconType));
                if (OnBeaconConnectedDelegate)
                {
                    OnBeaconConnectedDelegate->ExecuteIfBound(ClientActor, Connection);
                }
            }
            else
            {
                // Failed to connect.
                FString ErrorMsg = NSLOCTEXT("NetworkErrors", "BeaconSpawnNetGUIDAckError", "Join failure, no actor at NetGUIDAck.").ToString();
                UE_LOG(LogNet, Log, TEXT("%s"), *ErrorMsg);
                FNetControlMessage<NMT_Failure>::Send(Connection, ErrorMsg);
                bCloseConnection = true;
            }
            break;
        }
        case NMT_BeaconWelcome:
        case NMT_BeaconAssignGUID:
        default:
        {
            FString ErrorMsg = NSLOCTEXT("NetworkErrors", "BeaconSpawnUnexpectedError", "Join failure, unexpected control message.").ToString();
            UE_LOG(LogNet, Log, TEXT("%s"), *ErrorMsg);
            FNetControlMessage<NMT_Failure>::Send(Connection, ErrorMsg);
            bCloseConnection = true;
        }
        break;
        }

        if (bCloseConnection)
        {
            AOnlineBeaconClient* ClientActor = GetClientActor(Connection);
            if (ClientActor)
            {
                RemoveClientActor(ClientActor);
            }

            Connection->FlushNet(true);
            Connection->Close();
        }
    }
}
void AOnlineBeaconHost::NotifyControlMessage(UNetConnection* Connection, uint8 MessageType, class FInBunch& Bunch)
{
	if(NetDriver->ServerConnection == nullptr)
	{
		bool bCloseConnection = false;

		// We are the server.
#if !(UE_BUILD_SHIPPING && WITH_EDITOR)
		UE_LOG(LogBeacon, Verbose, TEXT("%s[%s] Host received: %s"), *GetName(), Connection ? *Connection->GetName() : TEXT("Invalid"), FNetControlMessageInfo::GetName(MessageType));
#endif
		switch (MessageType)
		{
		case NMT_Hello:
			{
				UE_LOG(LogBeacon, Log, TEXT("Beacon Hello"));
				uint8 IsLittleEndian;

				uint32 RemoteNetworkVersion = 0;
				uint32 LocalNetworkVersion = FNetworkVersion::GetLocalNetworkVersion();

				FNetControlMessage<NMT_Hello>::Receive(Bunch, IsLittleEndian, RemoteNetworkVersion);

				if (!FNetworkVersion::IsNetworkCompatible(LocalNetworkVersion, RemoteNetworkVersion))
				{
					UE_LOG(LogBeacon, Log, TEXT("Client not network compatible %s"), *Connection->GetName());
					FNetControlMessage<NMT_Upgrade>::Send(Connection, LocalNetworkVersion);
					bCloseConnection = true;
				}
				else
				{
					Connection->Challenge = FString::Printf(TEXT("%08X"), FPlatformTime::Cycles());
					FNetControlMessage<NMT_BeaconWelcome>::Send(Connection);
					Connection->FlushNet();
				}
				break;
			}
		case NMT_Netspeed:
			{
				int32 Rate;
				FNetControlMessage<NMT_Netspeed>::Receive(Bunch, Rate);
				Connection->CurrentNetSpeed = FMath::Clamp(Rate, 1800, NetDriver->MaxClientRate);
				UE_LOG(LogBeacon, Log, TEXT("Client netspeed is %i"), Connection->CurrentNetSpeed);
				break;
			}
		case NMT_BeaconJoin:
			{
				FString ErrorMsg;
				FString BeaconType;
				FUniqueNetIdRepl UniqueId;
				FNetControlMessage<NMT_BeaconJoin>::Receive(Bunch, BeaconType, UniqueId);
				UE_LOG(LogBeacon, Log, TEXT("Beacon Join %s %s"), *BeaconType, *UniqueId.ToDebugString());

				if (Connection->ClientWorldPackageName == NAME_None)
				{
					AOnlineBeaconClient* ClientActor = GetClientActor(Connection);
					if (ClientActor == nullptr)
					{
						UWorld* World = GetWorld();
						Connection->ClientWorldPackageName = World->GetOutermost()->GetFName();

						AOnlineBeaconClient* NewClientActor = nullptr;
						FOnBeaconSpawned* OnBeaconSpawnedDelegate = OnBeaconSpawnedMapping.Find(BeaconType);
						if (OnBeaconSpawnedDelegate && OnBeaconSpawnedDelegate->IsBound())
						{
							NewClientActor = OnBeaconSpawnedDelegate->Execute(Connection);
						}

						if (NewClientActor && BeaconType == NewClientActor->GetBeaconType())
						{
							NewClientActor->SetConnectionState(EBeaconConnectionState::Pending);

							FNetworkGUID NetGUID = Connection->Driver->GuidCache->AssignNewNetGUID_Server(NewClientActor);
							NewClientActor->SetNetConnection(Connection);
							Connection->PlayerId = UniqueId;
							Connection->OwningActor = NewClientActor;
							NewClientActor->Role = ROLE_Authority;
							NewClientActor->SetReplicates(false);
							check(NetDriverName == NetDriver->NetDriverName);
							NewClientActor->SetNetDriverName(NetDriverName);
							ClientActors.Add(NewClientActor);
							FNetControlMessage<NMT_BeaconAssignGUID>::Send(Connection, NetGUID);
						}
						else
						{
							ErrorMsg = NSLOCTEXT("NetworkErrors", "BeaconSpawnFailureError", "Join failure, Couldn't spawn beacon.").ToString();
						}
					}
					else
					{
						ErrorMsg = NSLOCTEXT("NetworkErrors", "BeaconSpawnExistingActorError", "Join failure, existing beacon actor.").ToString();
					}
				}
				else
				{
					ErrorMsg = NSLOCTEXT("NetworkErrors", "BeaconSpawnClientWorldPackageNameError", "Join failure, existing ClientWorldPackageName.").ToString();
				}

				if (!ErrorMsg.IsEmpty())
				{
					UE_LOG(LogBeacon, Log, TEXT("%s: %s"), *Connection->GetName(), *ErrorMsg);
					FNetControlMessage<NMT_Failure>::Send(Connection, ErrorMsg);
					bCloseConnection = true;
				}

				break;
			}
		case NMT_BeaconNetGUIDAck:
			{
				FString ErrorMsg;
				FString BeaconType;
				FNetControlMessage<NMT_BeaconNetGUIDAck>::Receive(Bunch, BeaconType);

				AOnlineBeaconClient* ClientActor = GetClientActor(Connection);
				if (ClientActor && BeaconType == ClientActor->GetBeaconType())
				{
					FOnBeaconConnected* OnBeaconConnectedDelegate = OnBeaconConnectedMapping.Find(BeaconType);
					if (OnBeaconConnectedDelegate)
					{
						ClientActor->SetReplicates(true);
						ClientActor->SetAutonomousProxy(true);
						ClientActor->SetConnectionState(EBeaconConnectionState::Open);
						// Send an RPC to the client to open the actor channel and guarantee RPCs will work
						ClientActor->ClientOnConnected();
						UE_LOG(LogBeacon, Log, TEXT("Handshake complete for %s!"), *ClientActor->GetName());

						OnBeaconConnectedDelegate->ExecuteIfBound(ClientActor, Connection);
					}
					else
					{
						// Failed to connect.
						ErrorMsg = NSLOCTEXT("NetworkErrors", "BeaconSpawnNetGUIDAckError1", "Join failure, no host object at NetGUIDAck.").ToString();
					}
				}
				else
				{
					// Failed to connect.
					ErrorMsg = NSLOCTEXT("NetworkErrors", "BeaconSpawnNetGUIDAckError2", "Join failure, no actor at NetGUIDAck.").ToString();
				}

				if (!ErrorMsg.IsEmpty())
				{
					UE_LOG(LogBeacon, Log, TEXT("%s: %s"), *Connection->GetName(), *ErrorMsg);
					FNetControlMessage<NMT_Failure>::Send(Connection, ErrorMsg);
					bCloseConnection = true;
				}

				break;
			}
		case NMT_BeaconWelcome:
		case NMT_BeaconAssignGUID:
		default:
			{
				FString ErrorMsg = NSLOCTEXT("NetworkErrors", "BeaconSpawnUnexpectedError", "Join failure, unexpected control message.").ToString();
				UE_LOG(LogBeacon, Log, TEXT("%s: %s"), *Connection->GetName(), *ErrorMsg);
				FNetControlMessage<NMT_Failure>::Send(Connection, ErrorMsg);
				bCloseConnection = true;
			}
			break;
		}

		if (bCloseConnection)
		{		
			UE_LOG(LogBeacon, Verbose, TEXT("Closing connection %s: %s"), *Connection->GetName(), *Connection->PlayerId.ToDebugString());
			AOnlineBeaconClient* ClientActor = GetClientActor(Connection);
			if (ClientActor)
			{
				UE_LOG(LogBeacon, Verbose, TEXT("- BeaconActor: %s %s"), *ClientActor->GetName(), *ClientActor->GetBeaconType());
				AOnlineBeaconHostObject* BeaconHostObject = GetHost(ClientActor->GetBeaconType());
				if (BeaconHostObject)
				{
					UE_LOG(LogBeacon, Verbose, TEXT("- HostObject: %s"), *BeaconHostObject->GetName());
					BeaconHostObject->NotifyClientDisconnected(ClientActor);
				}

				RemoveClientActor(ClientActor);
			}

			Connection->FlushNet(true);
			Connection->Close();
			UE_LOG(LogBeacon, Verbose, TEXT("--------------------------------"));
		}
	}
}