better matchmaking
This commit is contained in:
parent
972d438bdf
commit
181686189c
@ -110,7 +110,6 @@ class ConnectionHandler(object):
|
|||||||
del(self.open_connections_by_id[conn.id])
|
del(self.open_connections_by_id[conn.id])
|
||||||
del(self.open_connections_by_user[conn.user_name])
|
del(self.open_connections_by_user[conn.user_name])
|
||||||
|
|
||||||
|
|
||||||
async def new_connection(self,
|
async def new_connection(self,
|
||||||
socket: websockets.WebSocketServerProtocol,
|
socket: websockets.WebSocketServerProtocol,
|
||||||
login_msg: str):
|
login_msg: str):
|
||||||
@ -167,8 +166,6 @@ class ConnectionHandler(object):
|
|||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return conn
|
return conn
|
||||||
|
|
||||||
await socket.send(json.dumps({
|
await socket.send(json.dumps({
|
||||||
@ -269,7 +266,38 @@ class ConnectionHandler(object):
|
|||||||
)
|
)
|
||||||
|
|
||||||
async def _on_match_req(self, conn, data):
|
async def _on_match_req(self, conn, data):
|
||||||
|
n_open_matches = len(
|
||||||
|
self.match_manager.get_matches_for_user(conn.user_name))
|
||||||
|
|
||||||
|
if n_open_matches >= 5:
|
||||||
|
await conn.websocket.send(
|
||||||
|
json.dumps(
|
||||||
|
{
|
||||||
|
"type": "match_request_response",
|
||||||
|
"data": {
|
||||||
|
"success": False,
|
||||||
|
"msg": "you have too many active matches to search for a new one"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
if data['player'] is None:
|
if data['player'] is None:
|
||||||
|
if conn.user_name in self.match_queue:
|
||||||
|
await conn.websocket.send(
|
||||||
|
json.dumps(
|
||||||
|
{
|
||||||
|
"type": "match_request_response",
|
||||||
|
"data": {
|
||||||
|
"success": False,
|
||||||
|
"msg": "you are already searching for a random match"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
if len(self.match_queue) > 0:
|
if len(self.match_queue) > 0:
|
||||||
# it's a match!
|
# it's a match!
|
||||||
user_a = self.match_queue.pop()
|
user_a = self.match_queue.pop()
|
||||||
@ -293,6 +321,19 @@ class ConnectionHandler(object):
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
opponent = data['player']
|
opponent = data['player']
|
||||||
|
if opponent == conn.user_name:
|
||||||
|
await conn.websocket.send(
|
||||||
|
json.dumps(
|
||||||
|
{
|
||||||
|
"type": "match_request_response",
|
||||||
|
"data": {
|
||||||
|
"success": False,
|
||||||
|
"msg": "you cannot play against yourself"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return
|
||||||
try:
|
try:
|
||||||
if len(opponent) <= 16 and '\'' not in opponent and '"' not in opponent:
|
if len(opponent) <= 16 and '\'' not in opponent and '"' not in opponent:
|
||||||
if len(self.user_manager.get_user(opponent)) > 0:
|
if len(self.user_manager.get_user(opponent)) > 0:
|
||||||
@ -322,7 +363,6 @@ class ConnectionHandler(object):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print("error processing match request: " + str(data) + str(e))
|
print("error processing match request: " + str(data) + str(e))
|
||||||
|
|
||||||
|
185
game_manager.py
185
game_manager.py
@ -1,185 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import asyncio
|
|
||||||
import websockets
|
|
||||||
import json
|
|
||||||
|
|
||||||
player_id_queue = set()
|
|
||||||
sockets = {}
|
|
||||||
|
|
||||||
player_games = {}
|
|
||||||
|
|
||||||
|
|
||||||
async def register_user(id, socket):
|
|
||||||
|
|
||||||
if id in player_id_queue or id in player_games:
|
|
||||||
return False
|
|
||||||
|
|
||||||
player_id_queue.add(id)
|
|
||||||
sockets[id] = socket
|
|
||||||
|
|
||||||
await matchmaking()
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
async def unregister_user(id):
|
|
||||||
if id in player_id_queue:
|
|
||||||
player_id_queue.remove(id)
|
|
||||||
del(sockets[id])
|
|
||||||
|
|
||||||
elif id in player_games:
|
|
||||||
# we have an active game and have to end it
|
|
||||||
await player_games[id]._on_end_game(id)
|
|
||||||
del(player_games[id])
|
|
||||||
|
|
||||||
|
|
||||||
async def process_message(id, json):
|
|
||||||
if id in player_games:
|
|
||||||
await player_games[id].processPlayerMessage(id, json)
|
|
||||||
|
|
||||||
|
|
||||||
async def create_new_match():
|
|
||||||
p_a = player_id_queue.pop()
|
|
||||||
p_b = player_id_queue.pop()
|
|
||||||
|
|
||||||
s_a = sockets[p_a]
|
|
||||||
s_b = sockets[p_b]
|
|
||||||
|
|
||||||
del(sockets[p_a])
|
|
||||||
del(sockets[p_b])
|
|
||||||
|
|
||||||
new_game = GameManager(p_a, p_b, p_a, s_a, s_b)
|
|
||||||
|
|
||||||
player_games[p_a] = new_game
|
|
||||||
player_games[p_b] = new_game
|
|
||||||
|
|
||||||
await new_game.startMatch()
|
|
||||||
|
|
||||||
|
|
||||||
async def matchmaking():
|
|
||||||
if len(player_id_queue) < 2:
|
|
||||||
# we need at least 2 users for that
|
|
||||||
return
|
|
||||||
|
|
||||||
else:
|
|
||||||
asyncio.ensure_future(create_new_match())
|
|
||||||
|
|
||||||
|
|
||||||
class GameManager(object):
|
|
||||||
def __init__(self, player_a_id, player_b_id, start_player, socket_a, socket_b):
|
|
||||||
self.player_a_id = player_a_id
|
|
||||||
self.player_b_id = player_b_id
|
|
||||||
|
|
||||||
self.socket_a = socket_a
|
|
||||||
self.socket_b = socket_b
|
|
||||||
|
|
||||||
self.current_player = start_player
|
|
||||||
|
|
||||||
self.game_finished = False
|
|
||||||
|
|
||||||
async def startMatch(self):
|
|
||||||
|
|
||||||
print("match starts")
|
|
||||||
|
|
||||||
start_msg_a = {
|
|
||||||
'type': 'game_starts',
|
|
||||||
'data': {
|
|
||||||
'msg': '...',
|
|
||||||
'opponent_name': self.player_b_id,
|
|
||||||
'is_first_move': True
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
start_msg_b = {
|
|
||||||
'type': 'game_starts',
|
|
||||||
'data': {
|
|
||||||
'msg': '...',
|
|
||||||
'opponent_name': self.player_a_id,
|
|
||||||
'is_first_move': False
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await self.socket_a.send(json.dumps(start_msg_a))
|
|
||||||
await self.socket_b.send(json.dumps(start_msg_b))
|
|
||||||
|
|
||||||
print("start message send to all players")
|
|
||||||
|
|
||||||
async def processPlayerMessage(self, player_id, json_str):
|
|
||||||
if len(json_str) > 4096:
|
|
||||||
# something is fishy here
|
|
||||||
print("received strange message from client")
|
|
||||||
|
|
||||||
print("received message: " + json_str)
|
|
||||||
|
|
||||||
try:
|
|
||||||
json_dict = json.loads(json_str)
|
|
||||||
type = json_dict['type']
|
|
||||||
data = json_dict['data']
|
|
||||||
|
|
||||||
if type == "move":
|
|
||||||
await self._on_move(player_id, data)
|
|
||||||
|
|
||||||
elif type == "end_game":
|
|
||||||
await self._on_end_game(player_id)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print("" + str(e) + ": received wrong formated message")
|
|
||||||
|
|
||||||
async def _on_move(self, player_id, move_data):
|
|
||||||
response = {'type': 'move_response'}
|
|
||||||
response_data = {}
|
|
||||||
|
|
||||||
opponent_response = {'type': 'move'}
|
|
||||||
opponent_response_data = {}
|
|
||||||
|
|
||||||
opponent_response_data['sub_x'] = move_data['sub_x']
|
|
||||||
opponent_response_data['sub_y'] = move_data['sub_y']
|
|
||||||
opponent_response_data['x'] = move_data['x']
|
|
||||||
opponent_response_data['y'] = move_data['y']
|
|
||||||
opponent_response['data'] = opponent_response_data
|
|
||||||
|
|
||||||
if player_id == self.current_player:
|
|
||||||
|
|
||||||
is_a = (self.player_a_id == player_id)
|
|
||||||
current_socket = self.socket_a if is_a else self.socket_b
|
|
||||||
opponent_socket = self.socket_b if is_a else self.socket_a
|
|
||||||
|
|
||||||
response_data['success'] = True
|
|
||||||
response_data['msg'] = "move successful"
|
|
||||||
|
|
||||||
response['data'] = response_data
|
|
||||||
|
|
||||||
await opponent_socket.send(json.dumps(opponent_response))
|
|
||||||
await current_socket.send(json.dumps(response))
|
|
||||||
|
|
||||||
# switch player
|
|
||||||
self.current_player = self.player_b_id if is_a else self.player_a_id
|
|
||||||
|
|
||||||
else:
|
|
||||||
print("received move from wrong player")
|
|
||||||
|
|
||||||
is_a = (self.player_a_id == player_id)
|
|
||||||
current_socket = self.socket_a if is_a else self.socket_b
|
|
||||||
|
|
||||||
response_data["success"] = False
|
|
||||||
response_data["msg"] = "not your turn!"
|
|
||||||
|
|
||||||
response['data'] = response_data
|
|
||||||
|
|
||||||
await current_socket.send(json.dumps(response))
|
|
||||||
|
|
||||||
async def _on_end_game(self, player_id):
|
|
||||||
|
|
||||||
if self.game_finished:
|
|
||||||
return
|
|
||||||
|
|
||||||
is_a = (self.player_a_id == player_id)
|
|
||||||
opponent_socket = self.socket_b if is_a else self.socket_a
|
|
||||||
|
|
||||||
opponent_response = {'type': 'end_game'}
|
|
||||||
opponent_response['data'] = {'msg': 'game closed by opponent'}
|
|
||||||
|
|
||||||
await opponent_socket.send(json.dumps(opponent_response))
|
|
||||||
|
|
||||||
self.game_finished = True
|
|
67
main.py
67
main.py
@ -5,7 +5,6 @@ import ssl
|
|||||||
|
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
from game_manager import *
|
|
||||||
from session_manager import SessionManager
|
from session_manager import SessionManager
|
||||||
from connection_handler import Connection, ConnectionHandler
|
from connection_handler import Connection, ConnectionHandler
|
||||||
from match_manager import MatchManager
|
from match_manager import MatchManager
|
||||||
@ -27,7 +26,7 @@ DatabaseConnection(db_host,
|
|||||||
db_charset)
|
db_charset)
|
||||||
|
|
||||||
|
|
||||||
async def new_socket_worker(websocket, path):
|
async def socket_worker(websocket, path):
|
||||||
connection = None
|
connection = None
|
||||||
|
|
||||||
print("new incomin connection")
|
print("new incomin connection")
|
||||||
@ -68,69 +67,11 @@ async def new_socket_worker(websocket, path):
|
|||||||
id = "unknown_user"
|
id = "unknown_user"
|
||||||
print("close connection to user: " + id)
|
print("close connection to user: " + id)
|
||||||
|
|
||||||
|
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
||||||
async def socket_worker(websocket, path):
|
ssl_context.load_cert_chain(cert_file, keyfile=key_file)
|
||||||
|
|
||||||
registered = False
|
|
||||||
id = None
|
|
||||||
|
|
||||||
print("new connection")
|
|
||||||
|
|
||||||
try:
|
|
||||||
# get first message as register message
|
|
||||||
raw_msg = await websocket.recv()
|
|
||||||
|
|
||||||
msg = json.loads(raw_msg)
|
|
||||||
|
|
||||||
if msg['type'] != 'register':
|
|
||||||
print("got wrong registration")
|
|
||||||
websocket.close()
|
|
||||||
return
|
|
||||||
|
|
||||||
id = msg['data']['id']
|
|
||||||
|
|
||||||
registered = await register_user(id, websocket)
|
|
||||||
|
|
||||||
register_response = {
|
|
||||||
'type': 'register_response', 'data': {
|
|
||||||
'success': True, 'msg': '...'}}
|
|
||||||
|
|
||||||
if not registered:
|
|
||||||
register_response['data']['success'] = False
|
|
||||||
|
|
||||||
await websocket.send(json.dumps(register_response))
|
|
||||||
websocket.close()
|
|
||||||
return
|
|
||||||
|
|
||||||
await websocket.send(json.dumps(register_response))
|
|
||||||
|
|
||||||
print("successful redisterd user " + id)
|
|
||||||
|
|
||||||
async for m in websocket:
|
|
||||||
await process_message(id, m)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
# TODO: each disconnect is an exception so far
|
|
||||||
if id is not None:
|
|
||||||
print("catched exception in worker for user: " + id + ": " + str(e))
|
|
||||||
else:
|
|
||||||
print("catched exception in worker for unknown user")
|
|
||||||
|
|
||||||
|
|
||||||
finally:
|
|
||||||
if registered:
|
|
||||||
await unregister_user(id)
|
|
||||||
|
|
||||||
if id is None:
|
|
||||||
id = "unknown_user"
|
|
||||||
print("close connection to user: " + id)
|
|
||||||
|
|
||||||
|
|
||||||
#ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
|
||||||
#ssl_context.load_cert_chain(cert_file, keyfile=key_file)
|
|
||||||
|
|
||||||
start_server = websockets.serve(
|
start_server = websockets.serve(
|
||||||
new_socket_worker, host='', port=server_port) # , ssl=ssl_context)
|
socket_worker, host='', port=server_port, ssl=ssl_context)
|
||||||
|
|
||||||
asyncio.get_event_loop().run_until_complete(start_server)
|
asyncio.get_event_loop().run_until_complete(start_server)
|
||||||
asyncio.get_event_loop().run_forever()
|
asyncio.get_event_loop().run_forever()
|
||||||
|
10
settings.py
10
settings.py
@ -6,7 +6,11 @@ server_port = 5556
|
|||||||
db_host = "127.0.0.1"
|
db_host = "127.0.0.1"
|
||||||
db_port = 3306
|
db_port = 3306
|
||||||
|
|
||||||
db_user = "tictactoe"
|
db_user = None
|
||||||
dp_pw = ""
|
db_pw = None
|
||||||
|
db_db = None
|
||||||
|
|
||||||
charset = 'utf8mb4'
|
db_charset = 'utf8mb4'
|
||||||
|
|
||||||
|
# field dimension
|
||||||
|
n = 3
|
||||||
|
Loading…
Reference in New Issue
Block a user