I knew a threaded bancho server was going to be a bad idea...

This commit is contained in:
Giuseppe Guerra 2017-12-21 18:58:56 +01:00
parent 050c1d5fe8
commit e63a85e4a4
20 changed files with 200 additions and 219 deletions

View File

@ -15,29 +15,29 @@ def handle(userToken, packetData):
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.FREE_MOD:
# 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.changeMods(mods.DOUBLETIME)
# Nightcore
if (packetData["mods"] & mods.NIGHTCORE) > 0:
match.changeMods(match.mods + mods.NIGHTCORE)
elif (packetData["mods"] & mods.HALFTIME) > 0:
match.changeMods(mods.HALFTIME)
else:
# No DT/HT, set global mods to 0 (we are in freemod mode)
match.changeMods(0)
with glob.matches.matches[matchID] as match:
if match.matchModMode == matchModModes.FREE_MOD:
# 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.changeMods(mods.DOUBLETIME)
# Nightcore
if (packetData["mods"] & mods.NIGHTCORE) > 0:
match.changeMods(match.mods + mods.NIGHTCORE)
elif (packetData["mods"] & mods.HALFTIME) > 0:
match.changeMods(mods.HALFTIME)
else:
# No DT/HT, set global mods to 0 (we are in freemod mode)
match.changeMods(0)
# Set slot mods
slotID = match.getUserSlotID(userID)
if slotID is not None:
match.setSlotMods(slotID, packetData["mods"])
else:
# Not freemod, set match mods
match.changeMods(packetData["mods"])
# Set slot mods
slotID = match.getUserSlotID(userID)
if slotID is not None:
match.setSlotMods(slotID, packetData["mods"])
else:
# Not freemod, set match mods
match.changeMods(packetData["mods"])

View File

@ -10,12 +10,10 @@ def handle(userToken, packetData):
if matchID not in glob.matches.matches:
return
# Get our match
match = glob.matches.matches[matchID]
with glob.matches.matches[matchID] as match:
# Host check
if userToken.userID != match.hostUserID:
return
# Host check
if userToken.userID != match.hostUserID:
return
# Update match password
match.changePassword(packetData["matchPassword"])
# Update match password
match.changePassword(packetData["matchPassword"])

View File

@ -21,86 +21,84 @@ def handle(userToken, packetData):
if matchID not in glob.matches.matches:
return
# Get match object
match = glob.matches.matches[matchID]
# Host check
if userToken.userID != match.hostUserID:
return
with glob.matches.matches[matchID] as match:
if userToken.userID != match.hostUserID:
return
# 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"
]
# 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)
# Set match name
match.matchName = packetData["matchName"] if packetData["matchName"] != "meme" else random.choice(memeTitles)
# Update match settings
match.inProgress = packetData["inProgress"]
if packetData["matchPassword"] != "":
match.matchPassword = generalUtils.stringMd5(packetData["matchPassword"])
else:
match.matchPassword = ""
match.beatmapName = packetData["beatmapName"]
match.beatmapID = packetData["beatmapID"]
match.hostUserID = packetData["hostUserID"]
match.gameMode = packetData["gameMode"]
# Update match settings
match.inProgress = packetData["inProgress"]
if packetData["matchPassword"] != "":
match.matchPassword = generalUtils.stringMd5(packetData["matchPassword"])
else:
match.matchPassword = ""
match.beatmapName = packetData["beatmapName"]
match.beatmapID = packetData["beatmapID"]
match.hostUserID = packetData["hostUserID"]
match.gameMode = packetData["gameMode"]
oldBeatmapMD5 = match.beatmapMD5
oldMods = match.mods
oldMatchTeamType = match.matchTeamType
oldBeatmapMD5 = match.beatmapMD5
oldMods = match.mods
oldMatchTeamType = match.matchTeamType
match.mods = packetData["mods"]
match.beatmapMD5 = packetData["beatmapMD5"]
match.matchScoringType = packetData["scoringType"]
match.matchTeamType = packetData["teamType"]
match.matchModMode = packetData["freeMods"]
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:
match.resetReady()
# Reset ready if needed
if oldMods != match.mods or oldBeatmapMD5 != match.beatmapMD5:
match.resetReady()
# Reset mods if needed
if match.matchModMode == matchModModes.NORMAL:
# Reset slot mods if not freeMods
match.resetMods()
else:
# Reset match mods if freemod
match.mods = 0
# Reset mods if needed
if match.matchModMode == matchModModes.NORMAL:
# Reset slot mods if not freeMods
match.resetMods()
else:
# Reset match mods if freemod
match.mods = 0
# Initialize teams if team type changed
if match.matchTeamType != oldMatchTeamType:
match.initializeTeams()
# Initialize teams if team type changed
if match.matchTeamType != oldMatchTeamType:
match.initializeTeams()
# Force no freemods if tag coop
if match.matchTeamType == matchTeamTypes.TAG_COOP or match.matchTeamType == matchTeamTypes.TAG_TEAM_VS:
match.matchModMode = matchModModes.NORMAL
# Force no freemods if tag coop
if match.matchTeamType == matchTeamTypes.TAG_COOP or match.matchTeamType == matchTeamTypes.TAG_TEAM_VS:
match.matchModMode = matchModModes.NORMAL
# Send updated settings
match.sendUpdates()
# Send updated settings
match.sendUpdates()
# Console output
log.info("MPROOM{}: Updated room settings".format(match.matchID))
# Console output
log.info("MPROOM{}: Updated room settings".format(match.matchID))

View File

@ -8,8 +8,6 @@ def handle(userToken, packetData):
# Read packet data
packetData = clientPackets.changeSlot(packetData)
# Get match
match = glob.matches.matches[userToken.matchID]
# Change slot
match.userChangeSlot(userID, packetData["slotID"])
with glob.matches.matches[userToken.matchID] as match:
# Change slot
match.userChangeSlot(userID, packetData["slotID"])

View File

@ -20,15 +20,13 @@ def handle(userToken, packetData):
if matchID not in glob.matches.matches:
raise exceptions.matchCreateError()
# Get match object
match = glob.matches.matches[matchID]
with glob.matches.matches[matchID] as match:
# Join that match
userToken.joinMatch(matchID)
# Join that match
userToken.joinMatch(matchID)
# Give host to match creator
match.setHost(userID)
match.sendUpdates()
match.changePassword(packetData["matchPassword"])
# Give host to match creator
match.setHost(userID)
match.sendUpdates()
match.changePassword(packetData["matchPassword"])
except exceptions.matchCreateError:
log.error("Error while creating match!")

View File

@ -17,19 +17,17 @@ def handle(userToken, packetData):
if matchID not in glob.matches.matches:
return
# Match exists, get object
match = glob.matches.matches[matchID]
# Hash password if needed
#if password != "":
# if password != "":
# password = generalUtils.stringMd5(password)
# Check password
if match.matchPassword != "" and match.matchPassword != password:
raise exceptions.matchWrongPasswordException()
with glob.matches.matches[matchID] as match:
if match.matchPassword != "" and match.matchPassword != password:
raise exceptions.matchWrongPasswordException()
# Password is correct, join match
userToken.joinMatch(matchID)
# Password is correct, join match
userToken.joinMatch(matchID)
except exceptions.matchWrongPasswordException:
userToken.enqueue(serverPackets.matchJoinFail())
log.warning("{} has tried to join a mp room, but he typed the wrong password".format(userToken.username))

View File

@ -15,8 +15,6 @@ def handle(userToken, _, has):
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)
with glob.matches.matches[matchID] as match:
match.userHasBeatmap(userID, has)

View File

@ -15,8 +15,6 @@ def handle(userToken, _):
if matchID not in glob.matches.matches:
return
# Get match object
match = glob.matches.matches[matchID]
# Change team
match.changeTeam(userID)
with glob.matches.matches[matchID] as match:
match.changeTeam(userID)

View File

@ -15,8 +15,6 @@ def handle(userToken, _):
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)
with glob.matches.matches[matchID] as match:
match.playerCompleted(userID)

View File

@ -15,8 +15,6 @@ def handle(userToken, _):
if matchID not in glob.matches.matches:
return
# Match exists, get object
match = glob.matches.matches[matchID]
# Fail user
match.playerFailed(userID)
with glob.matches.matches[matchID] as match:
match.playerFailed(userID)

View File

@ -16,18 +16,16 @@ def handle(userToken, packetData):
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)
# Parse the data
data = clientPackets.matchFrames(packetData)
# Update the score
match.updateScore(slotID, data["totalScore"])
match.updateHP(slotID, data["currentHp"])
with glob.matches.matches[matchID] as match:
# Change slot id in packetData
slotID = match.getUserSlotID(userID)
# Enqueue frames to who's playing
glob.streams.broadcast(match.playingStreamName, serverPackets.matchFrames(slotID, packetData))
# Update the score
match.updateScore(slotID, data["totalScore"])
match.updateHP(slotID, data["currentHp"])
# Enqueue frames to who's playing
glob.streams.broadcast(match.playingStreamName, serverPackets.matchFrames(slotID, packetData))

View File

@ -17,8 +17,6 @@ def handle(userToken, packetData):
if matchID not in glob.matches.matches:
return
# Get match object
match = glob.matches.matches[matchID]
# Send invite
match.invite(userID, packetData["userID"])
with glob.matches.matches[matchID] as match:
match.invite(userID, packetData["userID"])

View File

@ -12,16 +12,16 @@ def handle(userToken, packetData):
matchID = userToken.matchID
if matchID not in glob.matches.matches:
return
match = glob.matches.matches[matchID]
# Host check
if userID != match.hostUserID:
return
with glob.matches.matches[matchID] as match:
# Host check
if userID != match.hostUserID:
return
# Make sure we aren't locking our slot
ourSlot = match.getUserSlotID(userID)
if packetData["slotID"] == ourSlot:
return
# Make sure we aren't locking our slot
ourSlot = match.getUserSlotID(userID)
if packetData["slotID"] == ourSlot:
return
# Lock/Unlock slot
match.toggleSlotLocked(packetData["slotID"])
# Lock/Unlock slot
match.toggleSlotLocked(packetData["slotID"])

View File

@ -15,8 +15,6 @@ def handle(userToken, _):
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)
with glob.matches.matches[matchID] as match:
match.playerLoaded(userID)

View File

@ -8,14 +8,14 @@ def handle(userToken, _):
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 is not None:
match.toggleSlotReady(slotID)
with glob.matches.matches[matchID] as match:
# Get our slotID and change ready status
slotID = match.getUserSlotID(userID)
if slotID is not None:
match.toggleSlotReady(slotID)
# If this is a tournament match, we should send the current status of ready
# players.
if match.isTourney:
match.sendReadyStatus()
# If this is a tournament match, we should send the current status of ready
# players.
if match.isTourney:
match.sendReadyStatus()

View File

@ -15,8 +15,6 @@ def handle(userToken, _):
if matchID not in glob.matches.matches:
return
# The match exists, get object
match = glob.matches.matches[matchID]
# Skip
match.playerSkip(userID)
with glob.matches.matches[matchID] as match:
match.playerSkip(userID)

View File

@ -13,11 +13,9 @@ def handle(userToken, _):
if matchID not in glob.matches.matches:
return
# The match exists, get object
match = glob.matches.matches[matchID]
with glob.matches.matches[matchID] as match:
# Host check
if userToken.userID != match.hostUserID:
return
# Host check
if userToken.userID != match.hostUserID:
return
match.start()
match.start()

View File

@ -16,12 +16,10 @@ def handle(userToken, packetData):
if matchID not in glob.matches.matches:
return
# Match exists, get object
match = glob.matches.matches[matchID]
# Host check
if userToken.userID != match.hostUserID:
return
with glob.matches.matches[matchID] as match:
if userToken.userID != match.hostUserID:
return
# Transfer host
match.transferHost(packetData["slotID"])
# Transfer host
match.transferHost(packetData["slotID"])

View File

@ -6,4 +6,5 @@ def handle(userToken, packetData):
matchID = packetData["matchID"]
if matchID not in glob.matches.matches or not userToken.tournament:
return
userToken.enqueue(glob.matches.matches[matchID].matchDataCache)
with glob.matches.matches[matchID] as m:
userToken.enqueue(m.matchDataCache)

View File

@ -1,5 +1,6 @@
import copy
import json
import threading
from common.log import logUtils as log
from constants import dataTypes
from constants import matchModModes
@ -60,6 +61,7 @@ class match:
self.isTourney = isTourney
self.isLocked = False # if True, users can't change slots/teams. Used in tourney matches
self.isStarting = False
self._lock = threading.Lock()
# Create all slots and reset them
self.slots = []
@ -83,55 +85,55 @@ class match:
"""
# General match info
# TODO: Test without safe copy, the error might have been caused by outdated python bytecode cache
safeMatch = copy.deepcopy(self)
# safeMatch = copy.deepcopy(self)
struct = [
[safeMatch.matchID, dataTypes.UINT16],
[int(safeMatch.inProgress), dataTypes.BYTE],
[self.matchID, dataTypes.UINT16],
[int(self.inProgress), dataTypes.BYTE],
[0, dataTypes.BYTE],
[safeMatch.mods, dataTypes.UINT32],
[safeMatch.matchName, dataTypes.STRING]
[self.mods, dataTypes.UINT32],
[self.matchName, dataTypes.STRING]
]
if censored and safeMatch.matchPassword:
if censored and self.matchPassword:
struct.append(["redacted", dataTypes.STRING])
else:
struct.append([safeMatch.matchPassword, dataTypes.STRING])
struct.append([self.matchPassword, dataTypes.STRING])
struct.extend([
[safeMatch.beatmapName, dataTypes.STRING],
[safeMatch.beatmapID, dataTypes.UINT32],
[safeMatch.beatmapMD5, 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([safeMatch.slots[i].status, dataTypes.BYTE])
struct.append([self.slots[i].status, dataTypes.BYTE])
# Slot teams, always 16 elements
for i in range(0,16):
struct.append([safeMatch.slots[i].team, dataTypes.BYTE])
struct.append([self.slots[i].team, dataTypes.BYTE])
# Slot user ID. Write only if slot is occupied
for i in range(0,16):
if safeMatch.slots[i].user is not None and safeMatch.slots[i].user in glob.tokens.tokens:
struct.append([glob.tokens.tokens[safeMatch.slots[i].user].userID, dataTypes.UINT32])
if self.slots[i].user is not None and self.slots[i].user in glob.tokens.tokens:
struct.append([glob.tokens.tokens[self.slots[i].user].userID, dataTypes.UINT32])
# Other match data
struct.extend([
[safeMatch.hostUserID, dataTypes.SINT32],
[safeMatch.gameMode, dataTypes.BYTE],
[safeMatch.matchScoringType, dataTypes.BYTE],
[safeMatch.matchTeamType, dataTypes.BYTE],
[safeMatch.matchModMode, dataTypes.BYTE],
[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 safeMatch.matchModMode == matchModModes.FREE_MOD:
if self.matchModMode == matchModModes.FREE_MOD:
for i in range(0,16):
struct.append([safeMatch.slots[i].mods, dataTypes.UINT32])
struct.append([self.slots[i].mods, dataTypes.UINT32])
# Seed idk
# TODO: Implement this, it should be used for mania "random" mod
struct.append([safeMatch.seed, dataTypes.UINT32])
struct.append([self.seed, dataTypes.UINT32])
return struct
@ -854,3 +856,11 @@ class match:
message = "The match is now empty."
chat.sendMessage("FokaBot", chanName, message)
def __enter__(self):
# 🌚🌚🌚🌚🌚
self._lock.acquire()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self._lock.release()