I’ve discovered this code, which joins a split screen player correctly, assigning a netId and all. However, this isn’t called when I call CreatePlayer, and so none of it happens and the NetId is NULL.
Note this code is found in this function:
void UWorld::NotifyControlMessage(UNetConnection* Connection, uint8 MessageType, class FInBunch& Bunch)
How do I get this to execute when I want to join a split screen player in an online game?
case NMT_JoinSplit:
{
// Handle server-side request for spawning a new controller using a child connection.
FString SplitRequestURL;
FUniqueNetIdRepl UniqueIdRepl;
FNetControlMessage<NMT_JoinSplit>::Receive(Bunch, SplitRequestURL, UniqueIdRepl);
// Compromise for passing splitscreen playercount through to gameplay login code,
// without adding a lot of extra unnecessary complexity throughout the login code.
// NOTE: This code differs from NMT_Login, by counting + 2 for SplitscreenCount
// (once for pending child connection, once for primary non-child connection)
FURL InURL( NULL, *SplitRequestURL, TRAVEL_Absolute );
if ( !InURL.Valid )
{
UE_LOG( LogNet, Error, TEXT( "NMT_JoinSplit: Invalid URL %s" ), *SplitRequestURL );
Bunch.SetError();
break;
}
uint8 SplitscreenCount = FMath::Min(Connection->Children.Num() + 2, 255);
// Don't allow clients to specify this value
InURL.RemoveOption(TEXT("SplitscreenCount"));
InURL.AddOption(*FString::Printf(TEXT("SplitscreenCount=%i"), SplitscreenCount));
SplitRequestURL = InURL.ToString();
// skip to the first option in the URL
const TCHAR* Tmp = *SplitRequestURL;
for (; *Tmp && *Tmp != '?'; Tmp++);
// keep track of net id for player associated with remote connection
Connection->PlayerId = UniqueIdRepl.GetUniqueNetId();
// go through the same full login process for the split player even though it's all in the same frame
FString ErrorMsg;
AuthorityGameMode->PreLogin(Tmp, Connection->LowLevelGetRemoteAddress(), Connection->PlayerId, ErrorMsg);
if (!ErrorMsg.IsEmpty())
{
// if any splitscreen viewport fails to join, all viewports on that client also fail
UE_LOG(LogNet, Log, TEXT("PreLogin failure: %s"), *ErrorMsg);
NETWORK_PROFILER(GNetworkProfiler.TrackEvent(TEXT("PRELOGIN FAILURE"), *ErrorMsg));
FNetControlMessage<NMT_Failure>::Send(Connection, ErrorMsg);
Connection->FlushNet(true);
//@todo sz - can't close the connection here since it will leave the failure message
// in the send buffer and just close the socket.
//Connection->Close();
}
else
{
// create a child network connection using the existing connection for its parent
check(Connection->GetUChildConnection() == NULL);
check(CurrentLevel);
UChildConnection* ChildConn = NetDriver->CreateChild(Connection);
ChildConn->PlayerId = Connection->PlayerId;
ChildConn->RequestURL = SplitRequestURL;
ChildConn->ClientWorldPackageName = CurrentLevel->GetOutermost()->GetFName();
// create URL from string
FURL JoinSplitURL(NULL, *SplitRequestURL, TRAVEL_Absolute);
UE_LOG(LogNet, Log, TEXT("JOINSPLIT: Join request: URL=%s"), *JoinSplitURL.ToString());
APlayerController* PC = SpawnPlayActor(ChildConn, ROLE_AutonomousProxy, JoinSplitURL, ChildConn->PlayerId, ErrorMsg, uint8(Connection->Children.Num()));
if (PC == NULL)
{
// Failed to connect.
UE_LOG(LogNet, Log, TEXT("JOINSPLIT: Join failure: %s"), *ErrorMsg);
NETWORK_PROFILER(GNetworkProfiler.TrackEvent(TEXT("JOINSPLIT FAILURE"), *ErrorMsg));
// remove the child connection
Connection->Children.Remove(ChildConn);
// if any splitscreen viewport fails to join, all viewports on that client also fail
FNetControlMessage<NMT_Failure>::Send(Connection, ErrorMsg);
Connection->FlushNet(true);
//@todo sz - can't close the connection here since it will leave the failure message
// in the send buffer and just close the socket.
//Connection->Close();
}
else
{
// Successfully spawned in game.
UE_LOG(LogNet, Log, TEXT("JOINSPLIT: Succeeded: %s PlayerId: %s"),
*ChildConn->PlayerController->PlayerState->PlayerName,
ChildConn->PlayerController->PlayerState->UniqueId.IsValid() ? *ChildConn->PlayerController->PlayerState->UniqueId->ToDebugString() : TEXT("INVALID"));
}
}