.BANCHO. pep.py modules
This commit is contained in:
42
objects/banchoConfig.py
Normal file
42
objects/banchoConfig.py
Normal file
@@ -0,0 +1,42 @@
|
||||
from objects import glob
|
||||
from helpers import generalFunctions
|
||||
|
||||
class banchoConfig:
|
||||
"""
|
||||
Class that loads settings from bancho_settings db table
|
||||
"""
|
||||
|
||||
config = {"banchoMaintenance": False, "freeDirect": True, "menuIcon": "", "loginNotification": ""}
|
||||
|
||||
def __init__(self, __loadFromDB = True):
|
||||
"""
|
||||
Initialize a banchoConfig object (and load bancho_settings from db)
|
||||
|
||||
[__loadFromDB -- if True, load values from db. If False, don't load values. Default: True]
|
||||
"""
|
||||
|
||||
if __loadFromDB:
|
||||
try:
|
||||
self.loadSettings()
|
||||
except:
|
||||
raise
|
||||
|
||||
def loadSettings(self):
|
||||
"""
|
||||
(re)load bancho_settings from DB and set values in config array
|
||||
"""
|
||||
|
||||
self.config["banchoMaintenance"] = generalFunctions.stringToBool(glob.db.fetch("SELECT value_int FROM bancho_settings WHERE name = 'bancho_maintenance'")["value_int"])
|
||||
self.config["freeDirect"] = generalFunctions.stringToBool(glob.db.fetch("SELECT value_int FROM bancho_settings WHERE name = 'free_direct'")["value_int"])
|
||||
self.config["menuIcon"] = glob.db.fetch("SELECT value_string FROM bancho_settings WHERE name = 'menu_icon'")["value_string"]
|
||||
self.config["loginNotification"] = glob.db.fetch("SELECT value_string FROM bancho_settings WHERE name = 'login_notification'")["value_string"]
|
||||
|
||||
def setMaintenance(self, __maintenance):
|
||||
"""
|
||||
Turn on/off bancho maintenance mode. Write new value to db too
|
||||
|
||||
__maintenance -- if True, turn on maintenance mode. If false, turn it off
|
||||
"""
|
||||
|
||||
self.config["banchoMaintenance"] = __maintenance
|
||||
glob.db.execute("UPDATE bancho_settings SET value_int = ? WHERE name = 'bancho_maintenance'", [int(__maintenance)])
|
78
objects/channel.py
Normal file
78
objects/channel.py
Normal file
@@ -0,0 +1,78 @@
|
||||
class channel:
|
||||
"""
|
||||
A chat channel
|
||||
|
||||
name -- channel name
|
||||
description -- channel description
|
||||
connectedUsers -- connected users IDs list
|
||||
publicRead -- bool
|
||||
publicWrite -- bool
|
||||
moderated -- bool
|
||||
"""
|
||||
|
||||
name = ""
|
||||
description = ""
|
||||
connectedUsers = []
|
||||
|
||||
publicRead = False
|
||||
publicWrite = False
|
||||
moderated = False
|
||||
|
||||
def __init__(self, __name, __description, __publicRead, __publicWrite):
|
||||
"""
|
||||
Create a new chat channel object
|
||||
|
||||
__name -- channel name
|
||||
__description -- channel description
|
||||
__publicRead -- bool, if true channel can be read by everyone, if false it can be read only by mods/admins
|
||||
__publicWrite -- bool, same as public read but relative to write permissions
|
||||
"""
|
||||
|
||||
self.name = __name
|
||||
self.description = __description
|
||||
self.publicRead = __publicRead
|
||||
self.publicWrite = __publicWrite
|
||||
self.connectedUsers = []
|
||||
|
||||
|
||||
def userJoin(self, __userID):
|
||||
"""
|
||||
Add a user to connected users
|
||||
|
||||
__userID -- user ID that joined the channel
|
||||
"""
|
||||
|
||||
if __userID not in self.connectedUsers:
|
||||
self.connectedUsers.append(__userID)
|
||||
|
||||
|
||||
def userPart(self, __userID):
|
||||
"""
|
||||
Remove a user from connected users
|
||||
|
||||
__userID -- user ID that left the channel
|
||||
"""
|
||||
|
||||
connectedUsers = self.connectedUsers
|
||||
if __userID in connectedUsers:
|
||||
connectedUsers.remove(__userID)
|
||||
|
||||
|
||||
def getConnectedUsers(self):
|
||||
"""
|
||||
Get connected user IDs list
|
||||
|
||||
return -- connectedUsers list
|
||||
"""
|
||||
|
||||
return self.connectedUsers
|
||||
|
||||
|
||||
def getConnectedUsersCount(self):
|
||||
"""
|
||||
Count connected users
|
||||
|
||||
return -- connected users number
|
||||
"""
|
||||
|
||||
return len(self.connectedUsers)
|
40
objects/channelList.py
Normal file
40
objects/channelList.py
Normal file
@@ -0,0 +1,40 @@
|
||||
from objects import glob
|
||||
from objects import channel
|
||||
|
||||
class channelList:
|
||||
"""
|
||||
Channel list
|
||||
|
||||
channels -- dictionary. key: channel name, value: channel object
|
||||
"""
|
||||
|
||||
channels = {}
|
||||
|
||||
|
||||
def loadChannels(self):
|
||||
"""
|
||||
Load chat channels from db and add them to channels dictionary
|
||||
"""
|
||||
|
||||
# Get channels from DB
|
||||
channels = glob.db.fetchAll("SELECT * FROM bancho_channels")
|
||||
|
||||
# Add each channel if needed
|
||||
for i in channels:
|
||||
if i["name"] not in self.channels:
|
||||
publicRead = True if i["public_read"] == 1 else False
|
||||
publicWrite = True if i["public_write"] == 1 else False
|
||||
self.addChannel(i["name"], i["description"], publicRead, publicWrite)
|
||||
|
||||
|
||||
def addChannel(self, __name, __description, __publicRead, __publicWrite):
|
||||
"""
|
||||
Add a channel object to channels dictionary
|
||||
|
||||
__name -- channel name
|
||||
__description -- channel description
|
||||
__publicRead -- bool, if true channel can be read by everyone, if false it can be read only by mods/admins
|
||||
__publicWrite -- bool, same as public read but relative to write permissions
|
||||
"""
|
||||
|
||||
self.channels[__name] = channel.channel(__name, __description, __publicRead, __publicWrite)
|
55
objects/fokabot.py
Normal file
55
objects/fokabot.py
Normal file
@@ -0,0 +1,55 @@
|
||||
"""FokaBot related functions"""
|
||||
from helpers import userHelper
|
||||
from objects import glob
|
||||
from constants import actions
|
||||
from constants import serverPackets
|
||||
from constants import fokabotCommands
|
||||
|
||||
def connect():
|
||||
"""Add FokaBot to connected users and send userpanel/stats packet to everyone"""
|
||||
|
||||
token = glob.tokens.addToken(999)
|
||||
token.actionID = actions.idle
|
||||
glob.tokens.enqueueAll(serverPackets.userPanel(999))
|
||||
glob.tokens.enqueueAll(serverPackets.userStats(999))
|
||||
|
||||
def disconnect():
|
||||
"""Remove FokaBot from connected users"""
|
||||
|
||||
glob.tokens.deleteToken(glob.tokens.getTokenFromUserID(999))
|
||||
|
||||
def fokabotResponse(fro, chan, message):
|
||||
"""
|
||||
Check if a message has triggered fokabot (and return its response)
|
||||
|
||||
fro -- sender username (for permissions stuff with admin commands)
|
||||
chan -- channel name
|
||||
message -- message
|
||||
|
||||
return -- fokabot's response string or False
|
||||
"""
|
||||
|
||||
for i in fokabotCommands.commands:
|
||||
# Loop though all commands
|
||||
if i["trigger"] in message:
|
||||
# message has triggered a command
|
||||
|
||||
# Make sure the user has right permissions
|
||||
if i["minRank"] > 1:
|
||||
# Get rank from db only if minrank > 1, so we save some CPU
|
||||
if userHelper.getRankPrivileges(userHelper.getID(fro)) < i["minRank"]:
|
||||
return False
|
||||
|
||||
# Check argument number
|
||||
message = message.split(" ")
|
||||
if i["syntax"] != "" and len(message) <= len(i["syntax"].split(" ")):
|
||||
return "Wrong syntax: {} {}".format(i["trigger"], i["syntax"])
|
||||
|
||||
# Return response or execute callback
|
||||
if i["callback"] == None:
|
||||
return i["response"]
|
||||
else:
|
||||
return i["callback"](fro, chan, message[1:])
|
||||
|
||||
# No commands triggered
|
||||
return False
|
16
objects/glob.py
Normal file
16
objects/glob.py
Normal file
@@ -0,0 +1,16 @@
|
||||
"""Global objects and variables"""
|
||||
|
||||
from objects import tokenList
|
||||
from objects import channelList
|
||||
from objects import matchList
|
||||
|
||||
VERSION = "0.9"
|
||||
|
||||
db = None
|
||||
conf = None
|
||||
banchoConf = None
|
||||
tokens = tokenList.tokenList()
|
||||
channels = channelList.channelList()
|
||||
matches = matchList.matchList()
|
||||
memes = True
|
||||
restarting = False
|
656
objects/match.py
Normal file
656
objects/match.py
Normal file
@@ -0,0 +1,656 @@
|
||||
# TODO: Enqueue all
|
||||
from constants import gameModes
|
||||
from constants import matchScoringTypes
|
||||
from constants import matchTeamTypes
|
||||
from constants import matchModModes
|
||||
from constants import slotStatuses
|
||||
from objects import glob
|
||||
from helpers import consoleHelper
|
||||
from constants import bcolors
|
||||
from constants import serverPackets
|
||||
from constants import dataTypes
|
||||
from constants import matchTeams
|
||||
|
||||
class match:
|
||||
"""Multiplayer match object"""
|
||||
matchID = 0
|
||||
inProgress = False
|
||||
mods = 0
|
||||
matchName = ""
|
||||
matchPassword = ""
|
||||
beatmapName = ""
|
||||
beatmapID = 0
|
||||
beatmapMD5 = ""
|
||||
slots = [] # list of dictionaries {"status": 0, "team": 0, "userID": -1, "mods": 0, "loaded": False, "skip": False, "complete": False}
|
||||
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
|
||||
|
||||
__matchID -- match progressive identifier
|
||||
__matchName -- match name, string
|
||||
__matchPassword -- match md5 password. Leave empty for no password
|
||||
__beatmapID -- beatmap ID
|
||||
__beatmapName -- beatmap name, string
|
||||
__beatmapMD5 -- beatmap md5 hash, string
|
||||
__gameMode -- game mode ID. See gameModes.py
|
||||
__hostUserID -- user id of the host
|
||||
"""
|
||||
self.matchID = __matchID
|
||||
self.inProgress = False
|
||||
self.mods = 0
|
||||
self.matchName = __matchName
|
||||
self.matchPassword = __matchPassword
|
||||
self.beatmapID = __beatmapID
|
||||
self.beatmapName = __beatmapName
|
||||
self.beatmapMD5 = __beatmapMD5
|
||||
self.hostUserID = __hostUserID
|
||||
self.gameMode = __gameMode
|
||||
self.matchScoringTypes = matchScoringTypes.score # default values
|
||||
self.matchTeamType = matchTeamTypes.headToHead # default value
|
||||
self.matchModMode = matchModModes.normal # default value
|
||||
self.seed = 0
|
||||
|
||||
# Create all slots and reset them
|
||||
self.slots = []
|
||||
for _ in range(0,16):
|
||||
self.slots.append({"status": slotStatuses.free, "team": 0, "userID": -1, "mods": 0, "loaded": False, "skip": False, "complete": False})
|
||||
|
||||
|
||||
def getMatchData(self):
|
||||
"""
|
||||
Return binary match data structure for packetHelper
|
||||
"""
|
||||
# General match info
|
||||
struct = [
|
||||
[self.matchID, dataTypes.uInt16],
|
||||
[int(self.inProgress), dataTypes.byte],
|
||||
[0, dataTypes.byte],
|
||||
[self.mods, dataTypes.uInt32],
|
||||
[self.matchName, dataTypes.string],
|
||||
[self.matchPassword, dataTypes.string],
|
||||
[self.beatmapName, dataTypes.string],
|
||||
[self.beatmapID, dataTypes.uInt32],
|
||||
[self.beatmapMD5, dataTypes.string],
|
||||
]
|
||||
|
||||
# Slots status IDs, always 16 elements
|
||||
for i in range(0,16):
|
||||
struct.append([self.slots[i]["status"], dataTypes.byte])
|
||||
|
||||
# Slot teams, always 16 elements
|
||||
for i in range(0,16):
|
||||
struct.append([self.slots[i]["team"], dataTypes.byte])
|
||||
|
||||
# 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])
|
||||
|
||||
# Other match data
|
||||
struct.extend([
|
||||
[self.hostUserID, dataTypes.sInt32],
|
||||
[self.gameMode, dataTypes.byte],
|
||||
[self.matchScoringType, dataTypes.byte],
|
||||
[self.matchTeamType, dataTypes.byte],
|
||||
[self.matchModMode, dataTypes.byte],
|
||||
])
|
||||
|
||||
# Slot mods if free mod is enabled
|
||||
if self.matchModMode == matchModModes.freeMod:
|
||||
for i in range(0,16):
|
||||
struct.append([self.slots[i]["mods"], dataTypes.uInt32])
|
||||
|
||||
# Seed idk
|
||||
struct.append([self.seed, dataTypes.uInt32])
|
||||
|
||||
return struct
|
||||
|
||||
|
||||
|
||||
def setHost(self, newHost):
|
||||
"""
|
||||
Set room host to newHost and send him host packet
|
||||
|
||||
newHost -- new host userID
|
||||
"""
|
||||
self.hostUserID = newHost
|
||||
|
||||
# Send host packet to new host
|
||||
token = glob.tokens.getTokenFromUserID(newHost)
|
||||
if token != None:
|
||||
token.enqueue(serverPackets.matchTransferHost())
|
||||
|
||||
consoleHelper.printColored("> MPROOM{}: {} is now the host".format(self.matchID, newHost), bcolors.BLUE)
|
||||
|
||||
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
|
||||
|
||||
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 Null is passed, that value won't be edited
|
||||
"""
|
||||
if slotStatus != None:
|
||||
self.slots[slotID]["status"] = slotStatus
|
||||
|
||||
if slotTeam != None:
|
||||
self.slots[slotID]["team"] = slotTeam
|
||||
|
||||
if slotUserID != None:
|
||||
self.slots[slotID]["userID"] = slotUserID
|
||||
|
||||
if slotMods != None:
|
||||
self.slots[slotID]["mods"] = slotMods
|
||||
|
||||
if slotLoaded != None:
|
||||
self.slots[slotID]["loaded"] = slotLoaded
|
||||
|
||||
if slotSkip != None:
|
||||
self.slots[slotID]["skip"] = slotSkip
|
||||
|
||||
if slotComplete != None:
|
||||
self.slots[slotID]["complete"] = slotComplete
|
||||
|
||||
|
||||
def setSlotMods(self, slotID, mods):
|
||||
"""
|
||||
Set slotID mods. Same as calling setSlot and then sendUpdate
|
||||
|
||||
slotID -- slot number
|
||||
mods -- new mods
|
||||
"""
|
||||
# Set new slot data and send update
|
||||
self.setSlot(slotID, None, None, None, mods)
|
||||
self.sendUpdate()
|
||||
consoleHelper.printColored("> MPROOM{}: Slot{} mods changed to {}".format(self.matchID, slotID, mods), bcolors.BLUE)
|
||||
|
||||
|
||||
def toggleSlotReady(self, slotID):
|
||||
"""
|
||||
Switch slotID ready/not ready status
|
||||
Same as calling setSlot and then sendUpdate
|
||||
|
||||
slotID -- slot number
|
||||
"""
|
||||
# Update ready status and setnd update
|
||||
oldStatus = self.slots[slotID]["status"]
|
||||
if oldStatus == slotStatuses.ready:
|
||||
newStatus = slotStatuses.notReady
|
||||
else:
|
||||
newStatus = slotStatuses.ready
|
||||
self.setSlot(slotID, newStatus, None, None, None)
|
||||
self.sendUpdate()
|
||||
consoleHelper.printColored("> MPROOM{}: Slot{} changed ready status to {}".format(self.matchID, slotID, self.slots[slotID]["status"]), bcolors.BLUE)
|
||||
|
||||
def toggleSlotLock(self, slotID):
|
||||
"""
|
||||
Lock a slot
|
||||
Same as calling setSlot and then sendUpdate
|
||||
|
||||
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
|
||||
|
||||
# Set new slot status
|
||||
self.setSlot(slotID, newStatus, 0, -1, 0)
|
||||
if token != 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()
|
||||
consoleHelper.printColored("> MPROOM{}: Slot{} {}".format(self.matchID, slotID, "locked" if newStatus == slotStatuses.locked else "unlocked"), bcolors.BLUE)
|
||||
|
||||
def playerLoaded(self, userID):
|
||||
"""
|
||||
Set a player loaded status to True
|
||||
|
||||
userID -- ID of user
|
||||
"""
|
||||
slotID = self.getUserSlotID(userID)
|
||||
if slotID == None:
|
||||
return
|
||||
|
||||
# Set loaded to True
|
||||
self.slots[slotID]["loaded"] = True
|
||||
consoleHelper.printColored("> MPROOM{}: User {} loaded".format(self.matchID, userID), bcolors.BLUE)
|
||||
|
||||
# Check all loaded
|
||||
total = 0
|
||||
loaded = 0
|
||||
for i in range(0,16):
|
||||
if self.slots[i]["status"] == slotStatuses.playing:
|
||||
total+=1
|
||||
if self.slots[i]["loaded"] == True:
|
||||
loaded+=1
|
||||
|
||||
if total == loaded:
|
||||
self.allPlayersLoaded()
|
||||
|
||||
|
||||
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 != None:
|
||||
token.enqueue(serverPackets.allPlayersLoaded())
|
||||
|
||||
consoleHelper.printColored("> MPROOM{}: All players loaded! Corrispondere iniziare in 3...".format(self.matchID), bcolors.BLUE)
|
||||
|
||||
|
||||
def playerSkip(self, userID):
|
||||
"""
|
||||
Set a player skip status to True
|
||||
|
||||
userID -- ID of user
|
||||
"""
|
||||
slotID = self.getUserSlotID(userID)
|
||||
if slotID == None:
|
||||
return
|
||||
|
||||
# Set skip to True
|
||||
self.slots[slotID]["skip"] = True
|
||||
consoleHelper.printColored("> MPROOM{}: User {} skipped".format(self.matchID, userID), bcolors.BLUE)
|
||||
|
||||
# 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 and uid > -1:
|
||||
token = glob.tokens.getTokenFromUserID(uid)
|
||||
if token != None:
|
||||
print("Enqueueueue {}".format(uid))
|
||||
token.enqueue(serverPackets.playerSkipped(uid))
|
||||
|
||||
# Check all skipped
|
||||
total = 0
|
||||
skipped = 0
|
||||
for i in range(0,16):
|
||||
if self.slots[i]["status"] == slotStatuses.playing:
|
||||
total+=1
|
||||
if self.slots[i]["skip"] == True:
|
||||
skipped+=1
|
||||
|
||||
if total == skipped:
|
||||
self.allPlayersSkipped()
|
||||
|
||||
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 != None:
|
||||
token.enqueue(serverPackets.allPlayersSkipped())
|
||||
|
||||
consoleHelper.printColored("> MPROOM{}: All players skipped!".format(self.matchID), bcolors.BLUE)
|
||||
|
||||
def playerCompleted(self, userID):
|
||||
"""
|
||||
Set userID's slot completed to True
|
||||
|
||||
userID -- ID of user
|
||||
"""
|
||||
slotID = self.getUserSlotID(userID)
|
||||
if slotID == None:
|
||||
return
|
||||
self.setSlot(slotID, None, None, None, None, None, None, True)
|
||||
|
||||
# Console output
|
||||
consoleHelper.printColored("> MPROOM{}: User {} has completed".format(self.matchID, userID), bcolors.BLUE)
|
||||
|
||||
# Check all completed
|
||||
total = 0
|
||||
completed = 0
|
||||
for i in range(0,16):
|
||||
if self.slots[i]["status"] == slotStatuses.playing:
|
||||
total+=1
|
||||
if self.slots[i]["complete"] == True:
|
||||
completed+=1
|
||||
|
||||
if total == completed:
|
||||
self.allPlayersCompleted()
|
||||
|
||||
def allPlayersCompleted(self):
|
||||
"""Cleanup match stuff and send match end packet to everyone"""
|
||||
|
||||
# Reset inProgress
|
||||
self.inProgress = False
|
||||
|
||||
# Reset slots
|
||||
for i in range(0,16):
|
||||
if self.slots[i]["userID"] > -1 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()
|
||||
|
||||
# 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 != None:
|
||||
token.enqueue(serverPackets.matchComplete())
|
||||
|
||||
# Console output
|
||||
consoleHelper.printColored("> MPROOM{}: Match completed".format(self.matchID), bcolors.BLUE)
|
||||
|
||||
|
||||
|
||||
def getUserSlotID(self, userID):
|
||||
"""
|
||||
Get slot ID occupied by userID
|
||||
|
||||
return -- slot id if found, None if user is not in room
|
||||
"""
|
||||
|
||||
for i in range(0,16):
|
||||
if self.slots[i]["userID"] == userID:
|
||||
return i
|
||||
|
||||
return None
|
||||
|
||||
def userJoin(self, userID):
|
||||
"""
|
||||
Add someone to users in match
|
||||
|
||||
userID -- user id of the user
|
||||
return -- True if join success, False if fail (room is full)
|
||||
"""
|
||||
|
||||
# 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)
|
||||
|
||||
# Send updated match data
|
||||
self.sendUpdate()
|
||||
|
||||
# Console output
|
||||
consoleHelper.printColored("> MPROOM{}: {} joined the room".format(self.matchID, userID), bcolors.BLUE)
|
||||
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def userLeft(self, userID):
|
||||
"""
|
||||
Remove someone from users in match
|
||||
|
||||
userID -- user if of the user
|
||||
"""
|
||||
|
||||
# Make sure the user is in room
|
||||
slotID = self.getUserSlotID(userID)
|
||||
if slotID == None:
|
||||
return
|
||||
|
||||
# Set that slot to free
|
||||
self.setSlot(slotID, slotStatuses.free, 0, -1, 0)
|
||||
|
||||
# Check if everyone left
|
||||
if self.countUsers() == 0:
|
||||
# Dispose match
|
||||
glob.matches.disposeMatch(self.matchID)
|
||||
consoleHelper.printColored("> MPROOM{}: Room disposed".format(self.matchID), bcolors.BLUE)
|
||||
return
|
||||
|
||||
# Check if host left
|
||||
if 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)
|
||||
break
|
||||
|
||||
# Send updated match data
|
||||
self.sendUpdate()
|
||||
|
||||
# Console output
|
||||
consoleHelper.printColored("> MPROOM{}: {} left the room".format(self.matchID, userID), bcolors.BLUE)
|
||||
|
||||
|
||||
def userChangeSlot(self, userID, newSlotID):
|
||||
"""
|
||||
Change userID slot to newSlotID
|
||||
|
||||
userID -- user that changed slot
|
||||
newSlotID -- slot id of new slot
|
||||
"""
|
||||
|
||||
# Make sure the user is in room
|
||||
oldSlotID = self.getUserSlotID(userID)
|
||||
if oldSlotID == None:
|
||||
return
|
||||
|
||||
# Make sure there is no one inside new slot
|
||||
if self.slots[newSlotID]["userID"] > -1:
|
||||
return
|
||||
|
||||
# Get old slot data
|
||||
oldData = self.slots[oldSlotID].copy()
|
||||
|
||||
# Free old slot
|
||||
self.setSlot(oldSlotID, slotStatuses.free, 0, -1, 0)
|
||||
|
||||
# Occupy new slot
|
||||
self.setSlot(newSlotID, oldData["status"], oldData["team"], userID, oldData["mods"])
|
||||
|
||||
# Send updated match data
|
||||
self.sendUpdate()
|
||||
|
||||
# Console output
|
||||
consoleHelper.printColored("> MPROOM{}: {} moved to slot {}".format(self.matchID, userID, newSlotID), bcolors.BLUE)
|
||||
|
||||
def changePassword(self, newPassword):
|
||||
"""
|
||||
Change match password to newPassword
|
||||
|
||||
newPassword -- new password string
|
||||
"""
|
||||
self.matchPassword = newPassword
|
||||
|
||||
# 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 != None:
|
||||
token.enqueue(serverPackets.changeMatchPassword(self.matchPassword))
|
||||
|
||||
# Send new match settings too
|
||||
self.sendUpdate()
|
||||
|
||||
# Console output
|
||||
consoleHelper.printColored("> MPROOM{}: Password changed to {}".format(self.matchID, self.matchPassword), bcolors.BLUE)
|
||||
|
||||
|
||||
def changeMatchMods(self, mods):
|
||||
"""
|
||||
Set match global mods
|
||||
|
||||
mods -- mods bitwise int thing
|
||||
"""
|
||||
# Set new mods and send update
|
||||
self.mods = mods
|
||||
self.sendUpdate()
|
||||
consoleHelper.printColored("> MPROOM{}: Mods changed to {}".format(self.matchID, self.mods), bcolors.BLUE)
|
||||
|
||||
def userHasBeatmap(self, userID, has = True):
|
||||
"""
|
||||
Set no beatmap status for userID
|
||||
|
||||
userID -- ID of user
|
||||
has -- True if has beatmap, false if not
|
||||
"""
|
||||
# Make sure the user is in room
|
||||
slotID = self.getUserSlotID(userID)
|
||||
if slotID == None:
|
||||
return
|
||||
|
||||
# Set slot
|
||||
self.setSlot(slotID, slotStatuses.noMap if not has else slotStatuses.notReady)
|
||||
|
||||
# Send updates
|
||||
self.sendUpdate()
|
||||
|
||||
def transferHost(self, slotID):
|
||||
"""
|
||||
Transfer host to slotID
|
||||
|
||||
slotID -- ID of slot
|
||||
"""
|
||||
# Make sure there is someone in that slot
|
||||
uid = self.slots[slotID]["userID"]
|
||||
if uid == -1:
|
||||
return
|
||||
|
||||
# Transfer host
|
||||
self.setHost(uid)
|
||||
|
||||
# Send updates
|
||||
self.sendUpdate()
|
||||
|
||||
|
||||
def playerFailed(self, userID):
|
||||
"""
|
||||
Send userID's failed packet to everyone in match
|
||||
|
||||
userID -- ID of user
|
||||
"""
|
||||
# Make sure the user is in room
|
||||
slotID = self.getUserSlotID(userID)
|
||||
if slotID == None:
|
||||
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 != None:
|
||||
token.enqueue(serverPackets.playerFailed(slotID))
|
||||
|
||||
# Console output
|
||||
consoleHelper.printColored("> MPROOM{}: {} has failed!".format(self.matchID, userID), bcolors.BLUE)
|
||||
|
||||
|
||||
def invite(self, fro, to):
|
||||
"""
|
||||
Fro invites to in this match.
|
||||
|
||||
fro -- sender userID
|
||||
to -- receiver userID
|
||||
"""
|
||||
|
||||
# Get tokens
|
||||
froToken = glob.tokens.getTokenFromUserID(fro)
|
||||
toToken = glob.tokens.getTokenFromUserID(to)
|
||||
if froToken == None or toToken == None:
|
||||
return
|
||||
|
||||
# FokaBot is too busy
|
||||
if to == 999:
|
||||
froToken.enqueue(serverPackets.sendMessage("FokaBot", froToken.username, "I would love to join your match, but I'm busy keeping ripple up and running. Sorry. Beep Boop."))
|
||||
|
||||
# Send message
|
||||
message = "Come join my multiplayer match: \"[osump://{}/{} {}]\"".format(self.matchID, self.matchPassword.replace(" ", "_"), self.matchName)
|
||||
toToken.enqueue(serverPackets.sendMessage(froToken.username, toToken.username, message))
|
||||
|
||||
|
||||
def countUsers(self):
|
||||
"""
|
||||
Return how many players are in that match
|
||||
|
||||
return -- number of users
|
||||
"""
|
||||
|
||||
c = 0
|
||||
for i in range(0,16):
|
||||
if self.slots[i]["userID"] > -1:
|
||||
c+=1
|
||||
|
||||
return c
|
||||
|
||||
def changeTeam(self, userID):
|
||||
"""
|
||||
Change userID's team
|
||||
|
||||
userID -- id of user
|
||||
"""
|
||||
# Make sure the user is in room
|
||||
slotID = self.getUserSlotID(userID)
|
||||
if slotID == None:
|
||||
return
|
||||
|
||||
# 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()
|
||||
|
||||
|
||||
|
||||
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 != None:
|
||||
token.enqueue(serverPackets.updateMatch(self.matchID))
|
||||
|
||||
# Send to users in lobby
|
||||
for i in glob.matches.usersInLobby:
|
||||
token = glob.tokens.getTokenFromUserID(i)
|
||||
if token != None:
|
||||
token.enqueue(serverPackets.updateMatch(self.matchID))
|
||||
|
||||
def checkTeams(self):
|
||||
"""
|
||||
Check if match teams are valid
|
||||
|
||||
return -- True if valid, False if invalid
|
||||
"""
|
||||
if match.matchTeamType != matchTeamTypes.teamVs or matchTeamTypes != 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 firstTeam == -1:
|
||||
firstTeam = self.slots[i]["team"]
|
||||
elif firstTeam != self.slots[i]["teams"]:
|
||||
consoleHelper.printColored("> MPROOM{}: Teams are valid".format(self.matchID), bcolors.BLUE)
|
||||
return True
|
||||
|
||||
consoleHelper.printColored("> MPROOM{}: Invalid teams!".format(self.matchID), bcolors.RED)
|
||||
return False
|
80
objects/matchList.py
Normal file
80
objects/matchList.py
Normal file
@@ -0,0 +1,80 @@
|
||||
from objects import match
|
||||
from objects import glob
|
||||
from constants import serverPackets
|
||||
|
||||
class matchList:
|
||||
matches = {}
|
||||
usersInLobby = []
|
||||
lastID = 1
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize a matchList object"""
|
||||
self.matches = {}
|
||||
self.usersInLobby = []
|
||||
self.lastID = 1
|
||||
|
||||
def createMatch(self, __matchName, __matchPassword, __beatmapID, __beatmapName, __beatmapMD5, __gameMode, __hostUserID):
|
||||
"""
|
||||
Add a new match to matches list
|
||||
|
||||
__matchName -- match name, string
|
||||
__matchPassword -- match md5 password. Leave empty for no password
|
||||
__beatmapID -- beatmap ID
|
||||
__beatmapName -- beatmap name, string
|
||||
__beatmapMD5 -- beatmap md5 hash, string
|
||||
__gameMode -- game mode ID. See gameModes.py
|
||||
__hostUserID -- user id of who created the match
|
||||
return -- match ID
|
||||
"""
|
||||
# Add a new match to matches list
|
||||
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
|
||||
|
||||
__matchID -- ID of match to dispose
|
||||
"""
|
||||
|
||||
# Make sure the match exists
|
||||
if __matchID not in self.matches:
|
||||
return
|
||||
|
||||
# Remove match object
|
||||
self.matches.pop(__matchID)
|
||||
|
||||
# Send match dispose packet to everyone in lobby
|
||||
for i in self.usersInLobby:
|
||||
token = glob.tokens.getTokenFromUserID(i)
|
||||
if token != None:
|
||||
token.enqueue(serverPackets.disposeMatch(__matchID))
|
227
objects/osuToken.py
Normal file
227
objects/osuToken.py
Normal file
@@ -0,0 +1,227 @@
|
||||
import uuid
|
||||
from constants import actions
|
||||
from constants import gameModes
|
||||
from helpers import userHelper
|
||||
import time
|
||||
from helpers import consoleHelper
|
||||
from constants import bcolors
|
||||
from constants import serverPackets
|
||||
from events import logoutEvent
|
||||
|
||||
class token:
|
||||
"""Osu Token object
|
||||
|
||||
token -- token string
|
||||
userID -- userID associated to that token
|
||||
username -- username relative to userID (cache)
|
||||
rank -- rank (permissions) relative to userID (cache)
|
||||
actionID -- current user action (see actions.py)
|
||||
actionText -- current user action text
|
||||
actionMd5 -- md5 relative to user action
|
||||
actionMods -- current acton mods
|
||||
gameMode -- current user game mode
|
||||
location -- [latitude,longitude]
|
||||
queue -- packets queue
|
||||
joinedChannels -- list. Contains joined channel names
|
||||
spectating -- userID of spectating user. 0 if not spectating.
|
||||
spectators -- list. Contains userIDs of spectators
|
||||
country -- osu country code. Use countryHelper to convert from letter country code to osu country code
|
||||
pingTime -- latest packet received UNIX time
|
||||
loginTime -- login UNIX time
|
||||
"""
|
||||
|
||||
token = ""
|
||||
userID = 0
|
||||
username = ""
|
||||
rank = 0
|
||||
actionID = actions.idle
|
||||
actionText = ""
|
||||
actionMd5 = ""
|
||||
actionMods = 0
|
||||
gameMode = gameModes.std
|
||||
|
||||
country = 0
|
||||
location = [0,0]
|
||||
|
||||
queue = bytes()
|
||||
joinedChannels = []
|
||||
|
||||
spectating = 0
|
||||
spectators = []
|
||||
|
||||
pingTime = 0
|
||||
loginTime = 0
|
||||
|
||||
awayMessage = ""
|
||||
|
||||
matchID = -1
|
||||
|
||||
|
||||
def __init__(self, __userID, __token = None):
|
||||
"""
|
||||
Create a token object and set userID and token
|
||||
|
||||
__userID -- user associated to this token
|
||||
__token -- if passed, set token to that value
|
||||
if not passed, token will be generated
|
||||
"""
|
||||
|
||||
# Set stuff
|
||||
self.userID = __userID
|
||||
self.username = userHelper.getUsername(self.userID)
|
||||
self.rank = userHelper.getRankPrivileges(self.userID)
|
||||
self.loginTime = int(time.time())
|
||||
self.pingTime = self.loginTime
|
||||
|
||||
# Default variables
|
||||
self.spectators = []
|
||||
self.spectating = 0
|
||||
self.location = [0,0]
|
||||
self.joinedChannels = []
|
||||
self.actionID = actions.idle
|
||||
self.actionText = ""
|
||||
self.actionMods = 0
|
||||
self.gameMode = gameModes.std
|
||||
self.awayMessage = ""
|
||||
self.matchID = -1
|
||||
|
||||
# Generate/set token
|
||||
if __token != None:
|
||||
self.token = __token
|
||||
else:
|
||||
self.token = str(uuid.uuid4())
|
||||
|
||||
|
||||
def enqueue(self, __bytes):
|
||||
"""
|
||||
Add bytes (packets) to queue
|
||||
|
||||
__bytes -- (packet) bytes to enqueue
|
||||
"""
|
||||
|
||||
self.queue += __bytes
|
||||
|
||||
|
||||
def resetQueue(self):
|
||||
"""Resets the queue. Call when enqueued packets have been sent"""
|
||||
self.queue = bytes()
|
||||
|
||||
|
||||
def joinChannel(self, __channel):
|
||||
"""Add __channel to joined channels list
|
||||
|
||||
__channel -- channel name"""
|
||||
|
||||
if __channel not in self.joinedChannels:
|
||||
self.joinedChannels.append(__channel)
|
||||
|
||||
|
||||
def partChannel(self, __channel):
|
||||
"""Remove __channel from joined channels list
|
||||
|
||||
__channel -- channel name"""
|
||||
|
||||
if __channel in self.joinedChannels:
|
||||
self.joinedChannels.remove(__channel)
|
||||
|
||||
|
||||
def setLocation(self, __location):
|
||||
"""Set location (latitude and longitude)
|
||||
|
||||
__location -- [latitude, longitude]"""
|
||||
|
||||
self.location = __location
|
||||
|
||||
|
||||
def getLatitude(self):
|
||||
"""Get latitude
|
||||
|
||||
return -- latitude"""
|
||||
|
||||
return self.location[0]
|
||||
|
||||
|
||||
def getLongitude(self):
|
||||
"""Get longitude
|
||||
|
||||
return -- longitude"""
|
||||
return self.location[1]
|
||||
|
||||
|
||||
def startSpectating(self, __userID):
|
||||
"""Set the spectating user to __userID
|
||||
|
||||
__userID -- target userID"""
|
||||
self.spectating = __userID
|
||||
|
||||
|
||||
def stopSpectating(self):
|
||||
"""Set the spectating user to 0, aka no user"""
|
||||
self.spectating = 0
|
||||
|
||||
|
||||
def addSpectator(self, __userID):
|
||||
"""Add __userID to our spectators
|
||||
|
||||
userID -- new spectator userID"""
|
||||
|
||||
# Add userID to spectators if not already in
|
||||
if __userID not in self.spectators:
|
||||
self.spectators.append(__userID)
|
||||
|
||||
|
||||
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
|
||||
|
||||
__countryID -- numeric country ID. See countryHelper.py"""
|
||||
|
||||
self.country = __countryID
|
||||
|
||||
|
||||
def getCountry(self):
|
||||
"""Get numeric country ID
|
||||
|
||||
return -- numeric country ID. See countryHelper.py"""
|
||||
|
||||
return self.country
|
||||
|
||||
|
||||
def updatePingTime(self):
|
||||
"""Update latest ping time"""
|
||||
self.pingTime = int(time.time())
|
||||
|
||||
def setAwayMessage(self, __awayMessage):
|
||||
"""Set a new away message"""
|
||||
self.awayMessage = __awayMessage
|
||||
|
||||
def joinMatch(self, __matchID):
|
||||
"""
|
||||
Set match to matchID
|
||||
|
||||
__matchID -- new match ID
|
||||
"""
|
||||
self.matchID = __matchID
|
||||
|
||||
def partMatch(self):
|
||||
"""Set match to -1"""
|
||||
self.matchID = -1
|
||||
|
||||
def kick(self):
|
||||
"""Kick this user from the server"""
|
||||
# Send packet to target
|
||||
consoleHelper.printColored("> {} has been disconnected. (kick)".format(self.username), bcolors.YELLOW)
|
||||
self.enqueue(serverPackets.notification("You have been kicked from the server. Please login again."))
|
||||
self.enqueue(serverPackets.loginFailed())
|
||||
|
||||
# Logout event
|
||||
logoutEvent.handle(self, None)
|
165
objects/tokenList.py
Normal file
165
objects/tokenList.py
Normal file
@@ -0,0 +1,165 @@
|
||||
from objects import osuToken
|
||||
import time
|
||||
import threading
|
||||
from events import logoutEvent
|
||||
|
||||
class tokenList:
|
||||
"""
|
||||
List of connected osu tokens
|
||||
|
||||
tokens -- dictionary. key: token string, value: token object
|
||||
"""
|
||||
|
||||
tokens = {}
|
||||
|
||||
def addToken(self, __userID):
|
||||
"""
|
||||
Add a token object to tokens list
|
||||
|
||||
__userID -- user id associated to that token
|
||||
return -- token object
|
||||
"""
|
||||
|
||||
newToken = osuToken.token(__userID)
|
||||
self.tokens[newToken.token] = newToken
|
||||
return newToken
|
||||
|
||||
def deleteToken(self, __token):
|
||||
"""
|
||||
Delete a token from token list if it exists
|
||||
|
||||
__token -- token string
|
||||
"""
|
||||
|
||||
if __token in self.tokens:
|
||||
self.tokens.pop(__token)
|
||||
|
||||
|
||||
def getUserIDFromToken(self, __token):
|
||||
"""
|
||||
Get user ID from a token
|
||||
|
||||
__token -- token to find
|
||||
|
||||
return: false if not found, userID if found
|
||||
"""
|
||||
|
||||
# Make sure the token exists
|
||||
if __token not in self.tokens:
|
||||
return False
|
||||
|
||||
# Get userID associated to that token
|
||||
return self.tokens[__token].userID
|
||||
|
||||
|
||||
def getTokenFromUserID(self, __userID):
|
||||
"""
|
||||
Get token from a user ID
|
||||
|
||||
__userID -- user ID to find
|
||||
return -- False if not found, token object if found
|
||||
"""
|
||||
|
||||
# Make sure the token exists
|
||||
for _, value in self.tokens.items():
|
||||
if value.userID == __userID:
|
||||
return value
|
||||
|
||||
# Return none if not found
|
||||
return None
|
||||
|
||||
|
||||
def getTokenFromUsername(self, __username):
|
||||
"""
|
||||
Get token from a username
|
||||
|
||||
__username -- username to find
|
||||
return -- False if not found, token object if found
|
||||
"""
|
||||
|
||||
# lowercase
|
||||
who = __username.lower()
|
||||
|
||||
# Make sure the token exists
|
||||
for _, value in self.tokens.items():
|
||||
if value.username.lower() == who:
|
||||
return value
|
||||
|
||||
# Return none if not found
|
||||
return None
|
||||
|
||||
|
||||
def deleteOldTokens(self, __userID):
|
||||
"""
|
||||
Delete old userID's tokens if found
|
||||
|
||||
__userID -- tokens associated to this user will be deleted
|
||||
"""
|
||||
|
||||
# Delete older tokens
|
||||
for key, value in self.tokens.items():
|
||||
if value.userID == __userID:
|
||||
# Delete this token from the dictionary
|
||||
self.tokens.pop(key)
|
||||
|
||||
# break or items() function throws errors
|
||||
break
|
||||
|
||||
|
||||
def multipleEnqueue(self, __packet, __who, __but = False):
|
||||
"""
|
||||
Enqueue a packet to multiple users
|
||||
|
||||
__packet -- packet bytes to enqueue
|
||||
__who -- userIDs array
|
||||
__but -- if True, enqueue to everyone but users in __who array
|
||||
"""
|
||||
|
||||
for _, value in self.tokens.items():
|
||||
shouldEnqueue = False
|
||||
if value.userID in __who and not __but:
|
||||
shouldEnqueue = True
|
||||
elif value.userID not in __who and __but:
|
||||
shouldEnqueue = True
|
||||
|
||||
if shouldEnqueue:
|
||||
value.enqueue(__packet)
|
||||
|
||||
|
||||
|
||||
def enqueueAll(self, __packet):
|
||||
"""
|
||||
Enqueue packet(s) to every connected user
|
||||
|
||||
__packet -- packet bytes to enqueue
|
||||
"""
|
||||
|
||||
for _, value in self.tokens.items():
|
||||
value.enqueue(__packet)
|
||||
|
||||
def usersTimeoutCheckLoop(self, __timeoutTime = 100, __checkTime = 100):
|
||||
"""
|
||||
Deletes all timed out users.
|
||||
If called once, will recall after __checkTime seconds and so on, forever
|
||||
CALL THIS FUNCTION ONLY ONCE!
|
||||
|
||||
__timeoutTime - seconds of inactivity required to disconnect someone (Default: 100)
|
||||
__checkTime - seconds between loops (Default: 100)
|
||||
"""
|
||||
|
||||
timedOutTokens = [] # timed out users
|
||||
timeoutLimit = time.time()-__timeoutTime
|
||||
for key, value in self.tokens.items():
|
||||
# Check timeout (fokabot is ignored)
|
||||
if value.pingTime < timeoutLimit and value.userID != 999:
|
||||
# That user has timed out, add to disconnected tokens
|
||||
# We can't delete it while iterating or items() throws an error
|
||||
timedOutTokens.append(key)
|
||||
|
||||
# Delete timed out users from self.tokens
|
||||
# i is token string (dictionary key)
|
||||
for i in timedOutTokens:
|
||||
logoutEvent.handle(self.tokens[i], None)
|
||||
|
||||
# Schedule a new check (endless loop)
|
||||
threading.Timer(__checkTime, self.usersTimeoutCheckLoop, [__timeoutTime, __checkTime]).start()
|
Reference in New Issue
Block a user