about summary refs log tree commit diff
path: root/scripts/tw_api.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/tw_api.py')
-rw-r--r--scripts/tw_api.py311
1 files changed, 225 insertions, 86 deletions
diff --git a/scripts/tw_api.py b/scripts/tw_api.py
index 054a4fa2..36cc5f5e 100644
--- a/scripts/tw_api.py
+++ b/scripts/tw_api.py
@@ -2,18 +2,57 @@
 from socket import *
 import struct
 import sys
+import threading
+import time
 
-def get_server_info(address, port):
+
+
+NUM_MASTERSERVERS = 4
+MASTERSERVER_PORT = 8300
+
+TIMEOUT = 2
+
+SERVERTYPE_NORMAL = 0
+SERVERTYPE_LEGACY = 1
+
+PACKET_GETLIST = "\x20\x00\x00\x00\x00\x00\xff\xff\xff\xffreqt"
+PACKET_GETLIST2 = "\x20\x00\x00\x00\x00\x00\xff\xff\xff\xffreq2"
+PACKET_GETINFO = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xffgief"
+PACKET_GETINFO2 = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xffgie2" + "\x00"
+PACKET_GETINFO3 = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xffgie3" + "\x00"
+
+
+
+class Server_Info(threading.Thread):
+
+	def __init__(self, address, type):
+		self.address = address
+		self.type = type
+		self.finished = False
+		threading.Thread.__init__(self, target = self.run)
+
+	def run(self):
+		self.info = None
+		if self.type == SERVERTYPE_NORMAL:
+			self.info = get_server_info3(self.address)
+		elif self.type == SERVERTYPE_LEGACY:
+			self.info = get_server_info(self.address)
+			if self.info:
+				self.info = get_server_info2(self.address)
+		self.finished = True
+
+
+def get_server_info(address):
 	try:
-		sock = socket(AF_INET, SOCK_DGRAM) 
-		sock.settimeout(1.5); 
-		sock.sendto("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xffgief", (address, port)) 
-		data, addr = sock.recvfrom(1024) 
-		sock.close() 
-	 
+		sock = socket(AF_INET, SOCK_DGRAM)
+		sock.settimeout(TIMEOUT);
+		sock.sendto(PACKET_GETINFO, address)
+		data, addr = sock.recvfrom(1024)
+		sock.close()
+
 		data = data[14:] # skip header
-	 	
 		slots = data.split("\x00")
+
 		server_info = {}
 		server_info["version"] = slots[0]
 		server_info["name"] = slots[1]
@@ -24,108 +63,208 @@ def get_server_info(address, port):
 		server_info["num_players"] = int(slots[6])
 		server_info["max_players"] = int(slots[7])
 		server_info["players"] = []
-		
+
 		for i in xrange(0, server_info["num_players"]):
 			player = {}
-			player["name"] = slots[8+i*2+1]
-			player["score"] = slots[8+i*2]
-			server_info["players"] += [player]
-			
-		gametypes = ["dm", "tdm", "ctf"]
-		try: server_info["gametype_name"] = gametypes[server_info["gametype_id"]]
-		except: server_info["gametype_name"] = "unknown"
-		
+			player["name"] = slots[8+i*2]
+			player["score"] = int(slots[8+i*2+1])
+			server_info["players"].append(player)
+
 		return server_info
+
 	except:
+		sock.close()
 		return None
-		
-def get_server_count(address, port):
+
+
+def get_server_info2(address):
 	try:
-		sock = socket(AF_INET, SOCK_DGRAM) 
-		sock.settimeout(1.5); 
-		sock.sendto("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xffcoun", (address, port)) 
-		data, addr = sock.recvfrom(1024) 
-		sock.close() 
-	 
+		sock = socket(AF_INET, SOCK_DGRAM)
+		sock.settimeout(TIMEOUT);
+		sock.sendto(PACKET_GETINFO2, address)
+		data, addr = sock.recvfrom(1024)
+		sock.close()
+
 		data = data[14:] # skip header
-		return struct.unpack(">H", data)[0]
+		slots = data.split("\x00")
+
+		server_info = {}
+		server_info["token"] = slots[0]
+		server_info["version"] = slots[1]
+		server_info["name"] = slots[2]
+		server_info["map"] = slots[3]
+		server_info["gametype"] = slots[4]
+		server_info["flags"] = int(slots[5])
+		server_info["progression"] = int(slots[6])
+		server_info["num_players"] = int(slots[7])
+		server_info["max_players"] = int(slots[8])
+		server_info["players"] = []
+
+		for i in xrange(0, server_info["num_players"]):
+			player = {}
+			player["name"] = slots[9+i*2]
+			player["score"] = int(slots[9+i*2+1])
+			server_info["players"].append(player)
+
+		return server_info
+
 	except:
-		return -1
+		sock.close()
+		return None
 
-def get_servers(address):
-	counter = 0
-	master_port = 8300
+
+def get_server_info3(address):
+	try:
+		sock = socket(AF_INET, SOCK_DGRAM)
+		sock.settimeout(TIMEOUT);
+		sock.sendto(PACKET_GETINFO3, address)
+		data, addr = sock.recvfrom(1400)
+		sock.close()
+
+		data = data[14:] # skip header
+		slots = data.split("\x00")
+
+		server_info = {}
+		server_info["token"] = slots[0]
+		server_info["version"] = slots[1]
+		server_info["name"] = slots[2]
+		server_info["map"] = slots[3]
+		server_info["gametype"] = slots[4]
+		server_info["flags"] = int(slots[5])
+		server_info["num_players"] = int(slots[6])
+		server_info["max_players"] = int(slots[7])
+		server_info["num_clients"] = int(slots[8])
+		server_info["max_clients"] = int(slots[9])
+		server_info["players"] = []
+
+		for i in xrange(0, server_info["num_clients"]):
+			player = {}
+			player["name"] = slots[10+i*5]
+			player["clan"] = slots[10+i*5+1]
+			player["country"] = int(slots[10+i*5+2])
+			player["score"] = int(slots[10+i*5+3])
+			if int(slots[10+i*5+4]):
+				player["player"] = True
+			else:
+				player["player"] = False
+			server_info["players"].append(player)
+
+		return server_info
+
+	except:
+		sock.close()
+		return None
+
+
+
+class Master_Server_Info(threading.Thread):
+
+	def __init__(self, address):
+		self.address = address
+		self.finished = False
+		threading.Thread.__init__(self, target = self.run)
+
+	def run(self):
+		self.servers = get_list(self.address) + get_list2(self.address)
+		self.finished = True
+
+
+def get_list(address):
 	servers = []
- 
+
 	try:
-		sock = socket(AF_INET, SOCK_DGRAM) 
-		sock.settimeout(1.5)
-		sock.sendto("\x20\x00\x00\x00\x00\x00\xff\xff\xff\xffreqt", (address, master_port)) 
-	
+		sock = socket(AF_INET, SOCK_DGRAM)
+		sock.settimeout(TIMEOUT)
+		sock.sendto(PACKET_GETLIST, address)
+
 		while 1:
 			data, addr = sock.recvfrom(1024)
+
+			data = data[14:]
+			num_servers = len(data) / 6
+
+			for n in range(0, num_servers):
+				ip = ".".join(map(str, map(ord, data[n*6:n*6+4])))
+				port = ord(data[n*6+5]) * 256 + ord(data[n*6+4])
+				servers += [[(ip, port), SERVERTYPE_LEGACY]]
+
+	except:
+		sock.close()
+
+	return servers
+
+
+def get_list2(address):
+	servers = []
+
+	try:
+		sock = socket(AF_INET, SOCK_DGRAM)
+		sock.settimeout(TIMEOUT)
+		sock.sendto(PACKET_GETLIST2, address)
+
+		while 1:
+			data, addr = sock.recvfrom(1400)
 			
-			data = data[14:] 
-			num_servers = len(data) / 6 
+			data = data[14:]
+			num_servers = len(data) / 18
 
 			for n in range(0, num_servers): 
-				ip = ".".join(map(str, map(ord, data[n*6:n*6+4]))) 
-				port = ord(data[n*6+5]) * 256 + ord(data[n*6+4]) 
-				servers += [[ip, port]]
+				if data[n*18:n*18+12] == "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff":
+					ip = ".".join(map(str, map(ord, data[n*18+12:n*18+16])))
+				else:
+					ip = ":".join(map(str, map(ord, data[n*18:n*18+16])))
+				port = (ord(data[n*18+16])<<8) + ord(data[n*18+17])
+				servers += [[(ip, port), SERVERTYPE_NORMAL]]
 
-	except: # timeout
+	except:
 		sock.close()
-		return servers
 
-def get_all_servers():
-	servers = []
-	for i in range(1, 16):
-		addr = "master%d.teeworlds.com"%i
-		list = get_servers(addr)
-		if list:
-			#print addr, "had", len(list), "servers"
-			servers += list
 	return servers
 
-servers = get_all_servers()
-total_players = 0
-players_per_versions = {}
-versions = {}
-gametypes = {}
-if 1:
-	for server in servers:
-		#print "checking server", server[0], server[1]
-		info = get_server_info(server[0], server[1])
-		if info:
-			total_players += len(info["players"])
-			if info["version"] in versions:
-				versions[info["version"]] += 1
-			else:
-				versions[info["version"]] = 1
 
-			if info["version"] in players_per_versions:
-				players_per_versions[info["version"]] += len(info["players"])
-			else:
-				players_per_versions[info["version"]] = len(info["players"])
 
-			if info["gametype"] in gametypes:
-				gametypes[info["gametype"]] += 1
-			else:
-				gametypes[info["gametype"]] = 1
+master_servers = []
+
+for i in range(1, NUM_MASTERSERVERS+1):
+	m = Master_Server_Info(("master%d.teeworlds.com"%i, MASTERSERVER_PORT))
+	master_servers.append(m)
+	m.start()
+	time.sleep(0.001) # avoid issues
+
+servers = []
+
+while len(master_servers) != 0:
+	if master_servers[0].finished == True:
+		if master_servers[0].servers:
+			servers += master_servers[0].servers
+		del master_servers[0]
+	time.sleep(0.001) # be nice
+
+servers_info = []
 
-print total_players
-				
-if 0:
-	print total_players, "on", len(servers), 'servers'
-	print "versions:"
-	for v in versions:
-		print "\t",v, versions[v]
+print str(len(servers)) + " servers"
+
+for server in servers:
+	s = Server_Info(server[0], server[1])
+	servers_info.append(s)
+	s.start()
+	time.sleep(0.001) # avoid issues
+
+num_players = 0
+num_clients = 0
+
+while len(servers_info) != 0:
+	if servers_info[0].finished == True:
+
+		if servers_info[0].info:
+			num_players += servers_info[0].info["num_players"]
+			if servers_info[0].type == SERVERTYPE_NORMAL:
+				num_clients += servers_info[0].info["num_clients"]
+			else:
+				num_clients += servers_info[0].info["num_players"]
 
-	print "players per version:"
-	for v in players_per_versions:
-		print "\t",v, players_per_versions[v]
+		del servers_info[0]
 
-	print "gametypes:"
-	for v in gametypes:
-		print "\t",v, gametypes[v]
+	time.sleep(0.001) # be nice
 
+print str(num_players) + " players and " + str(num_clients-num_players) + " spectators"