From 63cdaf36662937fe8940ec9fc88f9ee4737f9457 Mon Sep 17 00:00:00 2001 From: polaris Date: Tue, 8 Apr 2014 16:10:59 -0400 Subject: [PATCH] Preliminary matchmaking I don't know how well it works yet until more testing is done, but matchmaking works now. --- gs_server_database.py | 6 ++--- qr_server.py | 6 +++++ server_browser.py | 62 ++++++++++++++++++++++++++++++++----------- 3 files changed, 55 insertions(+), 19 deletions(-) diff --git a/gs_server_database.py b/gs_server_database.py index 3458a72..e8ca45f 100644 --- a/gs_server_database.py +++ b/gs_server_database.py @@ -20,6 +20,7 @@ from multiprocessing.managers import BaseManager from multiprocessing import freeze_support +import other.utils as utils server_list = {} @@ -264,7 +265,7 @@ def update_server_list(gameid, session, value): # Add new server value['__session__'] = session - print "Added %s to the server list for %s" % (gameid, value) + utils.print_log("Added %s to the server list for %s" % (value, gameid)) server_list[gameid].append(value) def delete_server(gameid, session): @@ -283,9 +284,6 @@ def start_server(): address = ("127.0.0.1", 27500) password = "" - #server_list["tetrisds"] = [] - #server_list["tetrisds"].append({'__session__': 0, 'key': "helloworld", 'value': "Hello, world!", 'extra': "Test"}) - GamespyServerDatabase.register("get_server_list", callable=lambda:server_list) GamespyServerDatabase.register("find_servers", callable=find_servers) GamespyServerDatabase.register("update_server_list", callable=update_server_list) diff --git a/qr_server.py b/qr_server.py index 54d3d0c..4b4ff9a 100644 --- a/qr_server.py +++ b/qr_server.py @@ -198,6 +198,12 @@ while 1: if "statechanged" in k: if k['statechanged'] == "1": # Create server if k['publicport'] != "0" and k['publicip'] != "0" and k['maxplayers'] != "0": + # dwc_mtype controls what kind of server query we're looking for. + # dwc_mtype = 0 is used when looking for a matchmaking game. + # dwc_mtype = 1 is unknown. + # dwc_mtype = 2 is used when hosting a friends only game (possibly other uses too). + # dwc_mtype = 3 is used when looking for a friends only game (possibly other uses too). + # Some memory could be saved by clearing out any unwanted fields from k before sending. server_manager.update_server_list(k['gamename'] , session_id, k) elif k['statechanged'] == "2": # Close server diff --git a/server_browser.py b/server_browser.py index b724b6c..7594853 100644 --- a/server_browser.py +++ b/server_browser.py @@ -8,6 +8,8 @@ from twisted.internet import reactor import socket import ctypes +import time +from threading import Thread import gamespy.gs_utility as gs_utils import other.utils as utils @@ -101,6 +103,12 @@ class Session(LineReceiver): self.addr = addr self.forward_to_client = False self.forward_client = () + self.is_searching = False + + # Amount of time (in seconds) we can search for a match before getting kicked off. + # Set to -1 to allow keep searching forever until a server appears. + #self.timeout = 60 * 10 + self.timeout = -1 def rawDataReceived(self, data): # First 2 bytes are the packet size. @@ -191,23 +199,16 @@ class Session(LineReceiver): #print "%08x" % options #print "%d %08x" % (max_servers, source_ip) - # Get dictionary from master server list server. - self.server_list = get_server_list(query_game, filter, fields, max_servers)._getvalue() + if self.is_searching == False: + self.is_searching = True - # Generate encrypted server list and send to client. - print self.server_list - for server in self.server_list: - # Generate binary server list data - data = generate_server_list_data(self.addr, fields, server) + # I still want the connection to close properly when the client disconnects, so put the server search + # part into its own thread. + # The game will create a new connection for every search query, so don't worry about setting + # self.is_searching to False. + t = Thread(target = self.find_server, args=(query_game, filter, fields, max_servers, game_name, challenge)) + t.start() - # Encrypt data - enc = gs_utils.EncTypeX() - data = enc.encrypt(secret_key_list[game_name], challenge, data) - - # Send to client - self.transport.write(bytes(data)) - utils.print_log("Sent server list message to %s:%s..." % (self.addr.host, self.addr.port)) - break elif data[2] == '\x02': # Send message request @@ -226,6 +227,37 @@ class Session(LineReceiver): else: utils.print_log("Received unknown command (%02x) from %s:%s... %s" % (ord(data[2]), self.addr.host, self.addr.port, data)) + def find_server(self, query_game, filter, fields, max_servers, game_name, challenge): + # Get dictionary from master server list server. + # The game sends a search query only once so we must loop until something is found. + # Search for the specified amount of time, or if self.timeout is set to -1, until a match is found. + start = time.time() + while True: + self.server_list = get_server_list(query_game, filter, fields, max_servers)._getvalue() + + if self.server_list != []: + break + + time.sleep(5) # Sleep 1 second + + if self.timeout != -1 and time.time() - start > self.timeout: + break + + # Generate encrypted server list and send to client. + print self.server_list + for server in self.server_list: + # Generate binary server list data + data = generate_server_list_data(self.addr, fields, server) + + # Encrypt data + enc = gs_utils.EncTypeX() + data = enc.encrypt(secret_key_list[game_name], challenge, data) + + # Send to client + self.transport.write(bytes(data)) + utils.print_log("Sent server list message to %s:%s..." % (self.addr.host, self.addr.port)) + break + class SessionFactory(Factory): def __init__(self):