.BANCHO. pep.py modules

This commit is contained in:
Nyo
2016-05-18 19:12:46 +02:00
parent 993079d2dd
commit 9325578377
74 changed files with 212 additions and 212 deletions

View File

@@ -0,0 +1,21 @@
from objects import glob
from constants import serverPackets
from helpers import consoleHelper
from constants import bcolors
from constants import exceptions
def handle(userToken, packetData):
# get usertoken data
userID = userToken.userID
try:
# We don't have the beatmap, we can't spectate
target = userToken.spectating
targetToken = glob.tokens.getTokenFromUserID(target)
# Send the packet to host
targetToken.enqueue(serverPackets.noSongSpectator(userID))
except exceptions.tokenNotFoundException:
# Stop spectating if token not found
consoleHelper.printColored("[!] Spectator can't spectate: token not found", bcolors.RED)
userToken.stopSpectating()

View File

@@ -0,0 +1,32 @@
from objects import glob
from constants import clientPackets
from constants import serverPackets
from constants import actions
from helpers import userHelper
def handle(userToken, packetData):
# Get usertoken data
userID = userToken.userID
username = userToken.username
# Make sure we are not banned
if userHelper.getAllowed(userID) == 0:
userToken.enqueue(serverPackets.loginBanned())
return
# Change action packet
packetData = clientPackets.userActionChange(packetData)
# Update our action id, text and md5
userToken.actionID = packetData["actionID"]
userToken.actionText = packetData["actionText"]
userToken.actionMd5 = packetData["actionMd5"]
userToken.actionMods = packetData["actionMods"]
userToken.gameMode = packetData["gameMode"]
# Enqueue our new user panel and stats to everyone
glob.tokens.enqueueAll(serverPackets.userPanel(userID))
glob.tokens.enqueueAll(serverPackets.userStats(userID))
# Console output
print("> {} changed action: {} [{}][{}]".format(username, str(userToken.actionID), userToken.actionText, userToken.actionMd5))

View File

@@ -0,0 +1,43 @@
from objects import glob
from constants import clientPackets
from constants import matchModModes
from constants import mods
def handle(userToken, packetData):
# Get token data
userID = userToken.userID
# Get packet data
packetData = clientPackets.changeMods(packetData)
# Make sure the match exists
matchID = userToken.matchID
if matchID not in glob.matches.matches:
return
match = glob.matches.matches[matchID]
# Set slot or match mods according to modType
if match.matchModMode == matchModModes.freeMod:
# Freemod
# Host can set global DT/HT
if userID == match.hostUserID:
# If host has selected DT/HT and Freemod is enabled, set DT/HT as match mod
if (packetData["mods"] & mods.DoubleTime) > 0:
match.changeMatchMods(mods.DoubleTime)
# Nighcore
if (packetData["mods"] & mods.Nightcore) > 0:
match.changeMatchMods(match.mods+mods.Nightcore)
elif (packetData["mods"] & mods.HalfTime) > 0:
match.changeMatchMods(mods.HalfTime)
else:
# No DT/HT, set global mods to 0 (we are in freemod mode)
match.changeMatchMods(0)
# Set slot mods
slotID = match.getUserSlotID(userID)
if slotID != None:
match.setSlotMods(slotID, packetData["mods"])
else:
# Not freemod, set match mods
match.changeMatchMods(packetData["mods"])

View File

@@ -0,0 +1,17 @@
from constants import clientPackets
from objects import glob
def handle(userToken, packetData):
# Read packet data. Same structure as changeMatchSettings
packetData = clientPackets.changeMatchSettings(packetData)
# Make sure the match exists
matchID = userToken.matchID
if matchID not in glob.matches.matches:
return
# Get our match
match = glob.matches.matches[matchID]
# Update match password
match.changePassword(packetData["matchPassword"])

View File

@@ -0,0 +1,109 @@
from objects import glob
from constants import clientPackets
from constants import matchModModes
from helpers import consoleHelper
from constants import bcolors
import random
from constants import matchTeamTypes
from constants import matchTeams
from constants import slotStatuses
def handle(userToken, packetData):
# Read new settings
packetData = clientPackets.changeMatchSettings(packetData)
# Get match ID
matchID = userToken.matchID
# Make sure the match exists
if matchID not in glob.matches.matches:
return
# Get match object
match = glob.matches.matches[matchID]
# Some dank memes easter egg
memeTitles = [
"RWC 2020",
"Fokabot is a duck",
"Dank memes",
"1337ms Ping",
"Iscriviti a Xenotoze",
"...e i marò?",
"Superman dies",
"The brace is on fire",
"print_foot()",
"#FREEZEBARKEZ",
"Ripple devs are actually cats",
"Thank Mr Shaural",
"NEVER GIVE UP",
"T I E D W I T H U N I T E D",
"HIGHEST HDHR LOBBY OF ALL TIME",
"This is gasoline and I set myself on fire",
"Everyone is cheating apparently",
"Kurwa mac",
"TATOE",
"This is not your drama landfill.",
"I like cheese",
"NYO IS NOT A CAT HE IS A DO(N)G",
"Datingu startuato"
]
# Set match name
match.matchName = packetData["matchName"] if packetData["matchName"] != "meme" else random.choice(memeTitles)
# Update match settings
match.inProgress = packetData["inProgress"]
match.matchPassword = packetData["matchPassword"]
match.beatmapName = packetData["beatmapName"]
match.beatmapID = packetData["beatmapID"]
match.hostUserID = packetData["hostUserID"]
match.gameMode = packetData["gameMode"]
oldBeatmapMD5 = match.beatmapMD5
oldMods = match.mods
match.mods = packetData["mods"]
match.beatmapMD5 = packetData["beatmapMD5"]
match.matchScoringType = packetData["scoringType"]
match.matchTeamType = packetData["teamType"]
match.matchModMode = packetData["freeMods"]
# Reset ready if needed
if oldMods != match.mods or oldBeatmapMD5 != match.beatmapMD5:
for i in range(0,16):
if match.slots[i]["status"] == slotStatuses.ready:
match.slots[i]["status"] = slotStatuses.notReady
# Reset mods if needed
if match.matchModMode == matchModModes.normal:
# Reset slot mods if not freeMods
for i in range(0,16):
match.slots[i]["mods"] = 0
else:
# Reset match mods if freemod
match.mods = 0
# Set/reset teams
if match.matchTeamType == matchTeamTypes.teamVs or match.matchTeamType == matchTeamTypes.tagTeamVs:
# Set teams
c=0
for i in range(0,16):
if match.slots[i]["team"] == matchTeams.noTeam:
match.slots[i]["team"] = matchTeams.red if c % 2 == 0 else matchTeams.blue
c+=1
else:
# Reset teams
for i in range(0,16):
match.slots[i]["team"] = matchTeams.noTeam
# Force no freemods if tag coop
if match.matchTeamType == matchTeamTypes.tagCoop or match.matchTeamType == matchTeamTypes.tagTeamVs:
match.matchModMode = matchModModes.normal
# Send updated settings
match.sendUpdate()
# Console output
consoleHelper.printColored("> MPROOM{}: Updated room settings".format(match.matchID), bcolors.BLUE)
#consoleHelper.printColored("> MPROOM{}: DEBUG: Host is {}".format(match.matchID, match.hostUserID), bcolors.PINK)

18
events/changeSlotEvent.py Normal file
View File

@@ -0,0 +1,18 @@
from constants import clientPackets
from objects import glob
from helpers import consoleHelper
from constants import bcolors
def handle(userToken, packetData):
# Get usertoken data
userID = userToken.userID
username = userToken.username
# Read packet data
packetData = clientPackets.changeSlot(packetData)
# Get match
match = glob.matches.matches[userToken.matchID]
# Change slot
match.userChangeSlot(userID, packetData["slotID"])

View File

@@ -0,0 +1,56 @@
"""
Event called when someone joins a channel
"""
from constants import clientPackets
from helpers import consoleHelper
from constants import bcolors
from constants import serverPackets
from objects import glob
from constants import exceptions
def handle(userToken, packetData):
# Channel join packet
packetData = clientPackets.channelJoin(packetData)
joinChannel(userToken, packetData["channel"])
def joinChannel(userToken, channelName):
'''
Join a channel
userToken -- user token object of user that joins the chanlle
channelName -- name of channel
'''
try:
# Get usertoken data
username = userToken.username
userID = userToken.userID
userRank = userToken.rank
# Check spectator channel
# If it's spectator channel, skip checks and list stuff
if channelName != "#spectator" and channelName != "#multiplayer":
# Normal channel, do check stuff
# Make sure the channel exists
if channelName not in glob.channels.channels:
raise exceptions.channelUnknownException
# Check channel permissions
if glob.channels.channels[channelName].publicRead == False and userRank <= 2:
raise exceptions.channelNoPermissionsException
# Add our userID to users in that channel
glob.channels.channels[channelName].userJoin(userID)
# Add the channel to our joined channel
userToken.joinChannel(channelName)
# Send channel joined
userToken.enqueue(serverPackets.channelJoinSuccess(userID, channelName))
# Console output
consoleHelper.printColored("> {} joined channel {}".format(username, channelName), bcolors.GREEN)
except exceptions.channelNoPermissionsException:
consoleHelper.printColored("[!] {} attempted to join channel {}, but they have no read permissions".format(username, channelName), bcolors.RED)
except exceptions.channelUnknownException:
consoleHelper.printColored("[!] {} attempted to join an unknown channel ({})".format(username, channelName), bcolors.RED)

View File

@@ -0,0 +1,36 @@
"""
Event called when someone parts a channel
"""
from helpers import consoleHelper
from constants import bcolors
from objects import glob
from constants import clientPackets
from constants import serverPackets
def handle(userToken, packetData):
# Channel part packet
packetData = clientPackets.channelPart(packetData)
partChannel(userToken, packetData["channel"])
def partChannel(userToken, channelName, kick = False):
# Get usertoken data
username = userToken.username
userID = userToken.userID
# Remove us from joined users and joined channels
if channelName in glob.channels.channels:
# Check that user is in channel
if channelName in userToken.joinedChannels:
userToken.partChannel(channelName)
# Check if user is in channel
if userID in glob.channels.channels[channelName].connectedUsers:
glob.channels.channels[channelName].userPart(userID)
# Force close tab if needed
if kick == True:
userToken.enqueue(serverPackets.channelKicked(channelName))
# Console output
consoleHelper.printColored("> {} parted channel {}".format(username, channelName), bcolors.YELLOW)

View File

@@ -0,0 +1,44 @@
from constants import serverPackets
from constants import clientPackets
from objects import glob
from helpers import consoleHelper
from constants import bcolors
from events import joinMatchEvent
from constants import exceptions
def handle(userToken, packetData):
try:
# get usertoken data
userID = userToken.userID
# Read packet data
packetData = clientPackets.createMatch(packetData)
# Create a match object
# TODO: Player number check
matchID = glob.matches.createMatch(packetData["matchName"], packetData["matchPassword"], packetData["beatmapID"], packetData["beatmapName"], packetData["beatmapMD5"], packetData["gameMode"], userID)
# Make sure the match has been created
if matchID not in glob.matches.matches:
raise exceptions.matchCreateError
# Get match object
match = glob.matches.matches[matchID]
# Join that match
joinMatchEvent.joinMatch(userToken, matchID, packetData["matchPassword"])
# Give host to match creator
match.setHost(userID)
# Send match create packet to everyone in lobby
for i in glob.matches.usersInLobby:
# Make sure this user is still connected
token = glob.tokens.getTokenFromUserID(i)
if token != None:
token.enqueue(serverPackets.createMatch(matchID))
# Console output
consoleHelper.printColored("> MPROOM{}: Room created!".format(matchID), bcolors.BLUE)
except exceptions.matchCreateError:
consoleHelper.printColored("[!] Error while creating match!", bcolors.RED)

10
events/friendAddEvent.py Normal file
View File

@@ -0,0 +1,10 @@
from helpers import userHelper
from constants import clientPackets
def handle(userToken, packetData):
# Friend add packet
packetData = clientPackets.addRemoveFriend(packetData)
userHelper.addFriend(userToken.userID, packetData["friendID"])
# Console output
print("> {} have added {} to their friends".format(userToken.username, str(packetData["friendID"])))

View File

@@ -0,0 +1,10 @@
from helpers import userHelper
from constants import clientPackets
def handle(userToken, packetData):
# Friend remove packet
packetData = clientPackets.addRemoveFriend(packetData)
userHelper.removeFriend(userToken.userID, packetData["friendID"])
# Console output
print("> {} have removed {} from their friends".format(userToken.username, str(packetData["friendID"])))

19
events/joinLobbyEvent.py Normal file
View File

@@ -0,0 +1,19 @@
from constants import serverPackets
from objects import glob
from helpers import consoleHelper
from constants import bcolors
def handle(userToken, _):
# Get userToken data
username = userToken.username
userID = userToken.userID
# Add user to users in lobby
glob.matches.lobbyUserJoin(userID)
# Send matches data
for key, _ in glob.matches.matches.items():
userToken.enqueue(serverPackets.createMatch(key))
# Console output
consoleHelper.printColored("> {} has joined multiplayer lobby".format(username), bcolors.BLUE)

60
events/joinMatchEvent.py Normal file
View File

@@ -0,0 +1,60 @@
from constants import clientPackets
from constants import serverPackets
from objects import glob
from helpers import consoleHelper
from constants import bcolors
from constants import exceptions
def handle(userToken, packetData):
# read packet data
packetData = clientPackets.joinMatch(packetData)
# Get match from ID
joinMatch(userToken, packetData["matchID"], packetData["password"])
def joinMatch(userToken, matchID, password):
try:
# TODO: leave other matches
# TODO: Stop spectating
# get usertoken data
userID = userToken.userID
username = userToken.username
# Make sure the match exists
if matchID not in glob.matches.matches:
raise exceptions.matchNotFoundException
# Match exists, get object
match = glob.matches.matches[matchID]
# Check password
# TODO: Admins can enter every match
if match.matchPassword != "":
if match.matchPassword != password:
raise exceptions.matchWrongPasswordException
# Password is correct, join match
result = match.userJoin(userID)
# Check if we've joined the match successfully
if result == False:
raise exceptions.matchJoinErrorException
# Match joined, set matchID for usertoken
userToken.joinMatch(matchID)
# Send packets
userToken.enqueue(serverPackets.matchJoinSuccess(matchID))
userToken.enqueue(serverPackets.channelJoinSuccess(userID, "#multiplayer"))
#userToken.enqueue(serverPackets.sendMessage("FokaBot", "#multiplayer", "Hi {}, and welcome to Ripple's multiplayer mode! This feature is still WIP and might have some issues. If you find any bugs, please report them (by clicking here)[https://ripple.moe/index.php?p=22].".format(username)))
except exceptions.matchNotFoundException:
userToken.enqueue(serverPackets.matchJoinFail())
consoleHelper.printColored("[!] {} has tried to join a mp room, but it doesn't exist".format(userToken.username), bcolors.RED)
except exceptions.matchWrongPasswordException:
userToken.enqueue(serverPackets.matchJoinFail())
consoleHelper.printColored("[!] {} has tried to join a mp room, but he typed the wrong password".format(userToken.username), bcolors.RED)
except exceptions.matchJoinErrorException:
userToken.enqueue(serverPackets.matchJoinFail())
consoleHelper.printColored("[!] {} has tried to join a mp room, but an error has occured".format(userToken.username), bcolors.RED)

184
events/loginEvent.py Normal file
View File

@@ -0,0 +1,184 @@
from helpers import userHelper
from constants import serverPackets
from constants import exceptions
from objects import glob
from helpers import consoleHelper
from constants import bcolors
from helpers import locationHelper
from helpers import countryHelper
import time
from helpers import generalFunctions
from events import channelJoinEvent
import sys
import traceback
def handle(flaskRequest):
# Data to return
responseTokenString = "ayy"
responseData = bytes()
# Get IP from flask request
requestIP = flaskRequest.headers.get('X-Real-IP')
if requestIP == None:
requestIP = flaskRequest.remote_addr
# Console output
print("> Accepting connection from {}...".format(requestIP))
# Split POST body so we can get username/password/hardware data
# 2:-3 thing is because requestData has some escape stuff that we don't need
loginData = str(flaskRequest.data)[2:-3].split("\\n")
# Process login
print("> Processing login request for {}...".format(loginData[0]))
try:
# If true, print error to console
err = False
# Try to get the ID from username
userID = userHelper.getID(str(loginData[0]))
if userID == False:
# Invalid username
raise exceptions.loginFailedException()
if userHelper.checkLogin(userID, loginData[1]) == False:
# Invalid password
raise exceptions.loginFailedException()
# Make sure we are not banned
userAllowed = userHelper.getAllowed(userID)
if userAllowed == 0:
# Banned
raise exceptions.loginBannedException()
# No login errors!
# Delete old tokens for that user and generate a new one
glob.tokens.deleteOldTokens(userID)
responseToken = glob.tokens.addToken(userID)
responseTokenString = responseToken.token
# Get silence end
userSilenceEnd = max(0, userHelper.getSilenceEnd(userID)-int(time.time()))
# Get supporter/GMT
userRank = userHelper.getRankPrivileges(userID)
userGMT = False
userSupporter = True
if userRank >= 3:
userGMT = True
# Server restarting check
if glob.restarting == True:
raise exceptions.banchoRestartingException()
# Maintenance check
if glob.banchoConf.config["banchoMaintenance"] == True:
if userGMT == False:
# We are not mod/admin, delete token, send notification and logout
glob.tokens.deleteToken(responseTokenString)
raise exceptions.banchoMaintenanceException()
else:
# We are mod/admin, send warning notification and continue
responseToken.enqueue(serverPackets.notification("Bancho is in maintenance mode. Only mods/admins have full access to the server.\nType !system maintenance off in chat to turn off maintenance mode."))
# Send all needed login packets
responseToken.enqueue(serverPackets.silenceEndTime(userSilenceEnd))
responseToken.enqueue(serverPackets.userID(userID))
responseToken.enqueue(serverPackets.protocolVersion())
responseToken.enqueue(serverPackets.userSupporterGMT(userSupporter, userGMT))
responseToken.enqueue(serverPackets.userPanel(userID))
responseToken.enqueue(serverPackets.userStats(userID))
# Channel info end (before starting!?! wtf bancho?)
responseToken.enqueue(serverPackets.channelInfoEnd())
# Default opened channels
# TODO: Configurable default channels
channelJoinEvent.joinChannel(responseToken, "#osu")
channelJoinEvent.joinChannel(responseToken, "#announce")
if userRank >= 3:
# Join admin chanenl if we are mod/admin
# TODO: Separate channels for mods and admins
channelJoinEvent.joinChannel(responseToken, "#admin")
# Output channels info
for key, value in glob.channels.channels.items():
if value.publicRead == True:
responseToken.enqueue(serverPackets.channelInfo(key))
responseToken.enqueue(serverPackets.friendList(userID))
# Send main menu icon and login notification if needed
if glob.banchoConf.config["menuIcon"] != "":
responseToken.enqueue(serverPackets.mainMenuIcon(glob.banchoConf.config["menuIcon"]))
if glob.banchoConf.config["loginNotification"] != "":
responseToken.enqueue(serverPackets.notification(glob.banchoConf.config["loginNotification"]))
# Get everyone else userpanel
# TODO: Better online users handling
for key, value in glob.tokens.tokens.items():
responseToken.enqueue(serverPackets.userPanel(value.userID))
responseToken.enqueue(serverPackets.userStats(value.userID))
# Send online users IDs array
responseToken.enqueue(serverPackets.onlineUsers())
# Get location and country from ip.zxq.co or database
if generalFunctions.stringToBool(glob.conf.config["server"]["localizeusers"]):
# Get location and country from IP
location = locationHelper.getLocation(requestIP)
countryLetters = locationHelper.getCountry(requestIP)
country = countryHelper.getCountryID(countryLetters)
else:
# Set location to 0,0 and get country from db
print("[!] Location skipped")
location = [0,0]
countryLetters = "XX"
country = countryHelper.getCountryID(userHelper.getCountry(userID))
# Set location and country
responseToken.setLocation(location)
responseToken.setCountry(country)
# Set country in db if user has no country (first bancho login)
if userHelper.getCountry(userID) == "XX":
userHelper.setCountry(userID, countryLetters)
# Send to everyone our userpanel and userStats (so they now we have logged in)
glob.tokens.enqueueAll(serverPackets.userPanel(userID))
glob.tokens.enqueueAll(serverPackets.userStats(userID))
# Set reponse data to right value and reset our queue
responseData = responseToken.queue
responseToken.resetQueue()
# Print logged in message
consoleHelper.printColored("> {} logged in ({})".format(loginData[0], responseToken.token), bcolors.GREEN)
except exceptions.loginFailedException:
# Login failed error packet
# (we don't use enqueue because we don't have a token since login has failed)
err = True
responseData += serverPackets.loginFailed()
except exceptions.loginBannedException:
# Login banned error packet
err = True
responseData += serverPackets.loginBanned()
except exceptions.banchoMaintenanceException:
# Bancho is in maintenance mode
responseData += serverPackets.notification("Our bancho server is in maintenance mode. Please try to login again later.")
responseData += serverPackets.loginError()
except exceptions.banchoRestartingException:
# Bancho is restarting
responseData += serverPackets.notification("Bancho is restarting. Try again in a few minutes.")
responseData += serverPackets.loginError()
except:
# Unknown exception
msg = "UNKNOWN ERROR IN LOGIN!!!\n{}\n{}".format(sys.exc_info(), traceback.format_exc())
consoleHelper.printColored("[!] {}".format(msg), bcolors.RED)
finally:
# Print login failed message to console if needed
if err == True:
consoleHelper.printColored("> {}'s login failed".format(loginData[0]), bcolors.YELLOW)
return (responseTokenString, responseData)

39
events/logoutEvent.py Normal file
View File

@@ -0,0 +1,39 @@
from objects import glob
from helpers import consoleHelper
from constants import bcolors
from constants import serverPackets
import time
def handle(userToken, _):
# get usertoken data
userID = userToken.userID
username = userToken.username
requestToken = userToken.token
# Big client meme here. If someone logs out and logs in right after,
# the old logout packet will still be in the queue and will be sent to
# the server, so we accept logout packets sent at least 5 seconds after login
# if the user logs out before 5 seconds, he will be disconnected later with timeout check
if int(time.time()-userToken.loginTime) >= 5:
# Stop spectating if needed
if userToken.spectating != 0:
# The user was spectating someone
spectatorHostToken = glob.tokens.getTokenFromUserID(userToken.spectating)
if spectatorHostToken != None:
# The host is still online, send removeSpectator to him
spectatorHostToken.enqueue(serverPackets.removeSpectator(userID))
# Part all joined channels
for i in userToken.joinedChannels:
glob.channels.channels[i].userPart(userID)
# TODO: Lobby left if joined
# Enqueue our disconnection to everyone else
glob.tokens.enqueueAll(serverPackets.userLogout(userID))
# Delete token
glob.tokens.deleteToken(requestToken)
# Console output
consoleHelper.printColored("> {} have been disconnected.".format(username), bcolors.YELLOW)

View File

@@ -0,0 +1,22 @@
from objects import glob
def handle(userToken, packetData, has):
# Get usertoken data
userID = userToken.userID
# Get match ID and match object
matchID = userToken.matchID
# Make sure we are in a match
if matchID == -1:
return
# Make sure the match exists
if matchID not in glob.matches.matches:
return
# The match exists, get object
match = glob.matches.matches[matchID]
# Set has beatmap/no beatmap
match.userHasBeatmap(userID, has)

View File

@@ -0,0 +1,22 @@
from objects import glob
def handle(userToken, _):
# Read token data
userID = userToken.userID
# Get match ID and match object
matchID = userToken.matchID
# Make sure we are in a match
if matchID == -1:
return
# Make sure the match exists
if matchID not in glob.matches.matches:
return
# Get match object
match = glob.matches.matches[matchID]
# Change team
match.changeTeam(userID)

View File

@@ -0,0 +1,22 @@
from objects import glob
def handle(userToken, packetData):
# Get usertoken data
userID = userToken.userID
# Get match ID and match object
matchID = userToken.matchID
# Make sure we are in a match
if matchID == -1:
return
# Make sure the match exists
if matchID not in glob.matches.matches:
return
# The match exists, get object
match = glob.matches.matches[matchID]
# Set our match complete
match.playerCompleted(userID)

View File

@@ -0,0 +1,22 @@
from objects import glob
def handle(userToken, _):
# Get usertoken data
userID = userToken.userID
# Get match ID and match object
matchID = userToken.matchID
# Make sure we are in a match
if matchID == -1:
return
# Make sure the match exists
if matchID not in glob.matches.matches:
return
# Match exists, get object
match = glob.matches.matches[matchID]
# Fail user
match.playerFailed(userID)

View File

@@ -0,0 +1,35 @@
from objects import glob
from constants import slotStatuses
from constants import serverPackets
def handle(userToken, packetData):
# Get usertoken data
userID = userToken.userID
# Get match ID and match object
matchID = userToken.matchID
# Make sure we are in a match
if matchID == -1:
return
# Make sure the match exists
if matchID not in glob.matches.matches:
return
# The match exists, get object
match = glob.matches.matches[matchID]
# Change slot id in packetData
slotID = match.getUserSlotID(userID)
'''opd = packetData[4]
packetData = bytearray(packetData)
packetData[4] = slotID
print("User: {}, slot {}, oldPackData: {}, packData {}".format(userID, slotID, opd, packetData[4]))'''
# 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 != None:
token.enqueue(serverPackets.matchFrames(slotID, packetData))

View File

@@ -0,0 +1,3 @@
from events import matchBeatmapEvent
def handle(userToken, packetData):
matchBeatmapEvent.handle(userToken, packetData, True)

View File

@@ -0,0 +1,24 @@
from constants import clientPackets
from objects import glob
def handle(userToken, packetData):
# Read token and packet data
userID = userToken.userID
packetData = clientPackets.matchInvite(packetData)
# Get match ID and match object
matchID = userToken.matchID
# Make sure we are in a match
if matchID == -1:
return
# Make sure the match exists
if matchID not in glob.matches.matches:
return
# Get match object
match = glob.matches.matches[matchID]
# Send invite
match.invite(userID, packetData["userID"])

23
events/matchLockEvent.py Normal file
View File

@@ -0,0 +1,23 @@
from objects import glob
from constants import clientPackets
def handle(userToken, packetData):
# Get token data
userID = userToken.userID
# Get packet data
packetData = clientPackets.lockSlot(packetData)
# Make sure the match exists
matchID = userToken.matchID
if matchID not in glob.matches.matches:
return
match = glob.matches.matches[matchID]
# Make sure we aren't locking our slot
ourSlot = match.getUserSlotID(userID)
if packetData["slotID"] == ourSlot:
return
# Lock/Unlock slot
match.toggleSlotLock(packetData["slotID"])

View File

@@ -0,0 +1,3 @@
from events import matchBeatmapEvent
def handle(userToken, packetData):
matchBeatmapEvent.handle(userToken, packetData, False)

View File

@@ -0,0 +1,22 @@
from objects import glob
def handle(userToken, packetData):
# Get userToken data
userID = userToken.userID
# Get match ID and match object
matchID = userToken.matchID
# Make sure we are in a match
if matchID == -1:
return
# Make sure the match exists
if matchID not in glob.matches.matches:
return
# The match exists, get object
match = glob.matches.matches[matchID]
# Set our load status
match.playerLoaded(userID)

16
events/matchReadyEvent.py Normal file
View File

@@ -0,0 +1,16 @@
from objects import glob
def handle(userToken, _):
# Get usertoken data
userID = userToken.userID
# Make sure the match exists
matchID = userToken.matchID
if matchID not in glob.matches.matches:
return
match = glob.matches.matches[matchID]
# Get our slotID and change ready status
slotID = match.getUserSlotID(userID)
if slotID != None:
match.toggleSlotReady(slotID)

22
events/matchSkipEvent.py Normal file
View File

@@ -0,0 +1,22 @@
from objects import glob
def handle(userToken, packetData):
# Get userToken data
userID = userToken.userID
# Get match ID and match object
matchID = userToken.matchID
# Make sure we are in a match
if matchID == -1:
return
# Make sure the match exists
if matchID not in glob.matches.matches:
return
# The match exists, get object
match = glob.matches.matches[matchID]
# Skip
match.playerSkip(userID)

47
events/matchStartEvent.py Normal file
View File

@@ -0,0 +1,47 @@
from objects import glob
from constants import slotStatuses
from constants import serverPackets
def handle(userToken, _):
# TODO: Host check
# Get match ID and match object
matchID = userToken.matchID
# Make sure we are in a match
if matchID == -1:
return
# Make sure the match exists
if matchID not in glob.matches.matches:
return
# The match exists, get object
match = glob.matches.matches[matchID]
force = False # TODO: Force thing
# Make sure we have enough players
if (match.countUsers() < 2 or not match.checkTeams()) and not force:
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 != None:
token.enqueue(serverPackets.matchStart(matchID))
# Send updates
match.sendUpdate()

View File

@@ -0,0 +1,23 @@
from objects import glob
from constants import clientPackets
def handle(userToken, packetData):
# Get packet data
packetData = clientPackets.transferHost(packetData)
# Get match ID and match object
matchID = userToken.matchID
# Make sure we are in a match
if matchID == -1:
return
# Make sure the match exists
if matchID not in glob.matches.matches:
return
# Match exists, get object
match = glob.matches.matches[matchID]
# Transfer host
match.transferHost(packetData["slotID"])

18
events/partLobbyEvent.py Normal file
View File

@@ -0,0 +1,18 @@
from objects import glob
from events import channelPartEvent
from helpers import consoleHelper
from constants import bcolors
def handle(userToken, _):
# Get usertoken data
userID = userToken.userID
username = userToken.username
# Remove user from users in lobby
glob.matches.lobbyUserPart(userID)
# Part lobby channel
channelPartEvent.partChannel(userToken, "#lobby", True)
# Console output
consoleHelper.printColored("> {} has left multiplayer lobby".format(username), bcolors.BLUE)

27
events/partMatchEvent.py Normal file
View File

@@ -0,0 +1,27 @@
from objects import glob
from constants import serverPackets
def handle(userToken, _):
# get data from usertoken
userID = userToken.userID
# Get match ID and match object
matchID = userToken.matchID
# Make sure we are in a match
if matchID == -1:
return
# Make sure the match exists
if matchID not in glob.matches.matches:
return
# The match exists, get object
match = glob.matches.matches[matchID]
# Set slot to free
match.userLeft(userID)
# Set usertoken match to -1
userToken.partMatch()
userToken.enqueue(serverPackets.channelKicked("#multiplayer"))

View File

@@ -0,0 +1,52 @@
from helpers import consoleHelper
from constants import bcolors
from constants import clientPackets
from constants import serverPackets
from objects import glob
from objects import fokabot
from constants import exceptions
from constants import messageTemplates
def handle(userToken, packetData):
"""
Event called when someone sends a private message
userToken -- request user token
packetData -- request data bytes
"""
try:
# Get usertoken username
username = userToken.username
# Private message packet
packetData = clientPackets.sendPrivateMessage(packetData)
if packetData["to"] == "FokaBot":
# FokaBot command check
fokaMessage = fokabot.fokabotResponse(username, packetData["to"], packetData["message"])
if fokaMessage != False:
userToken.enqueue(serverPackets.sendMessage("FokaBot", username, fokaMessage))
consoleHelper.printColored("> FokaBot>{}: {}".format(packetData["to"], str(fokaMessage.encode("UTF-8"))), bcolors.PINK)
else:
# Send packet message to target if it exists
token = glob.tokens.getTokenFromUsername(packetData["to"])
if token == None:
raise exceptions.tokenNotFoundException()
# Check message templates (mods/admins only)
if packetData["message"] in messageTemplates.templates and userToken.rank >= 3:
packetData["message"] = messageTemplates.templates[packetData["message"]]
# Send message to target
token.enqueue(serverPackets.sendMessage(username, packetData["to"], packetData["message"]))
# Send away message to sender if needed
if token.awayMessage != "":
userToken.enqueue(serverPackets.sendMessage(packetData["to"], username, "This user is away: {}".format(token.awayMessage)))
# Console output
consoleHelper.printColored("> {}>{}: {}".format(username, packetData["to"], packetData["message"]), bcolors.PINK)
except exceptions.tokenNotFoundException:
# Token not found, user disconnected
consoleHelper.printColored("[!] {} tried to send a message to {}, but their token couldn't be found".format(username, packetData["to"]), bcolors.RED)

View File

@@ -0,0 +1,108 @@
from constants import exceptions
from constants import clientPackets
from objects import glob
from objects import fokabot
from helpers import consoleHelper
from constants import bcolors
from constants import serverPackets
def handle(userToken, packetData):
"""
Event called when someone sends a public message
userToken -- request user token
packetData -- request data bytes
"""
try:
# Get uesrToken data
userID = userToken.userID
username = userToken.username
userRank = userToken.rank
# Public chat packet
packetData = clientPackets.sendPublicMessage(packetData)
# Receivers
who = []
# Check #spectator
if packetData["to"] == "#spectator":
# Spectator channel
# Send this packet to every spectator and host
if userToken.spectating == 0:
# We have sent to send a message to our #spectator channel
targetToken = userToken
who = targetToken.spectators[:]
# No need to remove us because we are the host so we are not in spectators list
else:
# We have sent a message to someone else's #spectator
targetToken = glob.tokens.getTokenFromUserID(userToken.spectating)
who = targetToken.spectators[:]
# Remove us
if userID in who:
who.remove(userID)
# Add host
who.append(targetToken.userID)
elif packetData["to"] == "#multiplayer":
# Multiplayer Channel
# Get match ID and match object
matchID = userToken.matchID
# Make sure we are in a match
if matchID == -1:
return
# Make sure the match exists
if matchID not in glob.matches.matches:
return
# The match exists, get object
match = glob.matches.matches[matchID]
# Create targets list
who = []
for i in range(0,16):
uid = match.slots[i]["userID"]
if uid > -1 and uid != userID:
who.append(uid)
else:
# Standard channel
# Make sure the channel exists
if packetData["to"] not in glob.channels.channels:
raise exceptions.channelUnknownException
# Make sure the channel is not in moderated mode
if glob.channels.channels[packetData["to"]].moderated == True and userRank <= 2:
raise exceptions.channelModeratedException
# Make sure we have write permissions
if glob.channels.channels[packetData["to"]].publicWrite == False and userRank <= 2:
raise exceptions.channelNoPermissionsException
# Send this packet to everyone in that channel except us
who = glob.channels.channels[packetData["to"]].getConnectedUsers()[:]
if userID in who:
who.remove(userID)
# Send packet to required users
glob.tokens.multipleEnqueue(serverPackets.sendMessage(username, packetData["to"], packetData["message"]), who, False)
# Fokabot command check
fokaMessage = fokabot.fokabotResponse(username, packetData["to"], packetData["message"])
if fokaMessage != False:
who.append(userID)
glob.tokens.multipleEnqueue(serverPackets.sendMessage("FokaBot", packetData["to"], fokaMessage), who, False)
consoleHelper.printColored("> FokaBot@{}: {}".format(packetData["to"], str(fokaMessage.encode("UTF-8"))), bcolors.PINK)
# Console output
consoleHelper.printColored("> {}@{}: {}".format(username, packetData["to"], str(packetData["message"].encode("UTF-8"))), bcolors.PINK)
except exceptions.channelModeratedException:
consoleHelper.printColored("[!] {} tried to send a message to a channel that is in moderated mode ({})".format(username, packetData["to"]), bcolors.RED)
except exceptions.channelUnknownException:
consoleHelper.printColored("[!] {} tried to send a message to an unknown channel ({})".format(username, packetData["to"]), bcolors.RED)
except exceptions.channelNoPermissionsException:
consoleHelper.printColored("[!] {} tried to send a message to channel {}, but they have no write permissions".format(username, packetData["to"]), bcolors.RED)

View File

@@ -0,0 +1,20 @@
from constants import clientPackets
from constants import serverPackets
def handle(userToken, packetData):
# get token data
username = userToken.username
# Read packet data
packetData = clientPackets.setAwayMessage(packetData)
# Set token away message
userToken.setAwayMessage(packetData["awayMessage"])
# Send private message from fokabot
if packetData["awayMessage"] == "":
fokaMessage = "Your away message has been reset"
else:
fokaMessage = "Your away message is now: {}".format(packetData["awayMessage"])
userToken.enqueue(serverPackets.sendMessage("FokaBot", username, fokaMessage))
print("{} has changed their away message to: {}".format(username, packetData["awayMessage"]))

View File

@@ -0,0 +1,33 @@
from objects import glob
from helpers import consoleHelper
from constants import bcolors
from constants import serverPackets
from constants import exceptions
def handle(userToken, packetData):
# get token data
userID = userToken.userID
# Send spectator frames to every spectator
consoleHelper.printColored("> {}'s spectators: {}".format(str(userID), str(userToken.spectators)), bcolors.BLUE)
for i in userToken.spectators:
# Send to every user but host
if i != userID:
try:
# Get spectator token object
spectatorToken = glob.tokens.getTokenFromUserID(i)
# Make sure the token exists
if spectatorToken == None:
raise exceptions.stopSpectating
# Make sure this user is spectating us
if spectatorToken.spectating != userID:
raise exceptions.stopSpectating
# Everything seems fine, send spectator frames to this spectator
spectatorToken.enqueue(serverPackets.spectatorFrames(packetData[7:]))
except exceptions.stopSpectating:
# Remove this user from spectators
userToken.removeSpectator(i)
userToken.enqueue(serverPackets.removeSpectator(i))

View File

@@ -0,0 +1,51 @@
from helpers import consoleHelper
from constants import bcolors
from constants import clientPackets
from constants import serverPackets
from constants import exceptions
from objects import glob
from helpers import userHelper
def handle(userToken, packetData):
try:
# Get usertoken data
userID = userToken.userID
username = userToken.username
# Start spectating packet
packetData = clientPackets.startSpectating(packetData)
# Stop spectating old user if needed
if userToken.spectating != 0:
oldTargetToken = glob.tokens.getTokenFromUserID(userToken.spectating)
oldTargetToken.enqueue(serverPackets.removeSpectator(userID))
userToken.stopSpectating()
# Start spectating new user
userToken.startSpectating(packetData["userID"])
# Get host token
targetToken = glob.tokens.getTokenFromUserID(packetData["userID"])
if targetToken == None:
raise exceptions.tokenNotFoundException
# Add us to host's spectators
targetToken.addSpectator(userID)
# Send spectator join packet to host
targetToken.enqueue(serverPackets.addSpectator(userID))
# Join #spectator channel
userToken.enqueue(serverPackets.channelJoinSuccess(userID, "#spectator"))
if len(targetToken.spectators) == 1:
# First spectator, send #spectator join to host too
targetToken.enqueue(serverPackets.channelJoinSuccess(userID, "#spectator"))
# Console output
consoleHelper.printColored("> {} are spectating {}".format(username, userHelper.getUsername(packetData["userID"])), bcolors.PINK)
consoleHelper.printColored("> {}'s spectators: {}".format(str(packetData["userID"]), str(targetToken.spectators)), bcolors.BLUE)
except exceptions.tokenNotFoundException:
# Stop spectating if token not found
consoleHelper.printColored("[!] Spectator start: token not found", bcolors.RED)
userToken.stopSpectating()

View File

@@ -0,0 +1,31 @@
from helpers import consoleHelper
from constants import bcolors
from objects import glob
from constants import serverPackets
from constants import exceptions
def handle(userToken, _):
try:
# get user token data
userID = userToken.userID
username = userToken.username
# Remove our userID from host's spectators
target = userToken.spectating
targetToken = glob.tokens.getTokenFromUserID(target)
if targetToken == None:
raise exceptions.tokenNotFoundException
targetToken.removeSpectator(userID)
# Send the spectator left packet to host
targetToken.enqueue(serverPackets.removeSpectator(userID))
# Console output
# TODO: Move messages in stop spectating
consoleHelper.printColored("> {} are no longer spectating whoever they were spectating".format(username), bcolors.PINK)
consoleHelper.printColored("> {}'s spectators: {}".format(str(target), str(targetToken.spectators)), bcolors.BLUE)
except exceptions.tokenNotFoundException:
consoleHelper.printColored("[!] Spectator stop: token not found", bcolors.RED)
finally:
# Set our spectating user to 0
userToken.stopSpectating()