Skip to content

Commit

Permalink
feat(matchmake-extension): Support additionalParticipants in AutoMatc…
Browse files Browse the repository at this point in the history
…hmakeWithParamPostpone
  • Loading branch information
ashquarky committed Jul 18, 2024
1 parent 98a2806 commit 2c01a31
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 7 deletions.
66 changes: 66 additions & 0 deletions globals/matchmaking_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -625,3 +625,69 @@ func ChangeSessionOwner(currentOwner *nex.PRUDPConnection, gathering uint32, isL
return false
})
}

func MovePlayersToSession(newSession *CommonMatchmakeSession, connectionIDs []uint32, initiatingConnection *nex.PRUDPConnection, joinMessage string) *nex.Error {
endpoint := initiatingConnection.Endpoint().(*nex.PRUDPEndPoint)
server := endpoint.Server

for _, connectionID := range connectionIDs {
target := endpoint.FindConnectionByID(connectionID)
if target == nil {
Logger.Warning("Connection not found")
continue
}

// * Switch to new gathering
category := notifications.NotificationCategories.SwitchGathering
subtype := notifications.NotificationSubTypes.SwitchGathering.None

oEvent := notifications_types.NewNotificationEvent()
oEvent.PIDSource = initiatingConnection.PID()
oEvent.Type = types.NewPrimitiveU32(notifications.BuildNotificationType(category, subtype))
oEvent.Param1 = newSession.GameMatchmakeSession.ID.Copy().(*types.PrimitiveU32)
oEvent.Param2 = types.NewPrimitiveU32(target.PID().LegacyValue()) // TODO - This assumes a legacy client. Will not work on the Switch

stream := nex.NewByteStreamOut(endpoint.LibraryVersions(), endpoint.ByteStreamSettings())

oEvent.WriteTo(stream)

rmcRequest := nex.NewRMCRequest(endpoint)
rmcRequest.ProtocolID = notifications.ProtocolID
rmcRequest.CallID = CurrentMatchmakingCallID.Next()
rmcRequest.MethodID = notifications.MethodProcessNotificationEvent
rmcRequest.Parameters = stream.Bytes()

rmcRequestBytes := rmcRequest.Bytes()

var messagePacket nex.PRUDPPacketInterface

if target.DefaultPRUDPVersion == 0 {
messagePacket, _ = nex.NewPRUDPPacketV0(server, target, nil)
} else {
messagePacket, _ = nex.NewPRUDPPacketV1(server, target, nil)
}

messagePacket.SetType(constants.DataPacket)
messagePacket.AddFlag(constants.PacketFlagNeedsAck)
messagePacket.AddFlag(constants.PacketFlagReliable)
messagePacket.SetSourceVirtualPortStreamType(target.StreamType)
messagePacket.SetSourceVirtualPortStreamID(endpoint.StreamID)
messagePacket.SetDestinationVirtualPortStreamType(target.StreamType)
messagePacket.SetDestinationVirtualPortStreamID(target.StreamID)
messagePacket.SetPayload(rmcRequestBytes)

server.Send(messagePacket)

// * Remove from old session(s)
// * Do it manually instead of RemoveConnectionFromAllSessions to avoid host migration and other confusing
// * notifications
for gid := FindConnectionSession(target.ID); gid != 0; {
RemoveConnectionIDFromSession(target.ID, gid)
gid = FindConnectionSession(target.ID)
}
// * Add to new session!
AddPlayersToSession(newSession, []uint32{target.ID}, initiatingConnection, "")
}

return nil
}
49 changes: 42 additions & 7 deletions matchmake-extension/auto_matchmake_with_param_postpone.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,35 @@ func (commonProtocol *CommonProtocol) autoMatchmakeWithParamPostpone(err error,
connection := packet.Sender().(*nex.PRUDPConnection)
endpoint := connection.Endpoint().(*nex.PRUDPEndPoint)

// * A client may disconnect from a session without leaving reliably,
// * so let's make sure the client is removed from the session
common_globals.RemoveConnectionFromAllSessions(connection)
// * Process additionalParticipants early so we can cancel matchmaking if it's wrong
// * additionalParticipants is used by Splatoon to move Fest teams around between rooms
oldGid := autoMatchmakeParam.GIDForParticipationCheck.Value
oldGathering := common_globals.Sessions[oldGid]
// * Check the caller is actually in the old session
useAdditionalParticipants := oldGathering != nil && oldGathering.ConnectionIDs.Has(connection.ID)

// * Check the other participants are actually in the old session, and note down the connection IDs
additionalParticipants := make([]uint32, autoMatchmakeParam.AdditionalParticipants.Length()+1)
// * If using additionalParticipants we'll *move* everyone, rather than disconnect/reconnect.
// * This prevents issues from host migration and disconnected notifications.
if useAdditionalParticipants {
for i, pid := range autoMatchmakeParam.AdditionalParticipants.Slice() {
targetConnection := endpoint.FindConnectionByPID(pid.Value())
if targetConnection == nil || !oldGathering.ConnectionIDs.Has(targetConnection.ID) {
// * This code is so early in the matchmaking process so this error can be here
return nil, nex.NewError(nex.ResultCodes.RendezVous.NotParticipatedGathering, "Couldn't find connection")
}

additionalParticipants[i] = targetConnection.ID
}

// * Include the host too!
additionalParticipants[len(additionalParticipants)-1] = connection.ID
} else {
// * A client may disconnect from a session without leaving reliably,
// * so let's make sure the client is removed from the session.
common_globals.RemoveConnectionFromAllSessions(connection)
}

matchmakeSession := autoMatchmakeParam.SourceMatchmakeSession

Expand All @@ -37,10 +63,19 @@ func (commonProtocol *CommonProtocol) autoMatchmakeWithParamPostpone(err error,
session = sessions[0]
}

errCode := common_globals.AddPlayersToSession(session, []uint32{connection.ID}, connection, "")
if errCode != nil {
common_globals.Logger.Error(errCode.Error())
return nil, errCode
if useAdditionalParticipants {
// * Move everyone. They're still connected to their old session
errCode := common_globals.MovePlayersToSession(session, additionalParticipants, connection, "")
if errCode != nil {
common_globals.Logger.Error(errCode.Error())
return nil, errCode
}
} else {
errCode := common_globals.AddPlayersToSession(session, []uint32{connection.ID}, connection, "")
if errCode != nil {
common_globals.Logger.Error(errCode.Error())
return nil, errCode
}
}

matchmakeDataHolder := types.NewAnyDataHolder()
Expand Down

0 comments on commit 2c01a31

Please sign in to comment.