From 795b6f09bef17e215ceaca595377e1ad5521f074 Mon Sep 17 00:00:00 2001 From: Nyo Date: Tue, 4 Oct 2016 23:43:02 +0200 Subject: [PATCH] .BANCHO. Implemented packet streams for multiplayer --- events/changeMatchSettingsEvent.py | 2 +- events/createMatchEvent.py | 3 +- events/joinMatchEvent.py | 39 +---- events/logoutEvent.py | 2 +- events/matchFramesEvent.py | 6 +- events/matchStartEvent.py | 25 +-- events/partMatchEvent.py | 2 +- objects/match.py | 265 +++++++++++++---------------- objects/matchList.py | 30 +--- objects/osuToken.py | 96 ++++++----- objects/stream.py | 3 +- objects/streamList.py | 1 - 12 files changed, 187 insertions(+), 287 deletions(-) diff --git a/events/changeMatchSettingsEvent.py b/events/changeMatchSettingsEvent.py index e497457..62b3d13 100644 --- a/events/changeMatchSettingsEvent.py +++ b/events/changeMatchSettingsEvent.py @@ -111,7 +111,7 @@ def handle(userToken, packetData): match.matchModMode = matchModModes.normal # Send updated settings - match.sendUpdate() + match.sendUpdates() # Console output log.info("MPROOM{}: Updated room settings".format(match.matchID)) diff --git a/events/createMatchEvent.py b/events/createMatchEvent.py index e245a24..3431d0c 100644 --- a/events/createMatchEvent.py +++ b/events/createMatchEvent.py @@ -2,7 +2,6 @@ from common.log import logUtils as log from constants import clientPackets from constants import exceptions from constants import serverPackets -from events import joinMatchEvent from objects import glob @@ -26,7 +25,7 @@ def handle(userToken, packetData): match = glob.matches.matches[matchID] # Join that match - joinMatchEvent.joinMatch(userToken, matchID, packetData["matchPassword"]) + userToken.joinMatch(matchID) # Give host to match creator match.setHost(userID) diff --git a/events/joinMatchEvent.py b/events/joinMatchEvent.py index c84db7d..9b76a4e 100644 --- a/events/joinMatchEvent.py +++ b/events/joinMatchEvent.py @@ -3,38 +3,26 @@ from common.log import logUtils as log from constants import clientPackets from constants import exceptions from constants import serverPackets -from helpers import chatHelper as chat from objects import glob def handle(userToken, packetData): # read packet data packetData = clientPackets.joinMatch(packetData) + matchID = packetData["matchID"] + password = packetData["password"] # Get match from ID - joinMatch(userToken, packetData["matchID"], packetData["password"]) - -def joinMatch(userToken, matchID, password, isPasswordHashed = False): try: - # Stop spectating - userToken.stopSpectating() - - # Leave other matches - if userToken.matchID > -1 and userToken.matchID != matchID: - userToken.partMatch() - - # Get usertoken data - userID = userToken.userID - # Make sure the match exists if matchID not in glob.matches.matches: - raise exceptions.matchNotFoundException + return # Match exists, get object match = glob.matches.matches[matchID] # Hash password if needed - if isPasswordHashed == False and password != "": + if password != "": password = generalUtils.stringMd5(password) # Check password @@ -44,24 +32,7 @@ def joinMatch(userToken, matchID, password, isPasswordHashed = False): raise exceptions.matchWrongPasswordException # Password is correct, join match - result = match.userJoin(userID) - - # Check if we've joined the match successfully - if not result: - raise exceptions.matchJoinErrorException - - # Match joined, set matchID for usertoken userToken.joinMatch(matchID) - - # Send packets - userToken.enqueue(serverPackets.matchJoinSuccess(matchID)) - chat.joinChannel(token=userToken, channel="#multi_{}".format(matchID)) - except exceptions.matchNotFoundException: - userToken.enqueue(serverPackets.matchJoinFail()) - log.warning("{} has tried to join a mp room, but it doesn't exist".format(userToken.username)) except exceptions.matchWrongPasswordException: userToken.enqueue(serverPackets.matchJoinFail()) - log.warning("{} has tried to join a mp room, but he typed the wrong password".format(userToken.username)) - except exceptions.matchJoinErrorException: - userToken.enqueue(serverPackets.matchJoinFail()) - log.warning("{} has tried to join a mp room, but an error has occured".format(userToken.username)) + log.warning("{} has tried to join a mp room, but he typed the wrong password".format(userToken.username)) \ No newline at end of file diff --git a/events/logoutEvent.py b/events/logoutEvent.py index a7d0148..030e4c3 100644 --- a/events/logoutEvent.py +++ b/events/logoutEvent.py @@ -21,7 +21,7 @@ def handle(userToken, _=None): userToken.stopSpectating() # Part matches - userToken.partMatch() + userToken.leaveMatch() # Part all joined channels for i in userToken.joinedChannels: diff --git a/events/matchFramesEvent.py b/events/matchFramesEvent.py index 68179c0..8467c63 100644 --- a/events/matchFramesEvent.py +++ b/events/matchFramesEvent.py @@ -24,8 +24,4 @@ def handle(userToken, packetData): slotID = match.getUserSlotID(userID) # Enqueue frames to who's playing - for i in range(0,16): - if match.slots[i].userID > -1 and match.slots[i].status == slotStatuses.playing: - token = glob.tokens.getTokenFromUserID(match.slots[i].userID) - if token is not None: - token.enqueue(serverPackets.matchFrames(slotID, packetData)) + glob.streams.broadcast(match.playingStreamName, serverPackets.matchFrames(slotID, packetData)) \ No newline at end of file diff --git a/events/matchStartEvent.py b/events/matchStartEvent.py index 777b12f..3ba7282 100644 --- a/events/matchStartEvent.py +++ b/events/matchStartEvent.py @@ -22,27 +22,4 @@ def handle(userToken, _): if userToken.userID != match.hostUserID: return - # Make sure we have enough players - if match.countUsers() < 2 or match.checkTeams() == False: - return - - # Change inProgress value - match.inProgress = True - - # Set playing to ready players and set load, skip and complete to False - for i in range(0,16): - if (match.slots[i].status & slotStatuses.ready) > 0: - match.slots[i].status = slotStatuses.playing - match.slots[i].loaded = False - match.slots[i].skip = False - match.slots[i].complete = False - - # Send match start packet - for i in range(0,16): - if (match.slots[i].status & slotStatuses.playing) > 0 and match.slots[i].userID != -1: - token = glob.tokens.getTokenFromUserID(match.slots[i].userID) - if token is not None: - token.enqueue(serverPackets.matchStart(matchID)) - - # Send updates - match.sendUpdate() + match.start() diff --git a/events/partMatchEvent.py b/events/partMatchEvent.py index 943a410..88bf90b 100644 --- a/events/partMatchEvent.py +++ b/events/partMatchEvent.py @@ -1,2 +1,2 @@ def handle(userToken, _=None): - userToken.partMatch() \ No newline at end of file + userToken.leaveMatch() \ No newline at end of file diff --git a/objects/match.py b/objects/match.py index 72ee488..3fdbb58 100644 --- a/objects/match.py +++ b/objects/match.py @@ -1,5 +1,5 @@ -# TODO: Enqueue all import copy +import dill from common import generalUtils from common.constants import gameModes @@ -20,6 +20,7 @@ class slot: self.status = slotStatuses.free self.team = 0 self.userID = -1 + self.user = None self.mods = 0 self.loaded = False self.skip = False @@ -27,22 +28,6 @@ class slot: class match: """Multiplayer match object""" - matchID = 0 - inProgress = False - mods = 0 - matchName = "" - matchPassword = "" - beatmapName = "" - beatmapID = 0 - beatmapMD5 = "" - slots = [] - hostUserID = 0 - gameMode = gameModes.STD - matchScoringType = matchScoringTypes.score - matchTeamType = matchTeamTypes.headToHead - matchModMode = matchModModes.normal - seed = 0 - def __init__(self, matchID, matchName, matchPassword, beatmapID, beatmapName, beatmapMD5, gameMode, hostUserID): """ Create a new match object @@ -57,6 +42,8 @@ class match: hostUserID -- user id of the host """ self.matchID = matchID + self.streamName = "multi/{}".format(self.matchID) + self.playingStreamName = "{}/playing".format(self.streamName) self.inProgress = False self.mods = 0 self.matchName = matchName @@ -69,7 +56,7 @@ class match: self.beatmapMD5 = beatmapMD5 self.hostUserID = hostUserID self.gameMode = gameMode - self.matchScoringTypes = matchScoringTypes.score # default values + self.matchScoringType = matchScoringTypes.score # default values self.matchTeamType = matchTeamTypes.headToHead # default value self.matchModMode = matchModModes.normal # default value self.seed = 0 @@ -79,6 +66,10 @@ class match: for _ in range(0,16): self.slots.append(slot()) + # Create streams + glob.streams.add(self.streamName) + glob.streams.add(self.playingStreamName) + # Create #multiplayer channel glob.channels.addTempChannel("#multi_{}".format(self.matchID)) @@ -109,9 +100,8 @@ class match: # Slot user ID. Write only if slot is occupied for i in range(0,16): - uid = self.slots[i].userID - if uid > -1: - struct.append([uid, dataTypes.UINT32]) + if self.slots[i].user is not None: + struct.append([self.slots[i].user.userID, dataTypes.UINT32]) # Other match data struct.extend([ @@ -138,50 +128,37 @@ class match: newHost -- new host userID """ + slotID = self.getUserSlotID(newHost) + if slotID is None: + return + token = self.slots[slotID].user self.hostUserID = newHost + token.enqueue(serverPackets.matchTransferHost()) + self.sendUpdates() + log.info("MPROOM{}: {} is now the host".format(self.matchID, token.username)) - # Send host packet to new host - token = glob.tokens.getTokenFromUserID(newHost) - if token is not None: - token.enqueue(serverPackets.matchTransferHost()) + def setSlot(self, slotID, status = None, team = None, user = -1, mods = None, loaded = None, skip = None, complete = None): + #self.setSlot(i, slotStatuses.notReady, 0, user, 0) + if status is not None: + self.slots[slotID].status = status - log.info("MPROOM{}: {} is now the host".format(self.matchID, newHost)) + if team is not None: + self.slots[slotID].team = team - def setSlot(self, slotID, slotStatus = None, slotTeam = None, slotUserID = None, slotMods = None, slotLoaded = None, slotSkip = None, slotComplete = None): - """ - Set a slot to a specific userID and status + if user is not -1: + self.slots[slotID].user = user - slotID -- id of that slot (0-15) - slotStatus -- see slotStatuses.py - slotTeam -- team id - slotUserID -- user ID of user in that slot - slotMods -- mods enabled in that slot. 0 if not free mod. - slotLoaded -- loaded status True/False - slotSkip -- skip status True/False - slotComplete -- completed status True/False + if mods is not -1: + self.slots[slotID].mods = mods - If Null is passed, that value won't be edited - """ - if slotStatus is not None: - self.slots[slotID].status = slotStatus + if loaded is not None: + self.slots[slotID].loaded = loaded - if slotTeam is not None: - self.slots[slotID].team = slotTeam + if skip is not None: + self.slots[slotID].skip = skip - if slotUserID is not None: - self.slots[slotID].userID = slotUserID - - if slotMods is not None: - self.slots[slotID].mods = slotMods - - if slotLoaded is not None: - self.slots[slotID].loaded = slotLoaded - - if slotSkip is not None: - self.slots[slotID].skip = slotSkip - - if slotComplete is not None: - self.slots[slotID].complete = slotComplete + if complete is not None: + self.slots[slotID].complete = complete def setSlotMods(self, slotID, mods): """ @@ -191,8 +168,8 @@ class match: mods -- new mods """ # Set new slot data and send update - self.setSlot(slotID, None, None, None, mods) - self.sendUpdate() + self.setSlot(slotID, mods=mods) + self.sendUpdates() log.info("MPROOM{}: Slot{} mods changed to {}".format(self.matchID, slotID, mods)) def toggleSlotReady(self, slotID): @@ -208,8 +185,8 @@ class match: newStatus = slotStatuses.notReady else: newStatus = slotStatuses.ready - self.setSlot(slotID, newStatus, None, None, None) - self.sendUpdate() + self.setSlot(slotID, newStatus) + self.sendUpdates() log.info("MPROOM{}: Slot{} changed ready status to {}".format(self.matchID, slotID, self.slots[slotID].status)) def toggleSlotLock(self, slotID): @@ -219,26 +196,21 @@ class match: slotID -- slot number """ - # Get token of user in that slot (if there's someone) - if self.slots[slotID].userID > -1: - token = glob.tokens.getTokenFromUserID(self.slots[slotID].userID) - else: - token = None - # Check if slot is already locked if self.slots[slotID].status == slotStatuses.locked: newStatus = slotStatuses.free else: newStatus = slotStatuses.locked + # Send updated settings to kicked user, so he returns to lobby + if self.slots[slotID].user is not None: + self.slots[slotID].user.enqueue(serverPackets.updateMatch(self.matchID)) + # Set new slot status self.setSlot(slotID, newStatus, 0, -1, 0) - if token is not None: - # Send updated settings to kicked user, so he returns to lobby - token.enqueue(serverPackets.updateMatch(self.matchID)) # Send updates to everyone else - self.sendUpdate() + self.sendUpdates() log.info("MPROOM{}: Slot{} {}".format(self.matchID, slotID, "locked" if newStatus == slotStatuses.locked else "unlocked")) def playerLoaded(self, userID): @@ -269,12 +241,7 @@ class match: def allPlayersLoaded(self): """Send allPlayersLoaded packet to every playing usr in match""" - for i in range(0,16): - if self.slots[i].userID > -1 and self.slots[i].status == slotStatuses.playing: - token = glob.tokens.getTokenFromUserID(self.slots[i].userID) - if token is not None: - token.enqueue(serverPackets.allPlayersLoaded()) - + glob.streams.broadcast(self.playingStreamName, serverPackets.allPlayersLoaded()) log.info("MPROOM{}: All players loaded! Match starting...".format(self.matchID)) def playerSkip(self, userID): @@ -292,12 +259,7 @@ class match: log.info("MPROOM{}: User {} skipped".format(self.matchID, userID)) # Send skip packet to every playing user - for i in range(0,16): - uid = self.slots[i].userID - if (self.slots[i].status & slotStatuses.playing > 0) and uid > -1: - token = glob.tokens.getTokenFromUserID(uid) - if token is not None: - token.enqueue(serverPackets.playerSkipped(uid)) + glob.streams.broadcast(self.playingStreamName, serverPackets.playerSkipped(self.slots[slotID].user.userID)) # Check all skipped total = 0 @@ -313,12 +275,7 @@ class match: def allPlayersSkipped(self): """Send allPlayersSkipped packet to every playing usr in match""" - for i in range(0,16): - if self.slots[i].userID > -1 and self.slots[i].status == slotStatuses.playing: - token = glob.tokens.getTokenFromUserID(self.slots[i].userID) - if token is not None: - token.enqueue(serverPackets.allPlayersSkipped()) - + glob.streams.broadcast(self.playingStreamName, serverPackets.allPlayersSkipped()) log.info("MPROOM{}: All players have skipped!".format(self.matchID)) def playerCompleted(self, userID): @@ -330,7 +287,7 @@ class match: slotID = self.getUserSlotID(userID) if slotID is None: return - self.setSlot(slotID, None, None, None, None, None, None, True) + self.setSlot(slotID, complete=True) # Console output log.info("MPROOM{}: User {} has completed his play".format(self.matchID, userID)) @@ -355,21 +312,20 @@ class match: # Reset slots for i in range(0,16): - if self.slots[i].userID > -1 and self.slots[i].status == slotStatuses.playing: + if self.slots[i].user is not None and self.slots[i].status == slotStatuses.playing: self.slots[i].status = slotStatuses.notReady self.slots[i].loaded = False self.slots[i].skip = False self.slots[i].complete = False # Send match update - self.sendUpdate() + self.sendUpdates() # Send match complete - for i in range(0,16): - if self.slots[i].userID > -1: - token = glob.tokens.getTokenFromUserID(self.slots[i].userID) - if token is not None: - token.enqueue(serverPackets.matchComplete()) + glob.streams.broadcast(self.streamName, serverPackets.matchComplete()) + + # Destroy playing stream + glob.streams.remove(self.playingStreamName) # Console output log.info("MPROOM{}: Match completed".format(self.matchID)) @@ -381,11 +337,11 @@ class match: return -- slot id if found, None if user is not in room """ for i in range(0,16): - if self.slots[i].userID == userID: + if self.slots[i].user is not None and self.slots[i].user.userID == userID: return i return None - def userJoin(self, userID): + def userJoin(self, user): """ Add someone to users in match @@ -395,39 +351,38 @@ class match: # Make sure we're not in this match for i in range(0,16): - if self.slots[i].userID == userID: + if self.slots[i].user == user: # Set bugged slot to free - self.setSlot(i, slotStatuses.free, 0, -1, 0) + self.setSlot(i, slotStatuses.free, 0, None, 0) # Find first free slot for i in range(0,16): if self.slots[i].status == slotStatuses.free: # Occupy slot - self.setSlot(i, slotStatuses.notReady, 0, userID, 0) + self.setSlot(i, slotStatuses.notReady, 0, user, 0) # Send updated match data - self.sendUpdate() + self.sendUpdates() # Console output - log.info("MPROOM{}: {} joined the room".format(self.matchID, userID)) - + log.info("MPROOM{}: {} joined the room".format(self.matchID, user.username)) return True return False - def userLeft(self, userID): + def userLeft(self, user): """ Remove someone from users in match userID -- user if of the user """ # Make sure the user is in room - slotID = self.getUserSlotID(userID) + slotID = self.getUserSlotID(user.userID) if slotID is None: return # Set that slot to free - self.setSlot(slotID, slotStatuses.free, 0, -1, 0) + self.setSlot(slotID, slotStatuses.free, 0, None, 0) # Check if everyone left if self.countUsers() == 0: @@ -437,19 +392,18 @@ class match: return # Check if host left - if userID == self.hostUserID: + if user.userID == self.hostUserID: # Give host to someone else for i in range(0,16): - uid = self.slots[i].userID - if uid > -1: - self.setHost(uid) + if self.slots[i].user is not None: + self.setHost(self.slots[i].user.userID) break # Send updated match data - self.sendUpdate() + self.sendUpdates() # Console output - log.info("MPROOM{}: {} left the room".format(self.matchID, userID)) + log.info("MPROOM{}: {} left the room".format(self.matchID, user.username)) def userChangeSlot(self, userID, newSlotID): """ @@ -464,20 +418,21 @@ class match: return # Make sure there is no one inside new slot - if self.slots[newSlotID].userID > -1 and self.slots[newSlotID].status != slotStatuses.free: + if self.slots[newSlotID].user is not None and self.slots[newSlotID].status != slotStatuses.free: return # Get old slot data - oldData = copy.deepcopy(self.slots[oldSlotID]) + oldData = dill.copy(self.slots[oldSlotID]) + #oldData = copy.deepcopy(self.slots[oldSlotID]) # Free old slot - self.setSlot(oldSlotID, slotStatuses.free, 0, -1, 0) + self.setSlot(oldSlotID, slotStatuses.free, 0, None, 0) # Occupy new slot - self.setSlot(newSlotID, oldData.status, oldData.team, oldData.userID, oldData.mods) + self.setSlot(newSlotID, oldData.status, oldData.team, oldData.user, oldData.mods) # Send updated match data - self.sendUpdate() + self.sendUpdates() # Console output log.info("MPROOM{}: {} moved to slot {}".format(self.matchID, userID, newSlotID)) @@ -494,14 +449,10 @@ class match: self.matchPassword = "" # Send password change to every user in match - for i in range(0,16): - if self.slots[i].userID > -1: - token = glob.tokens.getTokenFromUserID(self.slots[i].userID) - if token is not None: - token.enqueue(serverPackets.changeMatchPassword(self.matchPassword)) + glob.streams.broadcast(self.streamName, serverPackets.changeMatchPassword(self.matchPassword)) # Send new match settings too - self.sendUpdate() + self.sendUpdates() # Console output log.info("MPROOM{}: Password changed to {}".format(self.matchID, self.matchPassword)) @@ -514,7 +465,7 @@ class match: """ # Set new mods and send update self.mods = mods - self.sendUpdate() + self.sendUpdates() log.info("MPROOM{}: Mods changed to {}".format(self.matchID, self.mods)) def userHasBeatmap(self, userID, has = True): @@ -533,7 +484,7 @@ class match: self.setSlot(slotID, slotStatuses.noMap if not has else slotStatuses.notReady) # Send updates - self.sendUpdate() + self.sendUpdates() def transferHost(self, slotID): """ @@ -542,15 +493,14 @@ class match: slotID -- ID of slot """ # Make sure there is someone in that slot - uid = self.slots[slotID].userID - if uid == -1: + if self.slots[slotID].user is None: return # Transfer host - self.setHost(uid) + self.setHost(self.slots[slotID].user.userID) # Send updates - self.sendUpdate() + self.sendUpdates() def playerFailed(self, userID): """ @@ -564,12 +514,7 @@ class match: return # Send packet to everyone - for i in range(0,16): - uid = self.slots[i].userID - if uid > -1: - token = glob.tokens.getTokenFromUserID(uid) - if token is not None: - token.enqueue(serverPackets.playerFailed(slotID)) + glob.streams.broadcast(self.playingStreamName, serverPackets.playerFailed(slotID)) # Console output log.info("MPROOM{}: {} has failed!".format(self.matchID, userID)) @@ -604,7 +549,7 @@ class match: """ c = 0 for i in range(0,16): - if self.slots[i].userID > -1: + if self.slots[i].user is not None: c+=1 return c @@ -622,17 +567,10 @@ class match: # Update slot and send update newTeam = matchTeams.blue if self.slots[slotID].team == matchTeams.red else matchTeams.red self.setSlot(slotID, None, newTeam) - self.sendUpdate() + self.sendUpdates() - def sendUpdate(self): - # Send to users in room - for i in range(0,16): - if self.slots[i].userID > -1: - token = glob.tokens.getTokenFromUserID(self.slots[i].userID) - if token is not None: - token.enqueue(serverPackets.updateMatch(self.matchID)) - - # Send to users in lobby + def sendUpdates(self): + glob.streams.broadcast(self.streamName, serverPackets.updateMatch(self.matchID)) glob.streams.broadcast("lobby", serverPackets.updateMatch(self.matchID)) def checkTeams(self): @@ -641,14 +579,14 @@ class match: return -- True if valid, False if invalid """ - if match.matchTeamType != matchTeamTypes.teamVs or matchTeamTypes != matchTeamTypes.tagTeamVs: + if self.matchTeamType != matchTeamTypes.teamVs or self.matchTeamType != matchTeamTypes.tagTeamVs: # Teams are always valid if we have no teams return True # We have teams, check if they are valid firstTeam = -1 for i in range(0,16): - if self.slots[i].userID > -1 and (self.slots[i].status&slotStatuses.noMap) == 0: + if self.slots[i].user is not None and (self.slots[i].status&slotStatuses.noMap) == 0: if firstTeam == -1: firstTeam = self.slots[i].team elif firstTeam != self.slots[i].team: @@ -657,3 +595,30 @@ class match: log.warning("MPROOM{}: Invalid teams!".format(self.matchID)) return False + + def start(self): + # Make sure we have enough players + if self.countUsers() < 2 or not self.checkTeams(): + return + + # Create playing channel + glob.streams.add(self.playingStreamName) + + # Change inProgress value + match.inProgress = True + + # Set playing to ready players and set load, skip and complete to False + # Make clients join playing stream + for i in range(0, 16): + if (self.slots[i].status & slotStatuses.ready) > 0: + self.slots[i].status = slotStatuses.playing + self.slots[i].loaded = False + self.slots[i].skip = False + self.slots[i].complete = False + self.slots[i].user.joinStream(self.playingStreamName) + + # Send match start packet + glob.streams.broadcast(self.playingStreamName, serverPackets.matchStart(self.matchID)) + + # Send updates + self.sendUpdates() \ No newline at end of file diff --git a/objects/matchList.py b/objects/matchList.py index 80040a7..953253d 100644 --- a/objects/matchList.py +++ b/objects/matchList.py @@ -21,34 +21,12 @@ class matchList: hostUserID -- user id of who created the match return -- match ID """ - # Add a new match to matches list + # Add a new match to matches list and create its stream matchID = self.lastID self.lastID+=1 self.matches[matchID] = match.match(matchID, matchName, matchPassword, beatmapID, beatmapName, beatmapMD5, gameMode, hostUserID) return matchID - '''def lobbyUserJoin(self, userID): - """ - Add userID to users in lobby - - userID -- user who joined mp lobby - """ - # Make sure the user is not already in mp lobby - if userID not in self.usersInLobby: - # We don't need to join #lobby, client will automatically send a packet for it - self.usersInLobby.append(userID) - - def lobbyUserPart(self, userID): - """ - Remove userID from users in lobby - - userID -- user who left mp lobby - """ - # Make sure the user is in mp lobby - if userID in self.usersInLobby: - # Part lobby and #lobby channel - self.usersInLobby.remove(userID)''' - def disposeMatch(self, matchID): """ Destroy match object with id = matchID @@ -59,8 +37,10 @@ class matchList: if matchID not in self.matches: return - # Remove match object - self.matches.pop(matchID) + # Remove match object and stream + match = self.matches.pop(matchID) + glob.streams.remove(match.streamName) + glob.streams.remove(match.playingStreamName) # Send match dispose packet to everyone in lobby glob.streams.broadcast("lobby", serverPackets.disposeMatch(matchID)) \ No newline at end of file diff --git a/objects/osuToken.py b/objects/osuToken.py index 031927b..752b5d6 100644 --- a/objects/osuToken.py +++ b/objects/osuToken.py @@ -216,47 +216,6 @@ class token: # Set our spectating user to 0 self.spectating = None - def partMatch(self): - # Make sure we are in a match - if self.matchID == -1: - return - - # Part #multiplayer channel - chat.partChannel(token=self, channel="#multi_{}".format(self.matchID), kick=True) - - # Make sure the match exists - if self.matchID not in glob.matches.matches: - return - - # The match exists, get object - match = glob.matches.matches[self.matchID] - - # Set slot to free - match.userLeft(self.userID) - - # Set usertoken match to -1 - self.matchID = -1 - - '''def addSpectator(self, user): - """ - Add userID to our spectators - - user -- user object - """ - # Add userID to spectators if not already in - if user not in self.spectators: - self.spectators.append(user) - - def removeSpectator(self, userID): - """ - Remove userID from our spectators - - userID -- old spectator userID - """ - # Remove spectator - if userID in self.spectators: - self.spectators.remove(userID)''' - def setCountry(self, countryID): """ Set country to countryID @@ -281,13 +240,66 @@ class token: """Set a new away message""" self.awayMessage = __awayMessage + def joinMatch(self, matchID): """ - Set match to matchID + Set match to matchID, join match stream and channel matchID -- new match ID """ + # Make sure the match exists + if matchID not in glob.matches.matches: + return + + # Match exists, get object + match = glob.matches.matches[matchID] + + # Stop spectating + self.stopSpectating() + + # Leave other matches + if self.matchID > -1 and self.matchID != matchID: + self.leaveMatch() + + # Try to join match + joined = match.userJoin(self) + if not joined: + self.enqueue(serverPackets.matchJoinFail()) + return + + # Set matchID, join stream, channel and send packet self.matchID = matchID + self.joinStream(match.streamName) + chat.joinChannel(token=self, channel="#multi_{}".format(self.matchID)) + self.enqueue(serverPackets.matchJoinSuccess(matchID)) + + def leaveMatch(self): + """ + Leave joined match, match stream and match channel + + :return: + """ + # Make sure we are in a match + if self.matchID == -1: + return + + # Part #multiplayer channel and streams (/ and /playing) + chat.partChannel(token=self, channel="#multi_{}".format(self.matchID), kick=True) + self.leaveStream("multi/{}".format(self.matchID)) + self.leaveStream("multi/{}/playing".format(self.matchID)) # optional + + # Make sure the match exists + if self.matchID not in glob.matches.matches: + return + + # The match exists, get object + match = glob.matches.matches[self.matchID] + + # Set slot to free + match.userLeft(self) + + # Set usertoken match to -1 + self.matchID = -1 def kick(self, message="You have been kicked from the server. Please login again."): """ diff --git a/objects/stream.py b/objects/stream.py index 896027d..1abee3f 100644 --- a/objects/stream.py +++ b/objects/stream.py @@ -40,4 +40,5 @@ class stream: :return: """ for i in self.clients: - i.enqueue(data) \ No newline at end of file + if i is not None: + i.enqueue(data) \ No newline at end of file diff --git a/objects/streamList.py b/objects/streamList.py index 3d970d2..ec85d49 100644 --- a/objects/streamList.py +++ b/objects/streamList.py @@ -13,7 +13,6 @@ class streamList: """ if name not in self.streams: self.streams[name] = stream.stream(name) - print(str(self.streams)) def remove(self, name): """