diff --git a/globals/matchmaking_globals.go b/globals/matchmaking_globals.go index 135f91f..b6c0843 100644 --- a/globals/matchmaking_globals.go +++ b/globals/matchmaking_globals.go @@ -11,7 +11,7 @@ type CommonMatchmakeSession struct { ConnectionIDs *nex.MutexSlice[uint32] // * Players in the room, referenced by their connection IDs. This is used instead of the PID in order to ensure we're talking to the correct client (in case of e.g. multiple logins) } -var Sessions map[uint32]*CommonMatchmakeSession + var GetUserFriendPIDsHandler func(pid uint32) []uint32 var CurrentGatheringID = nex.NewCounter[uint32](0) var CurrentMatchmakingCallID = nex.NewCounter[uint32](0) diff --git a/globals/matchmaking_utils.go b/globals/matchmaking_utils.go index 1151cac..aa1c5fc 100644 --- a/globals/matchmaking_utils.go +++ b/globals/matchmaking_utils.go @@ -1,6 +1,7 @@ package common_globals import ( + "sync" "crypto/rand" "fmt" "strconv" @@ -9,6 +10,7 @@ import ( "github.com/PretendoNetwork/nex-go/v2" "github.com/PretendoNetwork/nex-go/v2/constants" "github.com/PretendoNetwork/nex-go/v2/types" + "github.com/PretendoNetwork/nex-protocols-go/v2/globals" match_making "github.com/PretendoNetwork/nex-protocols-go/v2/match-making" match_making_types "github.com/PretendoNetwork/nex-protocols-go/v2/match-making/types" notifications "github.com/PretendoNetwork/nex-protocols-go/v2/notifications" @@ -16,17 +18,79 @@ import ( "golang.org/x/exp/slices" ) +var sessions map[uint32]*CommonMatchmakeSession +var sessionsMutex = sync.RWMutex{} + +var onSessionCreatedHandlers []func(gid uint32) +var onSessionDeletedHandlers []func(gid uint32) +var onPlayerJoinSessionHandlers []func(gid uint32, cid uint32) +var onPlayerLeaveSessionHandlers []func(gid uint32, cid uint32, gracefully bool) + +var filterFoundCandidateSessions []func(sessions []uint32, connection *nex.PRUDPConnection, searchMatchmakeSession *match_making_types.MatchmakeSession) []uint32 + +var SessionManagementDebugLog = false + +func MakeSessions() { + sessions = make(map[uint32]*CommonMatchmakeSession) +} + +// GetSession returns a session using the gathering ID. +func GetSession(gatheringID uint32) (*CommonMatchmakeSession, bool) { + sessionsMutex.RLock() + defer sessionsMutex.RUnlock() + + ret, ok := sessions[gatheringID] + return ret, ok +} + +// EachSession runs a callback for every session until it returns true +func EachSession(callback func(index uint32, value *CommonMatchmakeSession) bool) bool { + sessionsMutex.RLock() + defer sessionsMutex.RUnlock() + + for i, value := range sessions { + if callback(i, value) { + return true + } + } + + return false +} + +// OnSessionCreated sets a callback that will run just after a session is created +func OnSessionCreated(handler func(gid uint32)) { + onSessionCreatedHandlers = append(onSessionCreatedHandlers, handler) +} + +// OnSessionDeleted sets a callback that will run just before a session is deleted +func OnSessionDeleted(handler func(gid uint32)) { + onSessionDeletedHandlers = append(onSessionDeletedHandlers, handler) +} + +// OnPlayerJoinSession sets a callback that will run just after a connection joins a session +func OnPlayerJoinSession(handler func(gid uint32, cid uint32)) { + onPlayerJoinSessionHandlers = append(onPlayerJoinSessionHandlers, handler) +} + +// OnPlayerLeaveSession sets a callback that will run just before a connection leaves a session +func OnPlayerLeaveSession(handler func(gid uint32, cid uint32, gracefully bool)) { + onPlayerLeaveSessionHandlers = append(onPlayerLeaveSessionHandlers, handler) +} + +// FilterFoundCandidateSessions sets a callback that filters or reorders the found sessions, with the session mutex already RLocked +func FilterFoundCandidateSessions(handler func(sessions []uint32, connection *nex.PRUDPConnection, searchMatchmakeSession *match_making_types.MatchmakeSession) []uint32) { + filterFoundCandidateSessions = append(filterFoundCandidateSessions, handler) +} + // GetAvailableGatheringID returns a gathering ID which doesn't belong to any session // Returns 0 if no IDs are available (math.MaxUint32 has been reached) func GetAvailableGatheringID() uint32 { return CurrentGatheringID.Next() } -// FindOtherConnectionID searches a connection ID on the session that isn't the given one -// Returns 0 if no connection ID could be found -func FindOtherConnectionID(excludedConnectionID uint32, gatheringID uint32) uint32 { +func findOtherConnectionIDImpl(excludedConnectionID uint32, gatheringID uint32) uint32 { var otherConnectionID uint32 = 0 - if session, ok := Sessions[gatheringID]; ok { + if session, ok := sessions[gatheringID]; ok { session.ConnectionIDs.Each(func(_ int, connectionID uint32) bool { if connectionID != excludedConnectionID { otherConnectionID = connectionID @@ -40,89 +104,56 @@ func FindOtherConnectionID(excludedConnectionID uint32, gatheringID uint32) uint return otherConnectionID } -// RemoveConnectionIDFromSession removes a PRUDP connection from the session -func RemoveConnectionIDFromSession(id uint32, gathering uint32) { - Sessions[gathering].ConnectionIDs.DeleteAll(id) +// FindOtherConnectionID searches a connection ID on the session that isn't the given one +// Returns 0 if no connection ID could be found +func FindOtherConnectionID(excludedConnectionID uint32, gatheringID uint32) uint32 { + sessionsMutex.RLock() + defer sessionsMutex.RUnlock() - if Sessions[gathering].ConnectionIDs.Size() == 0 { - delete(Sessions, gathering) - } else { - // Update the participation count with the new connection ID count - Sessions[gathering].GameMatchmakeSession.ParticipationCount.Value = uint32(Sessions[gathering].ConnectionIDs.Size()) - } + return findOtherConnectionIDImpl(excludedConnectionID, gatheringID) } -// FindConnectionSession searches for session the given connection ID is connected to -func FindConnectionSession(id uint32) uint32 { - for gatheringID := range Sessions { - if Sessions[gatheringID].ConnectionIDs.Has(id) { - return gatheringID - } +func removeSessionImpl(connection *nex.PRUDPConnection, gathering uint32) { + session, ok := sessions[gathering] + if !ok { + return } - - return 0 -} - -// RemoveConnectionFromAllSessions removes a connection from every session -func RemoveConnectionFromAllSessions(connection *nex.PRUDPConnection) { - // * Keep checking until no session is found - for gid := FindConnectionSession(connection.ID); gid != 0; { - session := Sessions[gid] - lenParticipants := session.ConnectionIDs.Size() - - RemoveConnectionIDFromSession(connection.ID, gid) - - if lenParticipants <= 1 { - gid = FindConnectionSession(connection.ID) - continue - } + if session.ConnectionIDs.Size() != 0 { + endpoint := connection.Endpoint().(*nex.PRUDPEndPoint) + server := endpoint.Server ownerPID := session.GameMatchmakeSession.Gathering.OwnerPID - if ownerPID.Equals(connection.PID()) { - // * This flag tells the server to change the matchmake session owner if they disconnect - // * If the flag is not set, delete the session - // * More info: https://nintendo-wiki.pretendo.network/docs/nex/protocols/match-making/types#flags - if session.GameMatchmakeSession.Gathering.Flags.PAND(match_making.GatheringFlags.DisconnectChangeOwner) == 0 { - delete(Sessions, gid) - } else { - ChangeSessionOwner(connection, gid, true) - } - } else { - endpoint := connection.Endpoint().(*nex.PRUDPEndPoint) - server := endpoint.Server + category := notifications.NotificationCategories.GatheringUnregistered + subtype := notifications.NotificationSubTypes.GatheringUnregistered.None - category := notifications.NotificationCategories.Participation - subtype := notifications.NotificationSubTypes.Participation.Disconnected - - oEvent := notifications_types.NewNotificationEvent() - oEvent.PIDSource = connection.PID() - oEvent.Type = types.NewPrimitiveU32(notifications.BuildNotificationType(category, subtype)) - oEvent.Param1 = types.NewPrimitiveU32(gid) - oEvent.Param2 = types.NewPrimitiveU32(connection.PID().LegacyValue()) // TODO - This assumes a legacy client. This won't work on the Switch + oEvent := notifications_types.NewNotificationEvent() + oEvent.PIDSource = ownerPID + oEvent.Type = types.NewPrimitiveU32(notifications.BuildNotificationType(category, subtype)) + oEvent.Param1 = types.NewPrimitiveU32(gathering) - stream := nex.NewByteStreamOut(endpoint.LibraryVersions(), endpoint.ByteStreamSettings()) + stream := nex.NewByteStreamOut(endpoint.LibraryVersions(), endpoint.ByteStreamSettings()) - oEvent.WriteTo(stream) + oEvent.WriteTo(stream) - rmcRequest := nex.NewRMCRequest(endpoint) - rmcRequest.ProtocolID = notifications.ProtocolID - rmcRequest.CallID = CurrentMatchmakingCallID.Next() - rmcRequest.MethodID = notifications.MethodProcessNotificationEvent - rmcRequest.Parameters = stream.Bytes() + rmcRequest := nex.NewRMCRequest(endpoint) + rmcRequest.ProtocolID = notifications.ProtocolID + rmcRequest.CallID = CurrentMatchmakingCallID.Next() + rmcRequest.MethodID = notifications.MethodProcessNotificationEvent + rmcRequest.Parameters = stream.Bytes() - rmcRequestBytes := rmcRequest.Bytes() + rmcRequestBytes := rmcRequest.Bytes() - target := endpoint.FindConnectionByPID(ownerPID.Value()) + session.ConnectionIDs.Each(func(_ int, connectionID uint32) bool { + target := endpoint.FindConnectionByID(connectionID) if target == nil { - Logger.Warning("Target connection not found") - gid = FindConnectionSession(connection.ID) - continue + Logger.Warning("Connection not found") + return false } var messagePacket nex.PRUDPPacketInterface - if connection.DefaultPRUDPVersion == 0 { + if target.DefaultPRUDPVersion == 0 { messagePacket, _ = nex.NewPRUDPPacketV0(server, target, nil) } else { messagePacket, _ = nex.NewPRUDPPacketV1(server, target, nil) @@ -131,21 +162,184 @@ func RemoveConnectionFromAllSessions(connection *nex.PRUDPConnection) { messagePacket.SetType(constants.DataPacket) messagePacket.AddFlag(constants.PacketFlagNeedsAck) messagePacket.AddFlag(constants.PacketFlagReliable) - messagePacket.SetSourceVirtualPortStreamType(connection.StreamType) + messagePacket.SetSourceVirtualPortStreamType(target.StreamType) messagePacket.SetSourceVirtualPortStreamID(endpoint.StreamID) - messagePacket.SetDestinationVirtualPortStreamType(connection.StreamType) - messagePacket.SetDestinationVirtualPortStreamID(connection.StreamID) + messagePacket.SetDestinationVirtualPortStreamType(target.StreamType) + messagePacket.SetDestinationVirtualPortStreamID(target.StreamID) messagePacket.SetPayload(rmcRequestBytes) server.Send(messagePacket) + + return false + }) + } + + if SessionManagementDebugLog { + globals.Logger.Infof("GID %d: Deleted", gathering) + } + + for _, handler := range onSessionDeletedHandlers { + handler(gathering) + } + + delete(sessions, gathering) +} + +func RemoveSession(connection *nex.PRUDPConnection, gathering uint32) { + sessionsMutex.Lock() + defer sessionsMutex.Unlock() + + removeSessionImpl(connection, gathering) +} + +// RemoveConnectionIDFromSession removes a PRUDP connection from the session +func removeConnectionIDFromSessionImpl(connection *nex.PRUDPConnection, gathering uint32, gracefully bool) { + session, ok := sessions[gathering] + if !ok { + return + } + + for _, handler := range onPlayerLeaveSessionHandlers { + handler(gathering, connection.ID, gracefully) + } + + session.ConnectionIDs.DeleteAll(connection.ID) + + ownerPID := session.GameMatchmakeSession.Gathering.OwnerPID + lenParticipants := session.ConnectionIDs.Size() + + if SessionManagementDebugLog { + var grace string + if gracefully { + grace = "gracefully" + } else { + grace = "ungracefully" + } + globals.Logger.Infof("GID %d: Removed PID %d %s", gathering, connection.PID().Value(), grace) + } + + // * If there are no more participants, remove the session + if lenParticipants == 0 { + removeSessionImpl(connection, gathering) + return + } + + // * If the owner is the one being removed... + if ownerPID.Equals(connection.PID()) { + // * This flag tells the server to change the matchmake session owner if they disconnect + // * If the flag is not set, delete the session + // * More info: https://nintendo-wiki.pretendo.network/docs/nex/protocols/match-making/types#flags + if session.GameMatchmakeSession.Gathering.Flags.PAND(match_making.GatheringFlags.DisconnectChangeOwner) == 0 { + removeSessionImpl(connection, gathering) + return + } else { + changeSessionOwnerImpl(connection, gathering, true) + } + } + + endpoint := connection.Endpoint().(*nex.PRUDPEndPoint) + server := endpoint.Server + + category := notifications.NotificationCategories.Participation + + var subtype uint32 + if gracefully { + subtype = notifications.NotificationSubTypes.Participation.Ended + } else { + subtype = notifications.NotificationSubTypes.Participation.Disconnected + } + + oEvent := notifications_types.NewNotificationEvent() + oEvent.PIDSource = connection.PID() + oEvent.Type = types.NewPrimitiveU32(notifications.BuildNotificationType(category, subtype)) + oEvent.Param1 = types.NewPrimitiveU32(gathering) + oEvent.Param2 = types.NewPrimitiveU32(connection.PID().LegacyValue()) // TODO - This assumes a legacy client. This won't 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() + + target := endpoint.FindConnectionByPID(ownerPID.Value()) + if target == nil { + Logger.Warning("Target connection not found") + return + } + + var messagePacket nex.PRUDPPacketInterface + + if connection.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(connection.StreamType) + messagePacket.SetSourceVirtualPortStreamID(endpoint.StreamID) + messagePacket.SetDestinationVirtualPortStreamType(connection.StreamType) + messagePacket.SetDestinationVirtualPortStreamID(connection.StreamID) + messagePacket.SetPayload(rmcRequestBytes) + + server.Send(messagePacket) + + // * Update the participation count with the new connection ID count + session.GameMatchmakeSession.ParticipationCount.Value = uint32(session.ConnectionIDs.Size()) +} + +func RemoveConnectionIDFromSession(connection *nex.PRUDPConnection, gathering uint32, gracefully bool) { + sessionsMutex.Lock() + defer sessionsMutex.Unlock() + + removeConnectionIDFromSessionImpl(connection, gathering, gracefully) +} + +// FindConnectionSession searches for session the given connection ID is connected to +func findConnectionSessionImpl(id uint32) uint32 { + for gatheringID := range sessions { + if sessions[gatheringID].ConnectionIDs.Has(id) { + return gatheringID } + } + + return 0 +} + +func FindConnectionSession(id uint32) uint32 { + sessionsMutex.RLock() + defer sessionsMutex.RUnlock() + + return findConnectionSessionImpl(id) +} - gid = FindConnectionSession(connection.ID) +// RemoveConnectionFromAllsessions removes a connection from every session +func RemoveConnectionFromAllSessions(connection *nex.PRUDPConnection) { + sessionsMutex.Lock() + defer sessionsMutex.Unlock() + + // * Keep checking until no session is found + for gid := findConnectionSessionImpl(connection.ID); gid != 0; { + + removeConnectionIDFromSessionImpl(connection, gid, false) + + gid = findConnectionSessionImpl(connection.ID) } } // CreateSessionByMatchmakeSession creates a gathering from a MatchmakeSession func CreateSessionByMatchmakeSession(matchmakeSession *match_making_types.MatchmakeSession, searchMatchmakeSession *match_making_types.MatchmakeSession, hostPID *types.PID) (*CommonMatchmakeSession, *nex.Error) { + sessionsMutex.Lock() + defer sessionsMutex.Unlock() + sessionIndex := GetAvailableGatheringID() if sessionIndex == 0 { sessionIndex = GetAvailableGatheringID() // * Skip to index 1 @@ -177,27 +371,70 @@ func CreateSessionByMatchmakeSession(matchmakeSession *match_making_types.Matchm session.GameMatchmakeSession.MatchmakeParam.Params.Set(types.NewString("@SR"), SR) session.GameMatchmakeSession.MatchmakeParam.Params.Set(types.NewString("@GIR"), GIR) - Sessions[sessionIndex] = &session + sessions[sessionIndex] = &session + + if SessionManagementDebugLog { + globals.Logger.Infof("GID %d: Created", sessionIndex) + } - return Sessions[sessionIndex], nil + for _, handler := range onSessionCreatedHandlers { + handler(session.GameMatchmakeSession.ID.Value) + } + + return sessions[sessionIndex], nil +} + +// isSessionHostConnected checks if the current session host is connected +func isSessionHostConnected(session *CommonMatchmakeSession, endpoint *nex.PRUDPEndPoint) bool { + return session.ConnectionIDs.Each(func(_ int, connectionID uint32) bool { + target := endpoint.FindConnectionByID(connectionID) + if target == nil { + return false + } + return session.GameMatchmakeSession.HostPID.Equals(target.PID()) + }) } // FindSessionByMatchmakeSession finds a gathering that matches with a MatchmakeSession -func FindSessionByMatchmakeSession(pid *types.PID, searchMatchmakeSession *match_making_types.MatchmakeSession) uint32 { +func FindSessionByMatchmakeSession(connection *nex.PRUDPConnection, searchMatchmakeSession *match_making_types.MatchmakeSession, dirtySearchMatchmakeSession *match_making_types.MatchmakeSession) uint32 { + sessionsMutex.RLock() + defer sessionsMutex.RUnlock() + // * This portion finds any sessions that match the search session // * It does not care about anything beyond that, such as if the match is already full // * This is handled below - candidateSessionIndexes := make([]uint32, 0, len(Sessions)) - for index, session := range Sessions { - if session.SearchMatchmakeSession.Equals(searchMatchmakeSession) { - candidateSessionIndexes = append(candidateSessionIndexes, index) + candidateSessionIndexes := make([]uint32, 0, len(sessions)) + for index, session := range sessions { + if !session.SearchMatchmakeSession.Equals(searchMatchmakeSession) { + continue + } + // * Do not find the session if the host is not currently connected + if !isSessionHostConnected(session, connection.Endpoint().(*nex.PRUDPEndPoint)) { + continue } + + // * Do not find the room if the requesting connection is the host. This means + // * the host was disconnected but the room host PID wasn't updated yet by the rest of + // * the clients. The host suddenly being available again causes issues. + if (session.GameMatchmakeSession.HostPID.Equals(connection.PID())) { + continue + } + + candidateSessionIndexes = append(candidateSessionIndexes, index) + } + + for _, handler := range filterFoundCandidateSessions { + candidateSessionIndexes = handler(candidateSessionIndexes, connection, dirtySearchMatchmakeSession) } // TODO - This whole section assumes legacy clients. None of it will work on the Switch var friendList []uint32 for _, sessionIndex := range candidateSessionIndexes { - sessionToCheck := Sessions[sessionIndex] + sessionToCheck, ok := sessions[sessionIndex] + if !ok { + continue + } + if sessionToCheck.ConnectionIDs.Size() >= int(sessionToCheck.GameMatchmakeSession.MaximumParticipants.Value) { continue } @@ -215,7 +452,7 @@ func FindSessionByMatchmakeSession(pid *types.PID, searchMatchmakeSession *match } if len(friendList) == 0 { - friendList = GetUserFriendPIDsHandler(pid.LegacyValue()) // TODO - This grpc method needs to support the Switch + friendList = GetUserFriendPIDsHandler(connection.PID().LegacyValue()) // TODO - This grpc method needs to support the Switch } if !slices.Contains(friendList, sessionToCheck.GameMatchmakeSession.OwnerPID.LegacyValue()) { @@ -230,12 +467,27 @@ func FindSessionByMatchmakeSession(pid *types.PID, searchMatchmakeSession *match } // FindSessionsByMatchmakeSessionSearchCriterias finds a gathering that matches with the given search criteria -func FindSessionsByMatchmakeSessionSearchCriterias(pid *types.PID, searchCriterias []*match_making_types.MatchmakeSessionSearchCriteria, gameSpecificChecks func(searchCriteria *match_making_types.MatchmakeSessionSearchCriteria, matchmakeSession *match_making_types.MatchmakeSession) bool) []*CommonMatchmakeSession { - candidateSessions := make([]*CommonMatchmakeSession, 0, len(Sessions)) +func FindSessionsByMatchmakeSessionSearchCriterias(connection *nex.PRUDPConnection, searchCriterias []*match_making_types.MatchmakeSessionSearchCriteria, gameSpecificChecks func(searchCriteria *match_making_types.MatchmakeSessionSearchCriteria, matchmakeSession *match_making_types.MatchmakeSession) bool) []*CommonMatchmakeSession { + sessionsMutex.RLock() + defer sessionsMutex.RUnlock() + + candidateSessions := make([]*CommonMatchmakeSession, 0, len(sessions)) // TODO - This whole section assumes legacy clients. None of it will work on the Switch var friendList []uint32 - for _, session := range Sessions { + for _, session := range sessions { + // * Do not find the session if the host is not currently connected + if !isSessionHostConnected(session, connection.Endpoint().(*nex.PRUDPEndPoint)) { + continue + } + + // * Do not find the room if the requesting connection is the host. This means + // * the host was disconnected but the room host PID wasn't updated yet by the rest of + // * the clients. The host suddenly being available again causes issues. + if (session.GameMatchmakeSession.HostPID.Equals(connection.PID())) { + continue + } + for _, criteria := range searchCriterias { // * Check things like game specific attributes if gameSpecificChecks != nil { @@ -281,7 +533,7 @@ func FindSessionsByMatchmakeSessionSearchCriterias(pid *types.PID, searchCriteri } if len(friendList) == 0 { - friendList = GetUserFriendPIDsHandler(pid.LegacyValue()) // TODO - Support the Switch + friendList = GetUserFriendPIDsHandler(connection.PID().LegacyValue()) // TODO - Support the Switch } if !slices.Contains(friendList, session.GameMatchmakeSession.OwnerPID.LegacyValue()) { @@ -291,7 +543,7 @@ func FindSessionsByMatchmakeSessionSearchCriterias(pid *types.PID, searchCriteri candidateSessions = append(candidateSessions, session) - // We don't have to compare with other search criterias + // * We don't have to compare with other search criterias break } } @@ -346,10 +598,22 @@ func compareSearchCriteria[T ~uint16 | ~uint32](original T, search string) bool // AddPlayersToSession updates the given sessions state to include the provided connection IDs // Returns a NEX error code if failed func AddPlayersToSession(session *CommonMatchmakeSession, connectionIDs []uint32, initiatingConnection *nex.PRUDPConnection, joinMessage string) *nex.Error { + sessionsMutex.RLock() + defer sessionsMutex.RUnlock() + if (session.ConnectionIDs.Size() + len(connectionIDs)) > int(session.GameMatchmakeSession.Gathering.MaximumParticipants.Value) { return nex.NewError(nex.ResultCodes.RendezVous.SessionFull, fmt.Sprintf("Gathering %d is full", session.GameMatchmakeSession.Gathering.ID)) } + // * TOCTOU, just in case + _, ok := sessions[session.GameMatchmakeSession.Gathering.ID.Value] + if !ok { + return nex.NewError(nex.ResultCodes.RendezVous.SessionVoid, "change_error") + } + + endpoint := initiatingConnection.Endpoint().(*nex.PRUDPEndPoint) + server := endpoint.Server + for _, connectedID := range connectionIDs { if session.ConnectionIDs.Has(connectedID) { return nex.NewError(nex.ResultCodes.RendezVous.AlreadyParticipatedGathering, fmt.Sprintf("Connection ID %d is already in gathering %d", connectedID, session.GameMatchmakeSession.Gathering.ID)) @@ -357,21 +621,21 @@ func AddPlayersToSession(session *CommonMatchmakeSession, connectionIDs []uint32 session.ConnectionIDs.Add(connectedID) - // Update the participation count with the new connection ID count - session.GameMatchmakeSession.ParticipationCount.Value = uint32(session.ConnectionIDs.Size()) - } + if SessionManagementDebugLog { + conn := endpoint.FindConnectionByID(connectedID) + globals.Logger.Infof("GID %d: Added PID %d", session.GameMatchmakeSession.Gathering.ID.Value, conn.PID().Value()) + } - endpoint := initiatingConnection.Endpoint().(*nex.PRUDPEndPoint) - server := endpoint.Server + // * Update the participation count with the new connection ID count + session.GameMatchmakeSession.ParticipationCount.Value = uint32(session.ConnectionIDs.Size()) - session.ConnectionIDs.Each(func(_ int, connectionID uint32) bool { - target := endpoint.FindConnectionByID(connectionID) - if target == nil { - // TODO - Error here? - Logger.Warning("Player not found") - return false + for _, handler := range onPlayerJoinSessionHandlers { + handler(session.GameMatchmakeSession.ID.Value, connectedID) } + } + target := endpoint.FindConnectionByPID(session.GameMatchmakeSession.OwnerPID.Value()) + if target != nil { notificationCategory := notifications.NotificationCategories.Participation notificationSubtype := notifications.NotificationSubTypes.Participation.NewParticipant @@ -413,9 +677,7 @@ func AddPlayersToSession(session *CommonMatchmakeSession, connectionIDs []uint32 messagePacket.SetPayload(notificationRequestBytes) server.Send(messagePacket) - - return false - }) + } // * This appears to be correct. Tri-Force Heroes uses 3.9.0, // * and has issues if these notifications are sent. @@ -546,14 +808,17 @@ func AddPlayersToSession(session *CommonMatchmakeSession, connectionIDs []uint32 } // ChangeSessionOwner changes the session owner to a different connection -func ChangeSessionOwner(currentOwner *nex.PRUDPConnection, gathering uint32, isLeaving bool) { +func changeSessionOwnerImpl(currentOwner *nex.PRUDPConnection, gathering uint32, isLeaving bool) { endpoint := currentOwner.Endpoint().(*nex.PRUDPEndPoint) server := endpoint.Server - session := Sessions[gathering] + session, ok := sessions[gathering] + if !ok { + return + } var newOwner *nex.PRUDPConnection - newOwnerConnectionID := FindOtherConnectionID(currentOwner.ID, gathering) + newOwnerConnectionID := findOtherConnectionIDImpl(currentOwner.ID, gathering) if newOwnerConnectionID != 0 { newOwner = endpoint.FindConnectionByID(newOwnerConnectionID) if newOwner == nil { @@ -561,10 +826,10 @@ func ChangeSessionOwner(currentOwner *nex.PRUDPConnection, gathering uint32, isL return } - // If the current owner is the host and they are leaving, change it by the new owner - if session.GameMatchmakeSession.Gathering.HostPID.Equals(currentOwner.PID()) && isLeaving { - session.GameMatchmakeSession.Gathering.HostPID = newOwner.PID() + if SessionManagementDebugLog { + globals.Logger.Infof("GID %d: ChangeSessionOwner OWNER from PID %d to PID %d", gathering, currentOwner.PID().Value(), newOwner.PID().Value()) } + session.GameMatchmakeSession.Gathering.OwnerPID = newOwner.PID() } else { return @@ -625,3 +890,10 @@ func ChangeSessionOwner(currentOwner *nex.PRUDPConnection, gathering uint32, isL return false }) } + +func ChangeSessionOwner(currentOwner *nex.PRUDPConnection, gathering uint32, isLeaving bool) { + sessionsMutex.RLock() + defer sessionsMutex.RUnlock() + + changeSessionOwnerImpl(currentOwner, gathering, isLeaving) +} diff --git a/go.mod b/go.mod index cb1e7e7..be3c5c7 100644 --- a/go.mod +++ b/go.mod @@ -3,23 +3,23 @@ module github.com/PretendoNetwork/nex-protocols-common-go/v2 go 1.21 require ( - github.com/PretendoNetwork/nex-go/v2 v2.0.1 + github.com/PretendoNetwork/nex-go/v2 v2.0.5 github.com/PretendoNetwork/nex-protocols-go/v2 v2.0.1 github.com/PretendoNetwork/plogger-go v1.0.4 github.com/minio/minio-go/v7 v7.0.63 - golang.org/x/exp v0.0.0-20231006140011-7918f672742d + golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 ) require ( github.com/dolthub/maphash v0.1.0 // indirect github.com/dustin/go-humanize v1.0.1 // indirect - github.com/fatih/color v1.15.0 // indirect + github.com/fatih/color v1.17.0 // indirect github.com/google/uuid v1.4.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/jwalton/go-supportscolor v1.2.0 // indirect - github.com/klauspost/compress v1.17.5 // indirect + github.com/klauspost/compress v1.17.8 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect - github.com/lxzan/gws v1.8.0 // indirect + github.com/lxzan/gws v1.8.3 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/minio/md5-simd v1.1.2 // indirect @@ -31,10 +31,10 @@ require ( github.com/sirupsen/logrus v1.9.3 // indirect github.com/superwhiskers/crunch/v3 v3.5.7 // indirect golang.org/x/crypto v0.14.0 // indirect - golang.org/x/mod v0.13.0 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.17.0 // indirect - golang.org/x/sys v0.15.0 // indirect - golang.org/x/term v0.15.0 // indirect + golang.org/x/sys v0.20.0 // indirect + golang.org/x/term v0.20.0 // indirect golang.org/x/text v0.13.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/go.sum b/go.sum index 9bc05f3..fcf0aed 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/PretendoNetwork/nex-go/v2 v2.0.1 h1:7UEwulBtWD+HIbwB0uaRjBK1EXFLfSnv0t5+WyQYV0s= -github.com/PretendoNetwork/nex-go/v2 v2.0.1/go.mod h1:EZNyRVr0WpPLHZQqZZvarQ8/tXsEyVqLr6zy/hKCAV4= +github.com/PretendoNetwork/nex-go/v2 v2.0.5 h1:S/bYPb2SNUb9MSzai4wlqj/9J1JIiLuMtZcAAbBughM= +github.com/PretendoNetwork/nex-go/v2 v2.0.5/go.mod h1:iW1xjbg/vl2c3uheitUFxGcrt0sxaDxeXR5QqDcyLpI= github.com/PretendoNetwork/nex-protocols-go/v2 v2.0.1 h1:BqrHYF2JeYfB/JUmhU3pWR1qUJEEqUDM4pigXzi95Ik= github.com/PretendoNetwork/nex-protocols-go/v2 v2.0.1/go.mod h1:TAzlc/gOu6E5Ct2NoTpN+Ea9Gpjh38dTsGqfs0pfZ4w= github.com/PretendoNetwork/plogger-go v1.0.4 h1:PF7xHw9eDRHH+RsAP9tmAE7fG0N0p6H4iPwHKnsoXwc= @@ -11,10 +11,10 @@ github.com/dolthub/maphash v0.1.0 h1:bsQ7JsF4FkkWyrP3oCnFJgrCUAFbFf3kOl4L/QxPDyQ github.com/dolthub/maphash v0.1.0/go.mod h1:gkg4Ch4CdCDu5h6PMriVLawB7koZ+5ijb9puGMV50a4= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= -github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= -github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= -github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -22,13 +22,13 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/jwalton/go-supportscolor v1.2.0 h1:g6Ha4u7Vm3LIsQ5wmeBpS4gazu0UP1DRDE8y6bre4H8= github.com/jwalton/go-supportscolor v1.2.0/go.mod h1:hFVUAZV2cWg+WFFC4v8pT2X/S2qUUBYMioBD9AINXGs= -github.com/klauspost/compress v1.17.5 h1:d4vBd+7CHydUqpFBgUEKkSdtSugf9YFmSkvUYPquI5E= -github.com/klauspost/compress v1.17.5/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= +github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/lxzan/gws v1.8.0 h1:SqRuU6PUez/BA6CHB9BufV6n+gCnRtWHUntjLcaHA44= -github.com/lxzan/gws v1.8.0/go.mod h1:FcGeRMB7HwGuTvMLR24ku0Zx0p6RXqeKASeMc4VYgi4= +github.com/lxzan/gws v1.8.3 h1:umX2VLhXj7oVV4Sd2gCuqzrzpVWtqkKMy0tjHBBxXg0= +github.com/lxzan/gws v1.8.3/go.mod h1:FcGeRMB7HwGuTvMLR24ku0Zx0p6RXqeKASeMc4VYgi4= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -62,10 +62,10 @@ github.com/superwhiskers/crunch/v3 v3.5.7 h1:N9RLxaR65C36i26BUIpzPXGy2f6pQ7wisu2 github.com/superwhiskers/crunch/v3 v3.5.7/go.mod h1:4ub2EKgF1MAhTjoOCTU4b9uLMsAweHEa89aRrfAypXA= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= -golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= -golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= -golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -74,11 +74,11 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= +golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/match-making-ext/end_participation.go b/match-making-ext/end_participation.go index e7664eb..515f40d 100644 --- a/match-making-ext/end_participation.go +++ b/match-making-ext/end_participation.go @@ -2,13 +2,9 @@ package match_making_ext import ( "github.com/PretendoNetwork/nex-go/v2" - "github.com/PretendoNetwork/nex-go/v2/constants" "github.com/PretendoNetwork/nex-go/v2/types" common_globals "github.com/PretendoNetwork/nex-protocols-common-go/v2/globals" - match_making "github.com/PretendoNetwork/nex-protocols-go/v2/match-making" match_making_ext "github.com/PretendoNetwork/nex-protocols-go/v2/match-making-ext" - notifications "github.com/PretendoNetwork/nex-protocols-go/v2/notifications" - notifications_types "github.com/PretendoNetwork/nex-protocols-go/v2/notifications/types" ) func (commonProtocol *CommonProtocol) endParticipation(err error, packet nex.PacketInterface, callID uint32, idGathering *types.PrimitiveU32, strMessage *types.String) (*nex.RMCMessage, *nex.Error) { @@ -17,35 +13,15 @@ func (commonProtocol *CommonProtocol) endParticipation(err error, packet nex.Pac return nil, nex.NewError(nex.ResultCodes.Core.InvalidArgument, "change_error") } - session, ok := common_globals.Sessions[idGathering.Value] + session, ok := common_globals.GetSession(idGathering.Value) if !ok { return nil, nex.NewError(nex.ResultCodes.RendezVous.SessionVoid, "change_error") } connection := packet.Sender().(*nex.PRUDPConnection) endpoint := connection.Endpoint().(*nex.PRUDPEndPoint) - server := endpoint.Server - matchmakeSession := session.GameMatchmakeSession - ownerPID := matchmakeSession.Gathering.OwnerPID - - var deleteSession bool = false - if connection.PID().Equals(matchmakeSession.Gathering.OwnerPID) { - // * This flag tells the server to change the matchmake session owner if they disconnect - // * If the flag is not set, delete the session - // * More info: https://nintendo-wiki.pretendo.network/docs/nex/protocols/match-making/types#flags - if matchmakeSession.Gathering.Flags.PAND(match_making.GatheringFlags.DisconnectChangeOwner) == 0 { - deleteSession = true - } else { - common_globals.ChangeSessionOwner(connection, idGathering.Value, true) - } - } - - if deleteSession { - delete(common_globals.Sessions, idGathering.Value) - } else { - common_globals.RemoveConnectionIDFromSession(connection.ID, idGathering.Value) - } + common_globals.RemoveConnectionIDFromSession(connection, session.GameMatchmakeSession.ID.Value, true) retval := types.NewPrimitiveBool(true) @@ -60,53 +36,6 @@ func (commonProtocol *CommonProtocol) endParticipation(err error, packet nex.Pac rmcResponse.MethodID = match_making_ext.MethodEndParticipation rmcResponse.CallID = callID - category := notifications.NotificationCategories.Participation - subtype := notifications.NotificationSubTypes.Participation.Ended - - oEvent := notifications_types.NewNotificationEvent() - oEvent.PIDSource = connection.PID().Copy().(*types.PID) - oEvent.Type = types.NewPrimitiveU32(notifications.BuildNotificationType(category, subtype)) - oEvent.Param1 = idGathering.Copy().(*types.PrimitiveU32) - oEvent.Param2 = types.NewPrimitiveU32(connection.PID().LegacyValue()) // TODO - This assumes a legacy client. Will not work on the Switch - oEvent.StrParam = strMessage.Copy().(*types.String) - - stream := nex.NewByteStreamOut(endpoint.LibraryVersions(), endpoint.ByteStreamSettings()) - - oEvent.WriteTo(stream) - - rmcRequest := nex.NewRMCRequest(endpoint) - rmcRequest.ProtocolID = notifications.ProtocolID - rmcRequest.MethodID = notifications.MethodProcessNotificationEvent - rmcRequest.CallID = common_globals.CurrentMatchmakingCallID.Next() - rmcRequest.Parameters = stream.Bytes() - - rmcRequestBytes := rmcRequest.Bytes() - - target := endpoint.FindConnectionByPID(ownerPID.Value()) - if target == nil { - common_globals.Logger.Warning("Owner client not found") - return nil, nil - } - - 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) - if commonProtocol.OnAfterEndParticipation != nil { go commonProtocol.OnAfterEndParticipation(packet, idGathering, strMessage) } diff --git a/match-making/find_by_single_id.go b/match-making/find_by_single_id.go index 973b80d..1412776 100644 --- a/match-making/find_by_single_id.go +++ b/match-making/find_by_single_id.go @@ -13,7 +13,7 @@ func (commonProtocol *CommonProtocol) findBySingleID(err error, packet nex.Packe return nil, nex.NewError(nex.ResultCodes.Core.InvalidArgument, "change_error") } - session, ok := common_globals.Sessions[id.Value] + session, ok := common_globals.GetSession(id.Value) if !ok { return nil, nex.NewError(nex.ResultCodes.RendezVous.SessionVoid, "change_error") } diff --git a/match-making/get_session_urls.go b/match-making/get_session_urls.go index 783a54d..5f3b5b8 100644 --- a/match-making/get_session_urls.go +++ b/match-making/get_session_urls.go @@ -13,7 +13,7 @@ func (commonProtocol *CommonProtocol) getSessionURLs(err error, packet nex.Packe return nil, nex.NewError(nex.ResultCodes.Core.InvalidArgument, "change_error") } - session, ok := common_globals.Sessions[gid.Value] + session, ok := common_globals.GetSession(gid.Value) if !ok { return nil, nex.NewError(nex.ResultCodes.RendezVous.SessionVoid, "change_error") } diff --git a/match-making/protocol.go b/match-making/protocol.go index 96d7271..994c4d1 100644 --- a/match-making/protocol.go +++ b/match-making/protocol.go @@ -28,7 +28,7 @@ func NewCommonProtocol(protocol match_making.Interface) *CommonProtocol { protocol: protocol, } - common_globals.Sessions = make(map[uint32]*common_globals.CommonMatchmakeSession) + common_globals.MakeSessions() protocol.SetHandlerUnregisterGathering(commonProtocol.unregisterGathering) protocol.SetHandlerFindBySingleID(commonProtocol.findBySingleID) diff --git a/match-making/unregister_gathering.go b/match-making/unregister_gathering.go index f77abb4..cc95df6 100644 --- a/match-making/unregister_gathering.go +++ b/match-making/unregister_gathering.go @@ -2,12 +2,9 @@ package matchmaking import ( "github.com/PretendoNetwork/nex-go/v2" - "github.com/PretendoNetwork/nex-go/v2/constants" "github.com/PretendoNetwork/nex-go/v2/types" common_globals "github.com/PretendoNetwork/nex-protocols-common-go/v2/globals" match_making "github.com/PretendoNetwork/nex-protocols-go/v2/match-making" - notifications "github.com/PretendoNetwork/nex-protocols-go/v2/notifications" - notifications_types "github.com/PretendoNetwork/nex-protocols-go/v2/notifications/types" ) func (commonProtocol *CommonProtocol) unregisterGathering(err error, packet nex.PacketInterface, callID uint32, idGathering *types.PrimitiveU32) (*nex.RMCMessage, *nex.Error) { @@ -16,22 +13,19 @@ func (commonProtocol *CommonProtocol) unregisterGathering(err error, packet nex. return nil, nex.NewError(nex.ResultCodes.Core.InvalidArgument, "change_error") } - session, ok := common_globals.Sessions[idGathering.Value] + session, ok := common_globals.GetSession(idGathering.Value) if !ok { return nil, nex.NewError(nex.ResultCodes.RendezVous.SessionVoid, "change_error") } connection := packet.Sender().(*nex.PRUDPConnection) endpoint := connection.Endpoint().(*nex.PRUDPEndPoint) - server := endpoint.Server if !session.GameMatchmakeSession.Gathering.OwnerPID.Equals(connection.PID()) { return nil, nex.NewError(nex.ResultCodes.RendezVous.PermissionDenied, "change_error") } - gatheringPlayers := session.ConnectionIDs - - delete(common_globals.Sessions, idGathering.Value) + common_globals.RemoveSession(connection, idGathering.Value) retval := types.NewPrimitiveBool(true) @@ -46,55 +40,6 @@ func (commonProtocol *CommonProtocol) unregisterGathering(err error, packet nex. rmcResponse.MethodID = match_making.MethodUnregisterGathering rmcResponse.CallID = callID - category := notifications.NotificationCategories.GatheringUnregistered - subtype := notifications.NotificationSubTypes.GatheringUnregistered.None - - oEvent := notifications_types.NewNotificationEvent() - oEvent.PIDSource = connection.PID().Copy().(*types.PID) - oEvent.Type = types.NewPrimitiveU32(notifications.BuildNotificationType(category, subtype)) - oEvent.Param1 = idGathering.Copy().(*types.PrimitiveU32) - - stream := nex.NewByteStreamOut(endpoint.LibraryVersions(), endpoint.ByteStreamSettings()) - - oEvent.WriteTo(stream) - - rmcRequest := nex.NewRMCRequest(endpoint) - rmcRequest.ProtocolID = notifications.ProtocolID - rmcRequest.CallID = common_globals.CurrentMatchmakingCallID.Next() - rmcRequest.MethodID = notifications.MethodProcessNotificationEvent - rmcRequest.Parameters = stream.Bytes() - - rmcRequestBytes := rmcRequest.Bytes() - - gatheringPlayers.Each(func(_ int, connectionID uint32) bool { - target := endpoint.FindConnectionByID(connectionID) - if target == nil { - common_globals.Logger.Warning("Client not found") - return false - } - - 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) - - return false - }) - if commonProtocol.OnAfterUnregisterGathering != nil { go commonProtocol.OnAfterUnregisterGathering(packet, idGathering) } diff --git a/match-making/update_session_host.go b/match-making/update_session_host.go index ee8b413..503ad33 100644 --- a/match-making/update_session_host.go +++ b/match-making/update_session_host.go @@ -16,7 +16,7 @@ func (commonProtocol *CommonProtocol) updateSessionHost(err error, packet nex.Pa return nil, nex.NewError(nex.ResultCodes.Core.InvalidArgument, "change_error") } - session, ok := common_globals.Sessions[gid.Value] + session, ok := common_globals.GetSession(gid.Value) if !ok { return nil, nex.NewError(nex.ResultCodes.RendezVous.SessionVoid, "change_error") } @@ -29,6 +29,7 @@ func (commonProtocol *CommonProtocol) updateSessionHost(err error, packet nex.Pa return nil, nex.NewError(nex.ResultCodes.RendezVous.PermissionDenied, "change_error") } + originalHost := session.GameMatchmakeSession.Gathering.HostPID session.GameMatchmakeSession.Gathering.HostPID = connection.PID().Copy().(*types.PID) rmcResponse := nex.NewRMCSuccess(endpoint, nil) @@ -36,6 +37,10 @@ func (commonProtocol *CommonProtocol) updateSessionHost(err error, packet nex.Pa rmcResponse.MethodID = match_making.MethodUpdateSessionHost rmcResponse.CallID = callID + if common_globals.SessionManagementDebugLog { + common_globals.Logger.Infof("GID %d: UpdateSessionHost from PID %d to PID %d", gid.Value, originalHost.Value(), connection.PID().Value()) + } + if !isMigrateOwner.Value { if commonProtocol.OnAfterUpdateSessionHost != nil { go commonProtocol.OnAfterUpdateSessionHost(packet, gid, isMigrateOwner) @@ -73,7 +78,7 @@ func (commonProtocol *CommonProtocol) updateSessionHost(err error, packet nex.Pa rmcRequestBytes := rmcRequest.Bytes() - common_globals.Sessions[gid.Value].ConnectionIDs.Each(func(_ int, connectionID uint32) bool { + session.ConnectionIDs.Each(func(_ int, connectionID uint32) bool { target := endpoint.FindConnectionByID(connectionID) if target == nil { common_globals.Logger.Warning("Client not found") diff --git a/match-making/update_session_host_v1.go b/match-making/update_session_host_v1.go index 10bc7c6..3fd9761 100644 --- a/match-making/update_session_host_v1.go +++ b/match-making/update_session_host_v1.go @@ -13,7 +13,7 @@ func (commonProtocol *CommonProtocol) updateSessionHostV1(err error, packet nex. return nil, nex.NewError(nex.ResultCodes.Core.InvalidArgument, "change_error") } - session, ok := common_globals.Sessions[gid.Value] + session, ok := common_globals.GetSession(gid.Value) if !ok { return nil, nex.NewError(nex.ResultCodes.RendezVous.SessionVoid, "change_error") } @@ -25,11 +25,16 @@ func (commonProtocol *CommonProtocol) updateSessionHostV1(err error, packet nex. return nil, nex.NewError(nex.ResultCodes.RendezVous.PermissionDenied, "change_error") } + originalHost := session.GameMatchmakeSession.Gathering.HostPID session.GameMatchmakeSession.Gathering.HostPID = connection.PID() if session.GameMatchmakeSession.Gathering.Flags.PAND(match_making.GatheringFlags.DisconnectChangeOwner) != 0 { session.GameMatchmakeSession.Gathering.OwnerPID = connection.PID() } + if common_globals.SessionManagementDebugLog { + common_globals.Logger.Infof("GID %d: UpdateSessionHost from PID %d to PID %d", gid.Value, originalHost.Value(), connection.PID().Value()) + } + rmcResponse := nex.NewRMCSuccess(endpoint, nil) rmcResponse.ProtocolID = match_making.ProtocolID rmcResponse.MethodID = match_making.MethodUpdateSessionHostV1 diff --git a/match-making/update_session_url.go b/match-making/update_session_url.go index f61bc3a..624cb48 100644 --- a/match-making/update_session_url.go +++ b/match-making/update_session_url.go @@ -16,7 +16,7 @@ func (commonProtocol *CommonProtocol) updateSessionURL(err error, packet nex.Pac return nil, nex.NewError(nex.ResultCodes.Core.InvalidArgument, "change_error") } - session, ok := common_globals.Sessions[idGathering.Value] + session, ok := common_globals.GetSession(idGathering.Value) if !ok { return nil, nex.NewError(nex.ResultCodes.RendezVous.SessionVoid, "change_error") } @@ -26,65 +26,11 @@ func (commonProtocol *CommonProtocol) updateSessionURL(err error, packet nex.Pac server := endpoint.Server // * Mario Kart 7 seems to set an empty strURL, so I assume this is what the method does? + originalHost := session.GameMatchmakeSession.Gathering.HostPID session.GameMatchmakeSession.Gathering.HostPID = connection.PID().Copy().(*types.PID) - if session.GameMatchmakeSession.Gathering.Flags.PAND(match_making.GatheringFlags.DisconnectChangeOwner) != 0 { - originalOwner := session.GameMatchmakeSession.Gathering.OwnerPID - session.GameMatchmakeSession.Gathering.OwnerPID = connection.PID().Copy().(*types.PID) - - category := notifications.NotificationCategories.OwnershipChanged - subtype := notifications.NotificationSubTypes.OwnershipChanged.None - - oEvent := notifications_types.NewNotificationEvent() - oEvent.PIDSource = originalOwner.Copy().(*types.PID) - oEvent.Type = types.NewPrimitiveU32(notifications.BuildNotificationType(category, subtype)) - oEvent.Param1 = idGathering.Copy().(*types.PrimitiveU32) - oEvent.Param2 = types.NewPrimitiveU32(connection.PID().LegacyValue()) // TODO - This assumes a legacy client. Will not work on the Switch - - // TODO - StrParam doesn't have this value on some servers - // * https://github.com/kinnay/NintendoClients/issues/101 - // * unixTime := time.Now() - // * oEvent.StrParam = strconv.FormatInt(unixTime.UnixMicro(), 10) - - stream := nex.NewByteStreamOut(endpoint.LibraryVersions(), endpoint.ByteStreamSettings()) - - oEvent.WriteTo(stream) - - rmcRequest := nex.NewRMCRequest(endpoint) - rmcRequest.ProtocolID = notifications.ProtocolID - rmcRequest.CallID = common_globals.CurrentMatchmakingCallID.Next() - rmcRequest.MethodID = notifications.MethodProcessNotificationEvent - rmcRequest.Parameters = stream.Bytes() - - rmcRequestBytes := rmcRequest.Bytes() - - common_globals.Sessions[idGathering.Value].ConnectionIDs.Each(func(_ int, connectionID uint32) bool { - target := endpoint.FindConnectionByID(connectionID) - if target == nil { - common_globals.Logger.Warning("Client not found") - return false - } - - 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) - - return false - }) + + if common_globals.SessionManagementDebugLog { + common_globals.Logger.Infof("GID %d: UpdateSessionURL HOST from PID %d to PID %d", idGathering.Value, originalHost.Value(), connection.PID().Value()) } retval := types.NewPrimitiveBool(true) @@ -100,6 +46,57 @@ func (commonProtocol *CommonProtocol) updateSessionURL(err error, packet nex.Pac rmcResponse.MethodID = match_making.MethodGetSessionURLs rmcResponse.CallID = callID + category := notifications.NotificationCategories.HostChanged + subtype := notifications.NotificationSubTypes.HostChanged.None + + oEvent := notifications_types.NewNotificationEvent() + oEvent.PIDSource = connection.PID() + oEvent.Type = types.NewPrimitiveU32(notifications.BuildNotificationType(category, subtype)) + oEvent.Param1 = types.NewPrimitiveU32(session.GameMatchmakeSession.Gathering.ID.Value) + oEvent.Param2 = types.NewPrimitiveU32(0) // TODO - Research what this means + + // TODO - StrParam doesn't have this value on some servers + // * https://github.com/kinnay/NintendoClients/issues/101 + // * unixTime := time.Now() + // * oEvent.StrParam = strconv.FormatInt(unixTime.UnixMicro(), 10) + + stream := nex.NewByteStreamOut(endpoint.LibraryVersions(), endpoint.ByteStreamSettings()) + + oEvent.WriteTo(stream) + + rmcRequest := nex.NewRMCRequest(endpoint) + rmcRequest.ProtocolID = notifications.ProtocolID + rmcRequest.CallID = common_globals.CurrentMatchmakingCallID.Next() + rmcRequest.MethodID = notifications.MethodProcessNotificationEvent + rmcRequest.Parameters = stream.Bytes() + + rmcRequestBytes := rmcRequest.Bytes() + + target := endpoint.FindConnectionByPID(originalHost.Value()) + if target == nil { + common_globals.Logger.Warning("Connection not found") + return rmcResponse, nil + } + + 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) + if commonProtocol.OnAfterUpdateSessionURL != nil { go commonProtocol.OnAfterUpdateSessionURL(packet, idGathering, strURL) } diff --git a/matchmake-extension/auto_matchmake_postpone.go b/matchmake-extension/auto_matchmake_postpone.go index e3d4c23..28aae7e 100644 --- a/matchmake-extension/auto_matchmake_postpone.go +++ b/matchmake-extension/auto_matchmake_postpone.go @@ -37,8 +37,9 @@ func (commonProtocol *CommonProtocol) autoMatchmakePostpone(err error, packet ne } searchMatchmakeSession := matchmakeSession.Copy().(*match_making_types.MatchmakeSession) + dirtySearchMatchmakeSession := matchmakeSession.Copy().(*match_making_types.MatchmakeSession) commonProtocol.CleanupSearchMatchmakeSession(searchMatchmakeSession) - sessionIndex := common_globals.FindSessionByMatchmakeSession(connection.PID(), searchMatchmakeSession) + sessionIndex := common_globals.FindSessionByMatchmakeSession(connection, searchMatchmakeSession, dirtySearchMatchmakeSession) var session *common_globals.CommonMatchmakeSession if sessionIndex == 0 { @@ -49,7 +50,12 @@ func (commonProtocol *CommonProtocol) autoMatchmakePostpone(err error, packet ne return nil, errCode } } else { - session = common_globals.Sessions[sessionIndex] + var ok bool + session, ok = common_globals.GetSession(sessionIndex) + // TOCTOU, just in case + if !ok { + return nil, nex.NewError(nex.ResultCodes.RendezVous.SessionVoid, "change_error") + } } errCode := common_globals.AddPlayersToSession(session, []uint32{connection.ID}, connection, message.Value) diff --git a/matchmake-extension/auto_matchmake_with_param_postpone.go b/matchmake-extension/auto_matchmake_with_param_postpone.go index c601397..ec0061a 100644 --- a/matchmake-extension/auto_matchmake_with_param_postpone.go +++ b/matchmake-extension/auto_matchmake_with_param_postpone.go @@ -23,7 +23,7 @@ func (commonProtocol *CommonProtocol) autoMatchmakeWithParamPostpone(err error, matchmakeSession := autoMatchmakeParam.SourceMatchmakeSession - sessions := common_globals.FindSessionsByMatchmakeSessionSearchCriterias(connection.PID(), autoMatchmakeParam.LstSearchCriteria.Slice(), commonProtocol.GameSpecificMatchmakeSessionSearchCriteriaChecks) + sessions := common_globals.FindSessionsByMatchmakeSessionSearchCriterias(connection, autoMatchmakeParam.LstSearchCriteria.Slice(), commonProtocol.GameSpecificMatchmakeSessionSearchCriteriaChecks) var session *common_globals.CommonMatchmakeSession if len(sessions) == 0 { diff --git a/matchmake-extension/auto_matchmake_with_search_criteria_postpone.go b/matchmake-extension/auto_matchmake_with_search_criteria_postpone.go index 5092b59..6802a83 100644 --- a/matchmake-extension/auto_matchmake_with_search_criteria_postpone.go +++ b/matchmake-extension/auto_matchmake_with_search_criteria_postpone.go @@ -30,7 +30,7 @@ func (commonProtocol *CommonProtocol) autoMatchmakeWithSearchCriteriaPostpone(er return nil, nex.NewError(nex.ResultCodes.Core.InvalidArgument, "change_error") } - sessions := common_globals.FindSessionsByMatchmakeSessionSearchCriterias(connection.PID(), lstSearchCriteria.Slice(), commonProtocol.GameSpecificMatchmakeSessionSearchCriteriaChecks) + sessions := common_globals.FindSessionsByMatchmakeSessionSearchCriterias(connection, lstSearchCriteria.Slice(), commonProtocol.GameSpecificMatchmakeSessionSearchCriteriaChecks) var session *common_globals.CommonMatchmakeSession if len(sessions) == 0 { diff --git a/matchmake-extension/browse_matchmake_session.go b/matchmake-extension/browse_matchmake_session.go index 18e8c64..5524e12 100644 --- a/matchmake-extension/browse_matchmake_session.go +++ b/matchmake-extension/browse_matchmake_session.go @@ -21,7 +21,7 @@ func (commonProtocol *CommonProtocol) browseMatchmakeSession(err error, packet n searchCriterias := []*match_making_types.MatchmakeSessionSearchCriteria{searchCriteria} - sessions := common_globals.FindSessionsByMatchmakeSessionSearchCriterias(connection.PID(), searchCriterias, commonProtocol.GameSpecificMatchmakeSessionSearchCriteriaChecks) + sessions := common_globals.FindSessionsByMatchmakeSessionSearchCriterias(connection, searchCriterias, commonProtocol.GameSpecificMatchmakeSessionSearchCriteriaChecks) // TODO - Is this right? if resultRange.Offset.Value != math.MaxUint32 { diff --git a/matchmake-extension/close_participation.go b/matchmake-extension/close_participation.go index 6bc1b00..1c4aaab 100644 --- a/matchmake-extension/close_participation.go +++ b/matchmake-extension/close_participation.go @@ -13,7 +13,7 @@ func (commonProtocol *CommonProtocol) closeParticipation(err error, packet nex.P return nil, nex.NewError(nex.ResultCodes.Core.InvalidArgument, "change_error") } - session, ok := common_globals.Sessions[gid.Value] + session, ok := common_globals.GetSession(gid.Value) if !ok { return nil, nex.NewError(nex.ResultCodes.RendezVous.SessionVoid, "change_error") } diff --git a/matchmake-extension/get_simple_playing_session.go b/matchmake-extension/get_simple_playing_session.go index 5059426..81809a5 100644 --- a/matchmake-extension/get_simple_playing_session.go +++ b/matchmake-extension/get_simple_playing_session.go @@ -28,8 +28,8 @@ func (commonProtocol *CommonProtocol) getSimplePlayingSession(err error, packet } simplePlayingSessions := make(map[string]*match_making_types.SimplePlayingSession) - - for gatheringID, session := range common_globals.Sessions { + + if common_globals.EachSession((func(gatheringID uint32, session *common_globals.CommonMatchmakeSession) bool { for _, pid := range listPID.Slice() { key := fmt.Sprintf("%d-%d", gatheringID, pid.Value()) if simplePlayingSessions[key] == nil { @@ -49,7 +49,7 @@ func (commonProtocol *CommonProtocol) getSimplePlayingSession(err error, packet attribute0, err := session.GameMatchmakeSession.Attributes.Get(0) if err != nil { common_globals.Logger.Error(err.Error()) - return nil, nex.NewError(nex.ResultCodes.Core.InvalidArgument, "change_error") + return true } simplePlayingSessions[key] = match_making_types.NewSimplePlayingSession() @@ -60,8 +60,12 @@ func (commonProtocol *CommonProtocol) getSimplePlayingSession(err error, packet } } } + return false + })) { + return nil, nex.NewError(nex.ResultCodes.Core.InvalidArgument, "change_error") } + lstSimplePlayingSession := types.NewList[*match_making_types.SimplePlayingSession]() for _, simplePlayingSession := range simplePlayingSessions { diff --git a/matchmake-extension/join_matchmake_session.go b/matchmake-extension/join_matchmake_session.go index 789523e..6dc8a89 100644 --- a/matchmake-extension/join_matchmake_session.go +++ b/matchmake-extension/join_matchmake_session.go @@ -13,7 +13,7 @@ func (commonProtocol *CommonProtocol) joinMatchmakeSession(err error, packet nex return nil, nex.NewError(nex.ResultCodes.Core.InvalidArgument, "change_error") } - session, ok := common_globals.Sessions[gid.Value] + session, ok := common_globals.GetSession(gid.Value) if !ok { return nil, nex.NewError(nex.ResultCodes.RendezVous.SessionVoid, "change_error") } diff --git a/matchmake-extension/join_matchmake_session_ex.go b/matchmake-extension/join_matchmake_session_ex.go index fb3d647..3d0323d 100644 --- a/matchmake-extension/join_matchmake_session_ex.go +++ b/matchmake-extension/join_matchmake_session_ex.go @@ -13,7 +13,7 @@ func (commonProtocol *CommonProtocol) joinMatchmakeSessionEx(err error, packet n return nil, nex.NewError(nex.ResultCodes.Core.InvalidArgument, "change_error") } - session, ok := common_globals.Sessions[gid.Value] + session, ok := common_globals.GetSession(gid.Value) if !ok { return nil, nex.NewError(nex.ResultCodes.RendezVous.SessionVoid, "change_error") } diff --git a/matchmake-extension/join_matchmake_session_with_param.go b/matchmake-extension/join_matchmake_session_with_param.go index 22cf55c..a1a90a1 100644 --- a/matchmake-extension/join_matchmake_session_with_param.go +++ b/matchmake-extension/join_matchmake_session_with_param.go @@ -13,7 +13,7 @@ func (commonProtocol *CommonProtocol) joinMatchmakeSessionWithParam(err error, p return nil, nex.NewError(nex.ResultCodes.Core.InvalidArgument, "change_error") } - session, ok := common_globals.Sessions[joinMatchmakeSessionParam.GID.Value] + session, ok := common_globals.GetSession(joinMatchmakeSessionParam.GID.Value) if !ok { return nil, nex.NewError(nex.ResultCodes.RendezVous.SessionVoid, "change_error") } diff --git a/matchmake-extension/modify_current_game_attribute.go b/matchmake-extension/modify_current_game_attribute.go index 8a12be3..fe79011 100644 --- a/matchmake-extension/modify_current_game_attribute.go +++ b/matchmake-extension/modify_current_game_attribute.go @@ -16,7 +16,7 @@ func (commonProtocol *CommonProtocol) modifyCurrentGameAttribute(err error, pack connection := packet.Sender().(*nex.PRUDPConnection) endpoint := connection.Endpoint().(*nex.PRUDPEndPoint) - session, ok := common_globals.Sessions[gid.Value] + session, ok := common_globals.GetSession(gid.Value) if !ok { return nil, nex.NewError(nex.ResultCodes.RendezVous.SessionVoid, "change_error") } diff --git a/matchmake-extension/open_participation.go b/matchmake-extension/open_participation.go index dde2d8a..5df7a9b 100644 --- a/matchmake-extension/open_participation.go +++ b/matchmake-extension/open_participation.go @@ -16,7 +16,7 @@ func (commonProtocol *CommonProtocol) openParticipation(err error, packet nex.Pa connection := packet.Sender().(*nex.PRUDPConnection) endpoint := connection.Endpoint().(*nex.PRUDPEndPoint) - session, ok := common_globals.Sessions[gid.Value] + session, ok := common_globals.GetSession(gid.Value) if !ok { return nil, nex.NewError(nex.ResultCodes.RendezVous.SessionVoid, "change_error") } diff --git a/matchmake-extension/update_application_buffer.go b/matchmake-extension/update_application_buffer.go index 325fc16..344a3f2 100644 --- a/matchmake-extension/update_application_buffer.go +++ b/matchmake-extension/update_application_buffer.go @@ -16,7 +16,7 @@ func (commonProtocol *CommonProtocol) updateApplicationBuffer(err error, packet connection := packet.Sender().(*nex.PRUDPConnection) endpoint := connection.Endpoint().(*nex.PRUDPEndPoint) - session, ok := common_globals.Sessions[gid.Value] + session, ok := common_globals.GetSession(gid.Value) if !ok { return nil, nex.NewError(nex.ResultCodes.RendezVous.SessionVoid, "change_error") } diff --git a/matchmake-extension/update_progress_score.go b/matchmake-extension/update_progress_score.go index 57a7773..9895bc4 100644 --- a/matchmake-extension/update_progress_score.go +++ b/matchmake-extension/update_progress_score.go @@ -13,8 +13,8 @@ func (commonProtocol *CommonProtocol) updateProgressScore(err error, packet nex. return nil, nex.NewError(nex.ResultCodes.Core.InvalidArgument, "change_error") } - session := common_globals.Sessions[gid.Value] - if session == nil { + session, ok := common_globals.GetSession(gid.Value) + if !ok { return nil, nex.NewError(nex.ResultCodes.RendezVous.SessionVoid, "change_error") }