.BANCHO. Implemented packet streams for multiplayer
This commit is contained in:
parent
afbd8e7e8c
commit
795b6f09be
|
@ -111,7 +111,7 @@ def handle(userToken, packetData):
|
||||||
match.matchModMode = matchModModes.normal
|
match.matchModMode = matchModModes.normal
|
||||||
|
|
||||||
# Send updated settings
|
# Send updated settings
|
||||||
match.sendUpdate()
|
match.sendUpdates()
|
||||||
|
|
||||||
# Console output
|
# Console output
|
||||||
log.info("MPROOM{}: Updated room settings".format(match.matchID))
|
log.info("MPROOM{}: Updated room settings".format(match.matchID))
|
||||||
|
|
|
@ -2,7 +2,6 @@ from common.log import logUtils as log
|
||||||
from constants import clientPackets
|
from constants import clientPackets
|
||||||
from constants import exceptions
|
from constants import exceptions
|
||||||
from constants import serverPackets
|
from constants import serverPackets
|
||||||
from events import joinMatchEvent
|
|
||||||
from objects import glob
|
from objects import glob
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,7 +25,7 @@ def handle(userToken, packetData):
|
||||||
match = glob.matches.matches[matchID]
|
match = glob.matches.matches[matchID]
|
||||||
|
|
||||||
# Join that match
|
# Join that match
|
||||||
joinMatchEvent.joinMatch(userToken, matchID, packetData["matchPassword"])
|
userToken.joinMatch(matchID)
|
||||||
|
|
||||||
# Give host to match creator
|
# Give host to match creator
|
||||||
match.setHost(userID)
|
match.setHost(userID)
|
||||||
|
|
|
@ -3,38 +3,26 @@ from common.log import logUtils as log
|
||||||
from constants import clientPackets
|
from constants import clientPackets
|
||||||
from constants import exceptions
|
from constants import exceptions
|
||||||
from constants import serverPackets
|
from constants import serverPackets
|
||||||
from helpers import chatHelper as chat
|
|
||||||
from objects import glob
|
from objects import glob
|
||||||
|
|
||||||
|
|
||||||
def handle(userToken, packetData):
|
def handle(userToken, packetData):
|
||||||
# read packet data
|
# read packet data
|
||||||
packetData = clientPackets.joinMatch(packetData)
|
packetData = clientPackets.joinMatch(packetData)
|
||||||
|
matchID = packetData["matchID"]
|
||||||
|
password = packetData["password"]
|
||||||
|
|
||||||
# Get match from ID
|
# Get match from ID
|
||||||
joinMatch(userToken, packetData["matchID"], packetData["password"])
|
|
||||||
|
|
||||||
def joinMatch(userToken, matchID, password, isPasswordHashed = False):
|
|
||||||
try:
|
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
|
# Make sure the match exists
|
||||||
if matchID not in glob.matches.matches:
|
if matchID not in glob.matches.matches:
|
||||||
raise exceptions.matchNotFoundException
|
return
|
||||||
|
|
||||||
# Match exists, get object
|
# Match exists, get object
|
||||||
match = glob.matches.matches[matchID]
|
match = glob.matches.matches[matchID]
|
||||||
|
|
||||||
# Hash password if needed
|
# Hash password if needed
|
||||||
if isPasswordHashed == False and password != "":
|
if password != "":
|
||||||
password = generalUtils.stringMd5(password)
|
password = generalUtils.stringMd5(password)
|
||||||
|
|
||||||
# Check password
|
# Check password
|
||||||
|
@ -44,24 +32,7 @@ def joinMatch(userToken, matchID, password, isPasswordHashed = False):
|
||||||
raise exceptions.matchWrongPasswordException
|
raise exceptions.matchWrongPasswordException
|
||||||
|
|
||||||
# Password is correct, join match
|
# 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)
|
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:
|
except exceptions.matchWrongPasswordException:
|
||||||
userToken.enqueue(serverPackets.matchJoinFail())
|
userToken.enqueue(serverPackets.matchJoinFail())
|
||||||
log.warning("{} has tried to join a mp room, but he typed the wrong password".format(userToken.username))
|
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))
|
|
|
@ -21,7 +21,7 @@ def handle(userToken, _=None):
|
||||||
userToken.stopSpectating()
|
userToken.stopSpectating()
|
||||||
|
|
||||||
# Part matches
|
# Part matches
|
||||||
userToken.partMatch()
|
userToken.leaveMatch()
|
||||||
|
|
||||||
# Part all joined channels
|
# Part all joined channels
|
||||||
for i in userToken.joinedChannels:
|
for i in userToken.joinedChannels:
|
||||||
|
|
|
@ -24,8 +24,4 @@ def handle(userToken, packetData):
|
||||||
slotID = match.getUserSlotID(userID)
|
slotID = match.getUserSlotID(userID)
|
||||||
|
|
||||||
# Enqueue frames to who's playing
|
# Enqueue frames to who's playing
|
||||||
for i in range(0,16):
|
glob.streams.broadcast(match.playingStreamName, serverPackets.matchFrames(slotID, packetData))
|
||||||
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))
|
|
|
@ -22,27 +22,4 @@ def handle(userToken, _):
|
||||||
if userToken.userID != match.hostUserID:
|
if userToken.userID != match.hostUserID:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Make sure we have enough players
|
match.start()
|
||||||
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()
|
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
def handle(userToken, _=None):
|
def handle(userToken, _=None):
|
||||||
userToken.partMatch()
|
userToken.leaveMatch()
|
265
objects/match.py
265
objects/match.py
|
@ -1,5 +1,5 @@
|
||||||
# TODO: Enqueue all
|
|
||||||
import copy
|
import copy
|
||||||
|
import dill
|
||||||
|
|
||||||
from common import generalUtils
|
from common import generalUtils
|
||||||
from common.constants import gameModes
|
from common.constants import gameModes
|
||||||
|
@ -20,6 +20,7 @@ class slot:
|
||||||
self.status = slotStatuses.free
|
self.status = slotStatuses.free
|
||||||
self.team = 0
|
self.team = 0
|
||||||
self.userID = -1
|
self.userID = -1
|
||||||
|
self.user = None
|
||||||
self.mods = 0
|
self.mods = 0
|
||||||
self.loaded = False
|
self.loaded = False
|
||||||
self.skip = False
|
self.skip = False
|
||||||
|
@ -27,22 +28,6 @@ class slot:
|
||||||
|
|
||||||
class match:
|
class match:
|
||||||
"""Multiplayer match object"""
|
"""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):
|
def __init__(self, matchID, matchName, matchPassword, beatmapID, beatmapName, beatmapMD5, gameMode, hostUserID):
|
||||||
"""
|
"""
|
||||||
Create a new match object
|
Create a new match object
|
||||||
|
@ -57,6 +42,8 @@ class match:
|
||||||
hostUserID -- user id of the host
|
hostUserID -- user id of the host
|
||||||
"""
|
"""
|
||||||
self.matchID = matchID
|
self.matchID = matchID
|
||||||
|
self.streamName = "multi/{}".format(self.matchID)
|
||||||
|
self.playingStreamName = "{}/playing".format(self.streamName)
|
||||||
self.inProgress = False
|
self.inProgress = False
|
||||||
self.mods = 0
|
self.mods = 0
|
||||||
self.matchName = matchName
|
self.matchName = matchName
|
||||||
|
@ -69,7 +56,7 @@ class match:
|
||||||
self.beatmapMD5 = beatmapMD5
|
self.beatmapMD5 = beatmapMD5
|
||||||
self.hostUserID = hostUserID
|
self.hostUserID = hostUserID
|
||||||
self.gameMode = gameMode
|
self.gameMode = gameMode
|
||||||
self.matchScoringTypes = matchScoringTypes.score # default values
|
self.matchScoringType = matchScoringTypes.score # default values
|
||||||
self.matchTeamType = matchTeamTypes.headToHead # default value
|
self.matchTeamType = matchTeamTypes.headToHead # default value
|
||||||
self.matchModMode = matchModModes.normal # default value
|
self.matchModMode = matchModModes.normal # default value
|
||||||
self.seed = 0
|
self.seed = 0
|
||||||
|
@ -79,6 +66,10 @@ class match:
|
||||||
for _ in range(0,16):
|
for _ in range(0,16):
|
||||||
self.slots.append(slot())
|
self.slots.append(slot())
|
||||||
|
|
||||||
|
# Create streams
|
||||||
|
glob.streams.add(self.streamName)
|
||||||
|
glob.streams.add(self.playingStreamName)
|
||||||
|
|
||||||
# Create #multiplayer channel
|
# Create #multiplayer channel
|
||||||
glob.channels.addTempChannel("#multi_{}".format(self.matchID))
|
glob.channels.addTempChannel("#multi_{}".format(self.matchID))
|
||||||
|
|
||||||
|
@ -109,9 +100,8 @@ class match:
|
||||||
|
|
||||||
# Slot user ID. Write only if slot is occupied
|
# Slot user ID. Write only if slot is occupied
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
uid = self.slots[i].userID
|
if self.slots[i].user is not None:
|
||||||
if uid > -1:
|
struct.append([self.slots[i].user.userID, dataTypes.UINT32])
|
||||||
struct.append([uid, dataTypes.UINT32])
|
|
||||||
|
|
||||||
# Other match data
|
# Other match data
|
||||||
struct.extend([
|
struct.extend([
|
||||||
|
@ -138,50 +128,37 @@ class match:
|
||||||
|
|
||||||
newHost -- new host userID
|
newHost -- new host userID
|
||||||
"""
|
"""
|
||||||
|
slotID = self.getUserSlotID(newHost)
|
||||||
|
if slotID is None:
|
||||||
|
return
|
||||||
|
token = self.slots[slotID].user
|
||||||
self.hostUserID = newHost
|
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
|
def setSlot(self, slotID, status = None, team = None, user = -1, mods = None, loaded = None, skip = None, complete = None):
|
||||||
token = glob.tokens.getTokenFromUserID(newHost)
|
#self.setSlot(i, slotStatuses.notReady, 0, user, 0)
|
||||||
if token is not None:
|
if status is not None:
|
||||||
token.enqueue(serverPackets.matchTransferHost())
|
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):
|
if user is not -1:
|
||||||
"""
|
self.slots[slotID].user = user
|
||||||
Set a slot to a specific userID and status
|
|
||||||
|
|
||||||
slotID -- id of that slot (0-15)
|
if mods is not -1:
|
||||||
slotStatus -- see slotStatuses.py
|
self.slots[slotID].mods = mods
|
||||||
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 Null is passed, that value won't be edited
|
if loaded is not None:
|
||||||
"""
|
self.slots[slotID].loaded = loaded
|
||||||
if slotStatus is not None:
|
|
||||||
self.slots[slotID].status = slotStatus
|
|
||||||
|
|
||||||
if slotTeam is not None:
|
if skip is not None:
|
||||||
self.slots[slotID].team = slotTeam
|
self.slots[slotID].skip = skip
|
||||||
|
|
||||||
if slotUserID is not None:
|
if complete is not None:
|
||||||
self.slots[slotID].userID = slotUserID
|
self.slots[slotID].complete = complete
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
def setSlotMods(self, slotID, mods):
|
def setSlotMods(self, slotID, mods):
|
||||||
"""
|
"""
|
||||||
|
@ -191,8 +168,8 @@ class match:
|
||||||
mods -- new mods
|
mods -- new mods
|
||||||
"""
|
"""
|
||||||
# Set new slot data and send update
|
# Set new slot data and send update
|
||||||
self.setSlot(slotID, None, None, None, mods)
|
self.setSlot(slotID, mods=mods)
|
||||||
self.sendUpdate()
|
self.sendUpdates()
|
||||||
log.info("MPROOM{}: Slot{} mods changed to {}".format(self.matchID, slotID, mods))
|
log.info("MPROOM{}: Slot{} mods changed to {}".format(self.matchID, slotID, mods))
|
||||||
|
|
||||||
def toggleSlotReady(self, slotID):
|
def toggleSlotReady(self, slotID):
|
||||||
|
@ -208,8 +185,8 @@ class match:
|
||||||
newStatus = slotStatuses.notReady
|
newStatus = slotStatuses.notReady
|
||||||
else:
|
else:
|
||||||
newStatus = slotStatuses.ready
|
newStatus = slotStatuses.ready
|
||||||
self.setSlot(slotID, newStatus, None, None, None)
|
self.setSlot(slotID, newStatus)
|
||||||
self.sendUpdate()
|
self.sendUpdates()
|
||||||
log.info("MPROOM{}: Slot{} changed ready status to {}".format(self.matchID, slotID, self.slots[slotID].status))
|
log.info("MPROOM{}: Slot{} changed ready status to {}".format(self.matchID, slotID, self.slots[slotID].status))
|
||||||
|
|
||||||
def toggleSlotLock(self, slotID):
|
def toggleSlotLock(self, slotID):
|
||||||
|
@ -219,26 +196,21 @@ class match:
|
||||||
|
|
||||||
slotID -- slot number
|
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
|
# Check if slot is already locked
|
||||||
if self.slots[slotID].status == slotStatuses.locked:
|
if self.slots[slotID].status == slotStatuses.locked:
|
||||||
newStatus = slotStatuses.free
|
newStatus = slotStatuses.free
|
||||||
else:
|
else:
|
||||||
newStatus = slotStatuses.locked
|
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
|
# Set new slot status
|
||||||
self.setSlot(slotID, newStatus, 0, -1, 0)
|
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
|
# Send updates to everyone else
|
||||||
self.sendUpdate()
|
self.sendUpdates()
|
||||||
log.info("MPROOM{}: Slot{} {}".format(self.matchID, slotID, "locked" if newStatus == slotStatuses.locked else "unlocked"))
|
log.info("MPROOM{}: Slot{} {}".format(self.matchID, slotID, "locked" if newStatus == slotStatuses.locked else "unlocked"))
|
||||||
|
|
||||||
def playerLoaded(self, userID):
|
def playerLoaded(self, userID):
|
||||||
|
@ -269,12 +241,7 @@ class match:
|
||||||
|
|
||||||
def allPlayersLoaded(self):
|
def allPlayersLoaded(self):
|
||||||
"""Send allPlayersLoaded packet to every playing usr in match"""
|
"""Send allPlayersLoaded packet to every playing usr in match"""
|
||||||
for i in range(0,16):
|
glob.streams.broadcast(self.playingStreamName, serverPackets.allPlayersLoaded())
|
||||||
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())
|
|
||||||
|
|
||||||
log.info("MPROOM{}: All players loaded! Match starting...".format(self.matchID))
|
log.info("MPROOM{}: All players loaded! Match starting...".format(self.matchID))
|
||||||
|
|
||||||
def playerSkip(self, userID):
|
def playerSkip(self, userID):
|
||||||
|
@ -292,12 +259,7 @@ class match:
|
||||||
log.info("MPROOM{}: User {} skipped".format(self.matchID, userID))
|
log.info("MPROOM{}: User {} skipped".format(self.matchID, userID))
|
||||||
|
|
||||||
# Send skip packet to every playing user
|
# Send skip packet to every playing user
|
||||||
for i in range(0,16):
|
glob.streams.broadcast(self.playingStreamName, serverPackets.playerSkipped(self.slots[slotID].user.userID))
|
||||||
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))
|
|
||||||
|
|
||||||
# Check all skipped
|
# Check all skipped
|
||||||
total = 0
|
total = 0
|
||||||
|
@ -313,12 +275,7 @@ class match:
|
||||||
|
|
||||||
def allPlayersSkipped(self):
|
def allPlayersSkipped(self):
|
||||||
"""Send allPlayersSkipped packet to every playing usr in match"""
|
"""Send allPlayersSkipped packet to every playing usr in match"""
|
||||||
for i in range(0,16):
|
glob.streams.broadcast(self.playingStreamName, serverPackets.allPlayersSkipped())
|
||||||
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())
|
|
||||||
|
|
||||||
log.info("MPROOM{}: All players have skipped!".format(self.matchID))
|
log.info("MPROOM{}: All players have skipped!".format(self.matchID))
|
||||||
|
|
||||||
def playerCompleted(self, userID):
|
def playerCompleted(self, userID):
|
||||||
|
@ -330,7 +287,7 @@ class match:
|
||||||
slotID = self.getUserSlotID(userID)
|
slotID = self.getUserSlotID(userID)
|
||||||
if slotID is None:
|
if slotID is None:
|
||||||
return
|
return
|
||||||
self.setSlot(slotID, None, None, None, None, None, None, True)
|
self.setSlot(slotID, complete=True)
|
||||||
|
|
||||||
# Console output
|
# Console output
|
||||||
log.info("MPROOM{}: User {} has completed his play".format(self.matchID, userID))
|
log.info("MPROOM{}: User {} has completed his play".format(self.matchID, userID))
|
||||||
|
@ -355,21 +312,20 @@ class match:
|
||||||
|
|
||||||
# Reset slots
|
# Reset slots
|
||||||
for i in range(0,16):
|
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].status = slotStatuses.notReady
|
||||||
self.slots[i].loaded = False
|
self.slots[i].loaded = False
|
||||||
self.slots[i].skip = False
|
self.slots[i].skip = False
|
||||||
self.slots[i].complete = False
|
self.slots[i].complete = False
|
||||||
|
|
||||||
# Send match update
|
# Send match update
|
||||||
self.sendUpdate()
|
self.sendUpdates()
|
||||||
|
|
||||||
# Send match complete
|
# Send match complete
|
||||||
for i in range(0,16):
|
glob.streams.broadcast(self.streamName, serverPackets.matchComplete())
|
||||||
if self.slots[i].userID > -1:
|
|
||||||
token = glob.tokens.getTokenFromUserID(self.slots[i].userID)
|
# Destroy playing stream
|
||||||
if token is not None:
|
glob.streams.remove(self.playingStreamName)
|
||||||
token.enqueue(serverPackets.matchComplete())
|
|
||||||
|
|
||||||
# Console output
|
# Console output
|
||||||
log.info("MPROOM{}: Match completed".format(self.matchID))
|
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
|
return -- slot id if found, None if user is not in room
|
||||||
"""
|
"""
|
||||||
for i in range(0,16):
|
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 i
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def userJoin(self, userID):
|
def userJoin(self, user):
|
||||||
"""
|
"""
|
||||||
Add someone to users in match
|
Add someone to users in match
|
||||||
|
|
||||||
|
@ -395,39 +351,38 @@ class match:
|
||||||
|
|
||||||
# Make sure we're not in this match
|
# Make sure we're not in this match
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
if self.slots[i].userID == userID:
|
if self.slots[i].user == user:
|
||||||
# Set bugged slot to free
|
# 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
|
# Find first free slot
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
if self.slots[i].status == slotStatuses.free:
|
if self.slots[i].status == slotStatuses.free:
|
||||||
# Occupy slot
|
# Occupy slot
|
||||||
self.setSlot(i, slotStatuses.notReady, 0, userID, 0)
|
self.setSlot(i, slotStatuses.notReady, 0, user, 0)
|
||||||
|
|
||||||
# Send updated match data
|
# Send updated match data
|
||||||
self.sendUpdate()
|
self.sendUpdates()
|
||||||
|
|
||||||
# Console output
|
# 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 True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def userLeft(self, userID):
|
def userLeft(self, user):
|
||||||
"""
|
"""
|
||||||
Remove someone from users in match
|
Remove someone from users in match
|
||||||
|
|
||||||
userID -- user if of the user
|
userID -- user if of the user
|
||||||
"""
|
"""
|
||||||
# Make sure the user is in room
|
# Make sure the user is in room
|
||||||
slotID = self.getUserSlotID(userID)
|
slotID = self.getUserSlotID(user.userID)
|
||||||
if slotID is None:
|
if slotID is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Set that slot to free
|
# 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
|
# Check if everyone left
|
||||||
if self.countUsers() == 0:
|
if self.countUsers() == 0:
|
||||||
|
@ -437,19 +392,18 @@ class match:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Check if host left
|
# Check if host left
|
||||||
if userID == self.hostUserID:
|
if user.userID == self.hostUserID:
|
||||||
# Give host to someone else
|
# Give host to someone else
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
uid = self.slots[i].userID
|
if self.slots[i].user is not None:
|
||||||
if uid > -1:
|
self.setHost(self.slots[i].user.userID)
|
||||||
self.setHost(uid)
|
|
||||||
break
|
break
|
||||||
|
|
||||||
# Send updated match data
|
# Send updated match data
|
||||||
self.sendUpdate()
|
self.sendUpdates()
|
||||||
|
|
||||||
# Console output
|
# 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):
|
def userChangeSlot(self, userID, newSlotID):
|
||||||
"""
|
"""
|
||||||
|
@ -464,20 +418,21 @@ class match:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Make sure there is no one inside new slot
|
# 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
|
return
|
||||||
|
|
||||||
# Get old slot data
|
# 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
|
# Free old slot
|
||||||
self.setSlot(oldSlotID, slotStatuses.free, 0, -1, 0)
|
self.setSlot(oldSlotID, slotStatuses.free, 0, None, 0)
|
||||||
|
|
||||||
# Occupy new slot
|
# 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
|
# Send updated match data
|
||||||
self.sendUpdate()
|
self.sendUpdates()
|
||||||
|
|
||||||
# Console output
|
# Console output
|
||||||
log.info("MPROOM{}: {} moved to slot {}".format(self.matchID, userID, newSlotID))
|
log.info("MPROOM{}: {} moved to slot {}".format(self.matchID, userID, newSlotID))
|
||||||
|
@ -494,14 +449,10 @@ class match:
|
||||||
self.matchPassword = ""
|
self.matchPassword = ""
|
||||||
|
|
||||||
# Send password change to every user in match
|
# Send password change to every user in match
|
||||||
for i in range(0,16):
|
glob.streams.broadcast(self.streamName, serverPackets.changeMatchPassword(self.matchPassword))
|
||||||
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))
|
|
||||||
|
|
||||||
# Send new match settings too
|
# Send new match settings too
|
||||||
self.sendUpdate()
|
self.sendUpdates()
|
||||||
|
|
||||||
# Console output
|
# Console output
|
||||||
log.info("MPROOM{}: Password changed to {}".format(self.matchID, self.matchPassword))
|
log.info("MPROOM{}: Password changed to {}".format(self.matchID, self.matchPassword))
|
||||||
|
@ -514,7 +465,7 @@ class match:
|
||||||
"""
|
"""
|
||||||
# Set new mods and send update
|
# Set new mods and send update
|
||||||
self.mods = mods
|
self.mods = mods
|
||||||
self.sendUpdate()
|
self.sendUpdates()
|
||||||
log.info("MPROOM{}: Mods changed to {}".format(self.matchID, self.mods))
|
log.info("MPROOM{}: Mods changed to {}".format(self.matchID, self.mods))
|
||||||
|
|
||||||
def userHasBeatmap(self, userID, has = True):
|
def userHasBeatmap(self, userID, has = True):
|
||||||
|
@ -533,7 +484,7 @@ class match:
|
||||||
self.setSlot(slotID, slotStatuses.noMap if not has else slotStatuses.notReady)
|
self.setSlot(slotID, slotStatuses.noMap if not has else slotStatuses.notReady)
|
||||||
|
|
||||||
# Send updates
|
# Send updates
|
||||||
self.sendUpdate()
|
self.sendUpdates()
|
||||||
|
|
||||||
def transferHost(self, slotID):
|
def transferHost(self, slotID):
|
||||||
"""
|
"""
|
||||||
|
@ -542,15 +493,14 @@ class match:
|
||||||
slotID -- ID of slot
|
slotID -- ID of slot
|
||||||
"""
|
"""
|
||||||
# Make sure there is someone in that slot
|
# Make sure there is someone in that slot
|
||||||
uid = self.slots[slotID].userID
|
if self.slots[slotID].user is None:
|
||||||
if uid == -1:
|
|
||||||
return
|
return
|
||||||
|
|
||||||
# Transfer host
|
# Transfer host
|
||||||
self.setHost(uid)
|
self.setHost(self.slots[slotID].user.userID)
|
||||||
|
|
||||||
# Send updates
|
# Send updates
|
||||||
self.sendUpdate()
|
self.sendUpdates()
|
||||||
|
|
||||||
def playerFailed(self, userID):
|
def playerFailed(self, userID):
|
||||||
"""
|
"""
|
||||||
|
@ -564,12 +514,7 @@ class match:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Send packet to everyone
|
# Send packet to everyone
|
||||||
for i in range(0,16):
|
glob.streams.broadcast(self.playingStreamName, serverPackets.playerFailed(slotID))
|
||||||
uid = self.slots[i].userID
|
|
||||||
if uid > -1:
|
|
||||||
token = glob.tokens.getTokenFromUserID(uid)
|
|
||||||
if token is not None:
|
|
||||||
token.enqueue(serverPackets.playerFailed(slotID))
|
|
||||||
|
|
||||||
# Console output
|
# Console output
|
||||||
log.info("MPROOM{}: {} has failed!".format(self.matchID, userID))
|
log.info("MPROOM{}: {} has failed!".format(self.matchID, userID))
|
||||||
|
@ -604,7 +549,7 @@ class match:
|
||||||
"""
|
"""
|
||||||
c = 0
|
c = 0
|
||||||
for i in range(0,16):
|
for i in range(0,16):
|
||||||
if self.slots[i].userID > -1:
|
if self.slots[i].user is not None:
|
||||||
c+=1
|
c+=1
|
||||||
return c
|
return c
|
||||||
|
|
||||||
|
@ -622,17 +567,10 @@ class match:
|
||||||
# Update slot and send update
|
# Update slot and send update
|
||||||
newTeam = matchTeams.blue if self.slots[slotID].team == matchTeams.red else matchTeams.red
|
newTeam = matchTeams.blue if self.slots[slotID].team == matchTeams.red else matchTeams.red
|
||||||
self.setSlot(slotID, None, newTeam)
|
self.setSlot(slotID, None, newTeam)
|
||||||
self.sendUpdate()
|
self.sendUpdates()
|
||||||
|
|
||||||
def sendUpdate(self):
|
def sendUpdates(self):
|
||||||
# Send to users in room
|
glob.streams.broadcast(self.streamName, serverPackets.updateMatch(self.matchID))
|
||||||
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
|
|
||||||
glob.streams.broadcast("lobby", serverPackets.updateMatch(self.matchID))
|
glob.streams.broadcast("lobby", serverPackets.updateMatch(self.matchID))
|
||||||
|
|
||||||
def checkTeams(self):
|
def checkTeams(self):
|
||||||
|
@ -641,14 +579,14 @@ class match:
|
||||||
|
|
||||||
return -- True if valid, False if invalid
|
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
|
# Teams are always valid if we have no teams
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# We have teams, check if they are valid
|
# We have teams, check if they are valid
|
||||||
firstTeam = -1
|
firstTeam = -1
|
||||||
for i in range(0,16):
|
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:
|
if firstTeam == -1:
|
||||||
firstTeam = self.slots[i].team
|
firstTeam = self.slots[i].team
|
||||||
elif 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))
|
log.warning("MPROOM{}: Invalid teams!".format(self.matchID))
|
||||||
return False
|
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()
|
|
@ -21,34 +21,12 @@ class matchList:
|
||||||
hostUserID -- user id of who created the match
|
hostUserID -- user id of who created the match
|
||||||
return -- match ID
|
return -- match ID
|
||||||
"""
|
"""
|
||||||
# Add a new match to matches list
|
# Add a new match to matches list and create its stream
|
||||||
matchID = self.lastID
|
matchID = self.lastID
|
||||||
self.lastID+=1
|
self.lastID+=1
|
||||||
self.matches[matchID] = match.match(matchID, matchName, matchPassword, beatmapID, beatmapName, beatmapMD5, gameMode, hostUserID)
|
self.matches[matchID] = match.match(matchID, matchName, matchPassword, beatmapID, beatmapName, beatmapMD5, gameMode, hostUserID)
|
||||||
return matchID
|
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):
|
def disposeMatch(self, matchID):
|
||||||
"""
|
"""
|
||||||
Destroy match object with id = matchID
|
Destroy match object with id = matchID
|
||||||
|
@ -59,8 +37,10 @@ class matchList:
|
||||||
if matchID not in self.matches:
|
if matchID not in self.matches:
|
||||||
return
|
return
|
||||||
|
|
||||||
# Remove match object
|
# Remove match object and stream
|
||||||
self.matches.pop(matchID)
|
match = self.matches.pop(matchID)
|
||||||
|
glob.streams.remove(match.streamName)
|
||||||
|
glob.streams.remove(match.playingStreamName)
|
||||||
|
|
||||||
# Send match dispose packet to everyone in lobby
|
# Send match dispose packet to everyone in lobby
|
||||||
glob.streams.broadcast("lobby", serverPackets.disposeMatch(matchID))
|
glob.streams.broadcast("lobby", serverPackets.disposeMatch(matchID))
|
|
@ -216,47 +216,6 @@ class token:
|
||||||
# Set our spectating user to 0
|
# Set our spectating user to 0
|
||||||
self.spectating = None
|
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):
|
def setCountry(self, countryID):
|
||||||
"""
|
"""
|
||||||
Set country to countryID
|
Set country to countryID
|
||||||
|
@ -281,13 +240,66 @@ class token:
|
||||||
"""Set a new away message"""
|
"""Set a new away message"""
|
||||||
self.awayMessage = __awayMessage
|
self.awayMessage = __awayMessage
|
||||||
|
|
||||||
|
|
||||||
def joinMatch(self, matchID):
|
def joinMatch(self, matchID):
|
||||||
"""
|
"""
|
||||||
Set match to matchID
|
Set match to matchID, join match stream and channel
|
||||||
|
|
||||||
matchID -- new match ID
|
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.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."):
|
def kick(self, message="You have been kicked from the server. Please login again."):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -40,4 +40,5 @@ class stream:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
for i in self.clients:
|
for i in self.clients:
|
||||||
i.enqueue(data)
|
if i is not None:
|
||||||
|
i.enqueue(data)
|
|
@ -13,7 +13,6 @@ class streamList:
|
||||||
"""
|
"""
|
||||||
if name not in self.streams:
|
if name not in self.streams:
|
||||||
self.streams[name] = stream.stream(name)
|
self.streams[name] = stream.stream(name)
|
||||||
print(str(self.streams))
|
|
||||||
|
|
||||||
def remove(self, name):
|
def remove(self, name):
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in New Issue
Block a user