예제 #1
0
bool NUTNet::CreateFakePlayer(UWorld* InWorld, UNetDriver*& InNetDriver, FString ServerIP, FNetworkNotify* InNotify/*=NULL*/,
								bool bSkipJoin/*=false*/, FUniqueNetIdRepl* InNetID/*=NULL*/, bool bBeaconConnect/*=false*/,
								FString InBeaconType/*=TEXT("")*/)
{
	bool bSuccess = false;

	if (InNetDriver == NULL)
	{
		InNetDriver = (InWorld != NULL ? NUTNet::CreateUnitTestNetDriver(InWorld) : NULL);
	}

	if (InNetDriver != NULL)
	{
		if (InNotify == NULL)
		{
			FNetworkNotifyHook* NotifyHook = new FNetworkNotifyHook();
			InNotify = NotifyHook;

			auto DefaultRejectChan = [](UChannel* Channel)
				{
					UE_LOG(LogUnitTest, Log, TEXT("UnitTestNetDriver: NotifyAcceptingChannel: %s"), *Channel->Describe());

					return false;
				};

			NotifyHook->NotifyAcceptingChannelDelegate.BindLambda(DefaultRejectChan);
		}

		FURL DefaultURL;
		FURL TravelURL(&DefaultURL, *ServerIP, TRAVEL_Absolute);
		FString ConnectionError;

		if (InNetDriver->InitConnect(InNotify, TravelURL, ConnectionError))
		{
			UNetConnection* TargetConn = InNetDriver->ServerConnection;

			UE_LOG(LogUnitTest, Log, TEXT("Successfully kicked off connect to IP '%s'"), *ServerIP);


			int ControlBunchSequence = 0;

			FOutBunch* ControlChanBunch = NUTNet::CreateChannelBunch(ControlBunchSequence, TargetConn, CHTYPE_Control, 0);

			// Need to send 'NMT_Hello' to start off the connection (the challenge is not replied to)
			uint8 IsLittleEndian = uint8(PLATFORM_LITTLE_ENDIAN);

			// We need to construct the NMT_Hello packet manually, for the initial connection
			uint8 MessageType = NMT_Hello;

			*ControlChanBunch << MessageType;
			*ControlChanBunch << IsLittleEndian;


#if TARGET_UE4_CL >= CL_FNETWORKVERSION
			// Starting with 4.8.0, the network protocol has changed slightly
			// @todo JohnB: Refactor this, to toggle at compile time only, based on CL (might require more accurate UT integrate CLs)
			FString VersionStr = GEngineVersion.ToString(EVersionComponent::Minor);
			int32 VersionDelim = VersionStr.Find(TEXT("."));
			int32 MajorVersion = FCString::Atoi(*VersionStr.Left(VersionDelim));
			int32 MinorVersion = FCString::Atoi(*VersionStr.Mid(VersionDelim+1));


			bool bOldProtocol = (MajorVersion <= 4 && MinorVersion <= 7) &&
				/** Exception for UT (treat 4.7 as having the new protocol) */
				(FString(FApp::GetGameName()) != TEXT("UnrealTournament") || (MajorVersion <= 4 && MinorVersion <= 6));

			if (bOldProtocol)
#endif
			{
				int32 EngineMinNetVersion = GEngineMinNetVersion;
				*ControlChanBunch << EngineMinNetVersion;
				int32 EngineNetVersion = GEngineNetVersion;
				*ControlChanBunch << EngineNetVersion;
				*ControlChanBunch << (FGuid&)GetDefault<UGeneralProjectSettings>()->ProjectID;
			}
#if TARGET_UE4_CL >= CL_FNETWORKVERSION
			else
			{
				uint32 LocalNetworkVersion = FNetworkVersion::GetLocalNetworkVersion();
				*ControlChanBunch << LocalNetworkVersion;
			}
#endif


			if (bBeaconConnect)
			{
				if (!bSkipJoin)
				{
					MessageType = NMT_BeaconJoin;
					*ControlChanBunch << MessageType;
					*ControlChanBunch << InBeaconType;

					// Also immediately ack the beacon GUID setup; we're just going to let the server setup the client beacon,
					// through the actor channel
					MessageType = NMT_BeaconNetGUIDAck;
					*ControlChanBunch << MessageType;
					*ControlChanBunch << InBeaconType;
				}
			}
			else
			{
				// Then send NMT_Login
#if TARGET_UE4_CL < CL_CONSTUNIQUEID
				TSharedPtr<FUniqueNetId> DudPtr = MakeShareable(new FUniqueNetIdString(TEXT("Dud")));
#else
				TSharedPtr<const FUniqueNetId> DudPtr = MakeShareable(new FUniqueNetIdString(TEXT("Dud")));
#endif

				FUniqueNetIdRepl PlayerUID(DudPtr);
				FString BlankStr = TEXT("");
				FString ConnectURL = UUnitTest::UnitEnv->GetDefaultClientConnectURL();

				if (InNetID != NULL)
				{
					PlayerUID = *InNetID;
				}

				MessageType = NMT_Login;
				*ControlChanBunch << MessageType;
				*ControlChanBunch << BlankStr;
				*ControlChanBunch << ConnectURL;
				*ControlChanBunch << PlayerUID;


				// Now send NMT_Join, to trigger a fake player, which should then trigger replication of basic actor channels
				if (!bSkipJoin)
				{
					MessageType = NMT_Join;
					*ControlChanBunch << MessageType;
				}
			}


			// Big hack: Store OutRec value on the unit test control channel, to enable 'retry-send' code
			TargetConn->Channels[0]->OutRec = ControlChanBunch;

			TargetConn->SendRawBunch(*ControlChanBunch, true);


			bSuccess = true;

		}
		else
		{
			UE_LOG(LogUnitTest, Log, TEXT("Failed to kickoff connect to IP '%s', error: %s"), *ServerIP, *ConnectionError);
		}
	}
	else if (InNetDriver == NULL)
	{
		UE_LOG(LogUnitTest, Log, TEXT("Failed to create an instance of the unit test net driver"));
	}
	else
	{
		UE_LOG(LogUnitTest, Log, TEXT("Failed to get a reference to WorldContext"));
	}

	return bSuccess;
}