From 1ba36a725af67800abb93ddf2c2b1f65056cbf30 Mon Sep 17 00:00:00 2001 From: Battlefield Duck Date: Mon, 12 Feb 2024 04:11:51 +0800 Subject: [PATCH] Support Kaillera Network Protocol --- docs/tests/protocols/index.rst | 1 + docs/tests/protocols/test_kaillera/index.rst | 8 + .../test_kaillera/test_get_status.rst | 8 + .../test_query_master_servers.rst | 529 ++++++++++++++++++ opengsq/protocols/kaillera.py | 79 +++ opengsq/responses/kaillera/__init__.py | 1 + opengsq/responses/kaillera/status.py | 26 + tests/protocols/test_kaillera.py | 21 + 8 files changed, 673 insertions(+) create mode 100644 docs/tests/protocols/test_kaillera/index.rst create mode 100644 docs/tests/protocols/test_kaillera/test_get_status.rst create mode 100644 docs/tests/protocols/test_kaillera/test_query_master_servers.rst create mode 100644 opengsq/protocols/kaillera.py create mode 100644 opengsq/responses/kaillera/__init__.py create mode 100644 opengsq/responses/kaillera/status.py create mode 100644 tests/protocols/test_kaillera.py diff --git a/docs/tests/protocols/index.rst b/docs/tests/protocols/index.rst index 4307449..c4e3c24 100644 --- a/docs/tests/protocols/index.rst +++ b/docs/tests/protocols/index.rst @@ -13,6 +13,7 @@ Protocols Tests test_gamespy2/index test_gamespy3/index test_gamespy4/index + test_kaillera/index test_killingfloor/index test_minecraft/index test_quake1/index diff --git a/docs/tests/protocols/test_kaillera/index.rst b/docs/tests/protocols/test_kaillera/index.rst new file mode 100644 index 0000000..2087956 --- /dev/null +++ b/docs/tests/protocols/test_kaillera/index.rst @@ -0,0 +1,8 @@ +.. _test_kaillera: + +test_kaillera +============= + +.. toctree:: + test_get_status + test_query_master_servers diff --git a/docs/tests/protocols/test_kaillera/test_get_status.rst b/docs/tests/protocols/test_kaillera/test_get_status.rst new file mode 100644 index 0000000..bdb2016 --- /dev/null +++ b/docs/tests/protocols/test_kaillera/test_get_status.rst @@ -0,0 +1,8 @@ +test_get_status +=============== + +Here are the results for the test method. + +.. code-block:: json + + true diff --git a/docs/tests/protocols/test_kaillera/test_query_master_servers.rst b/docs/tests/protocols/test_kaillera/test_query_master_servers.rst new file mode 100644 index 0000000..18aeee2 --- /dev/null +++ b/docs/tests/protocols/test_kaillera/test_query_master_servers.rst @@ -0,0 +1,529 @@ +test_query_master_servers +========================= + +Here are the results for the test method. + +.. code-block:: json + + [ + { + "server_name": "[Korea Fast Server. 1] (KFS.1)", + "ip_address": "112.161.44.113", + "port": 27888, + "users": 34, + "max_users": 100, + "game_count": 1, + "version": "KFS_3.9", + "location": "Korea Republic" + }, + { + "server_name": "Retroxogos", + "ip_address": "77.27.254.198", + "port": 27888, + "users": 0, + "max_users": 100, + "game_count": 0, + "version": "ESF93.2", + "location": "Galicia" + }, + { + "server_name": "Anti3D", + "ip_address": "82.165.211.39", + "port": 27888, + "users": 0, + "max_users": 100, + "game_count": 0, + "version": "ESF92.9", + "location": "USA" + }, + { + "server_name": "Supernova", + "ip_address": "208.99.44.140", + "port": 27888, + "users": 0, + "max_users": 100, + "game_count": 0, + "version": "ESF93.2", + "location": "NYC" + }, + { + "server_name": "Emulation Paradise", + "ip_address": "5.252.152.88", + "port": 27888, + "users": 0, + "max_users": 100, + "game_count": 0, + "version": "ESF93.2", + "location": "Netherlands" + }, + { + "server_name": "Desiree Server", + "ip_address": "193.29.97.99", + "port": 27888, + "users": 0, + "max_users": 150, + "game_count": 0, + "version": "EMX2.0.2", + "location": "Miami" + }, + { + "server_name": "champ", + "ip_address": "192.168.11.35", + "port": 27888, + "users": 0, + "max_users": 2, + "game_count": 0, + "version": "0.86", + "location": "Unknown location" + }, + { + "server_name": "Joburg", + "ip_address": "169.239.128.47", + "port": 27888, + "users": 0, + "max_users": 100, + "game_count": 0, + "version": "ESF93.2", + "location": "South Africa" + }, + { + "server_name": "Dragon Spirit", + "ip_address": "116.251.223.214", + "port": 27888, + "users": 0, + "max_users": 100, + "game_count": 0, + "version": "ESF93.2", + "location": "Singapore" + }, + { + "server_name": "Vietnam Fast Server", + "ip_address": "113.161.176.124", + "port": 27888, + "users": 0, + "max_users": 100, + "game_count": 0, + "version": "VFS0.6.2", + "location": "Vietnam" + }, + { + "server_name": "Rebel Squadrons", + "ip_address": "141.11.228.27", + "port": 27888, + "users": 0, + "max_users": 100, + "game_count": 0, + "version": "ESF92.9", + "location": "New York" + }, + { + "server_name": "Kaillera Syrup", + "ip_address": "103.144.177.53", + "port": 27888, + "users": 0, + "max_users": 500, + "game_count": 0, + "version": "ESF93.2", + "location": "Canada" + }, + { + "server_name": "China Games [Srv.2]", + "ip_address": "101.33.210.38", + "port": 27888, + "users": 0, + "max_users": 100, + "game_count": 0, + "version": "ESF93.2", + "location": "China" + }, + { + "server_name": "Phantasia", + "ip_address": "54.37.60.104", + "port": 27888, + "users": 8, + "max_users": 900, + "game_count": 4, + "version": "ESF93.2", + "location": "France" + }, + { + "server_name": "Best Old Games Server", + "ip_address": "151.248.116.119", + "port": 27888, + "users": 1, + "max_users": 20, + "game_count": 1, + "version": "ESF93.2", + "location": "Russia" + }, + { + "server_name": "[Korea Fast Server. 2] (KFS.2)", + "ip_address": "112.161.44.114", + "port": 27888, + "users": 32, + "max_users": 100, + "game_count": 0, + "version": "KFS_3.9", + "location": "Korea Republic" + }, + { + "server_name": "Moscow Entertainment Server", + "ip_address": "104.166.186.176", + "port": 27888, + "users": 5, + "max_users": 200, + "game_count": 2, + "version": "ESF93.2", + "location": "Russia" + }, + { + "server_name": "China Games [Srv.1]", + "ip_address": "211.101.247.247", + "port": 27888, + "users": 0, + "max_users": 100, + "game_count": 0, + "version": "ESF93.2", + "location": "China" + }, + { + "server_name": "[totoli-Srv KOREA]", + "ip_address": "totoli.cloud", + "port": 27888, + "users": 0, + "max_users": 70, + "game_count": 0, + "version": "0.86", + "location": "KOREA" + }, + { + "server_name": "Kiwis", + "ip_address": "185.99.133.114", + "port": 27888, + "users": 0, + "max_users": 100, + "game_count": 0, + "version": "ESF93.2", + "location": "New Zealand" + }, + { + "server_name": "cllsmash", + "ip_address": "192.168.3.240", + "port": 27888, + "users": 0, + "max_users": 10, + "game_count": 0, + "version": "0.86", + "location": "Unknown location" + }, + { + "server_name": "Unknown serv0r", + "ip_address": "27.156.166.30", + "port": 27888, + "users": 1, + "max_users": 34, + "game_count": 0, + "version": "0.86", + "location": "Unknown location" + }, + { + "server_name": "Fortaleza", + "ip_address": "5.252.24.227", + "port": 27888, + "users": 0, + "max_users": 100, + "game_count": 0, + "version": "elk", + "location": "North Brasil" + }, + { + "server_name": "Mortal Kombat WaveNet", + "ip_address": "82.153.68.29", + "port": 27888, + "users": 0, + "max_users": 100, + "game_count": 0, + "version": "ESF92.9", + "location": "Atlanta" + }, + { + "server_name": "RETROKAILLERA", + "ip_address": "142.202.136.112", + "port": 27888, + "users": 0, + "max_users": 100, + "game_count": 0, + "version": "ESF93.2", + "location": "USA" + }, + { + "server_name": "SameTeem UK", + "ip_address": "51.89.139.238", + "port": 27888, + "users": 0, + "max_users": 100, + "game_count": 0, + "version": "ESF93.2", + "location": "GB" + }, + { + "server_name": "###[China]### Emu.jy6d.com", + "ip_address": "122.141.100.90", + "port": 27888, + "users": 0, + "max_users": 888, + "game_count": 0, + "version": "1.01", + "location": "China-jilin" + }, + { + "server_name": "Valhalla", + "ip_address": "85.118.207.52", + "port": 27888, + "users": 1, + "max_users": 100, + "game_count": 1, + "version": "ESF93.2", + "location": "Sweden" + }, + { + "server_name": "[SCD] Sonic Cage Dome", + "ip_address": "141.11.208.139", + "port": 27888, + "users": 0, + "max_users": 150, + "game_count": 0, + "version": "EMX2.0.2", + "location": "L.A." + }, + { + "server_name": "Pixelated Playground", + "ip_address": "176.105.227.131", + "port": 27888, + "users": 0, + "max_users": 150, + "game_count": 0, + "version": "EMX2.0.2", + "location": "Tampa Bay" + }, + { + "server_name": "Miami Secret", + "ip_address": "185.144.159.190", + "port": 27888, + "users": 0, + "max_users": 100, + "game_count": 0, + "version": "elk", + "location": "Florida" + }, + { + "server_name": "ROMAN_GAME", + "ip_address": "82.156.206.238", + "port": 27888, + "users": 0, + "max_users": 10, + "game_count": 0, + "version": "0.86", + "location": "China" + }, + { + "server_name": "vacuum-server", + "ip_address": "178.76.239.106", + "port": 27888, + "users": 0, + "max_users": 100, + "game_count": 0, + "version": "ESF93.2", + "location": "Rostov-on-Don" + }, + { + "server_name": "Chile x Kaillera", + "ip_address": "216.73.159.45", + "port": 27888, + "users": 0, + "max_users": 100, + "game_count": 0, + "version": "ESF93.2", + "location": "Chile" + }, + { + "server_name": "Aussie Kaillera", + "ip_address": "202.169.104.136", + "port": 27888, + "users": 0, + "max_users": 20, + "game_count": 0, + "version": "ESF93.2", + "location": "Australia" + }, + { + "server_name": "Neo Kaillera", + "ip_address": "31.220.1.195", + "port": 27888, + "users": 0, + "max_users": 100, + "game_count": 0, + "version": "elk", + "location": "Netherlands" + }, + { + "server_name": "Winning Eleven 3 Version Final Online", + "ip_address": "161.132.55.157", + "port": 27888, + "users": 0, + "max_users": 50, + "game_count": 0, + "version": "ESF92.9", + "location": "Peru" + }, + { + "server_name": "Galaxy", + "ip_address": "104.234.10.201", + "port": 27888, + "users": 0, + "max_users": 100, + "game_count": 0, + "version": "ESF92.9", + "location": "Chicago" + }, + { + "server_name": "Chibi Server2", + "ip_address": "172.17.0.1", + "port": 27882, + "users": 0, + "max_users": 100, + "game_count": 0, + "version": "ESF92.9", + "location": "China" + }, + { + "server_name": "EmuLinker.org [EU]", + "ip_address": "85.215.174.176", + "port": 27888, + "users": 0, + "max_users": 100, + "game_count": 0, + "version": "ESF92.9", + "location": "Berlin" + }, + { + "server_name": "Liperock Oficial MK", + "ip_address": "34.95.239.96", + "port": 27888, + "users": 0, + "max_users": 100, + "game_count": 0, + "version": "elk", + "location": "Sao Paulo" + }, + { + "server_name": ":»¶Ó­À´µ½ÔËÏú³µ¼äKOF¾ãÀÖ²¿", + "ip_address": "192.168.1.2", + "port": 27888, + "users": 0, + "max_users": 200, + "game_count": 0, + "version": "0.92", + "location": "ÔËÏú³µ¼ä" + }, + { + "server_name": "[Tekken Battle Net]", + "ip_address": "220.85.140.51", + "port": 27888, + "users": 15, + "max_users": 100, + "game_count": 2, + "version": "ESF92.9", + "location": "KOREA" + }, + { + "server_name": "Brightspeed", + "ip_address": "67.145.163.81", + "port": 27888, + "users": 0, + "max_users": 100, + "game_count": 0, + "version": "elk", + "location": "North Carolina" + }, + { + "server_name": "HK Gamers", + "ip_address": "202.53.150.101", + "port": 27888, + "users": 0, + "max_users": 100, + "game_count": 0, + "version": "ESF93.2", + "location": "Hong Kong" + }, + { + "server_name": "China Games [Srv.3]", + "ip_address": "101.42.29.253", + "port": 27888, + "users": 1, + "max_users": 100, + "game_count": 1, + "version": "ESF93.2", + "location": "China" + }, + { + "server_name": "alex.schroedsen", + "ip_address": "192.168.0.16", + "port": 27888, + "users": 0, + "max_users": 10, + "game_count": 0, + "version": "0.86", + "location": "Unknown location" + }, + { + "server_name": "Unknown serv0r", + "ip_address": "192.168.1.112", + "port": 147, + "users": 0, + "max_users": 6, + "game_count": 0, + "version": "0.86", + "location": "Unknown location" + }, + { + "server_name": "100% BEST", + "ip_address": "146.71.78.239", + "port": 27888, + "users": 0, + "max_users": 100, + "game_count": 0, + "version": "ESF93.2", + "location": "BETTER" + }, + { + "server_name": "msk.13.st", + "ip_address": "172.17.0.1", + "port": 27888, + "users": 0, + "max_users": 130, + "game_count": 0, + "version": "ESF93.2", + "location": "Russia" + }, + { + "server_name": "Sao Paulo", + "ip_address": "38.54.57.120", + "port": 27888, + "users": 1, + "max_users": 40, + "game_count": 1, + "version": "elk", + "location": "Brasil" + }, + { + "server_name": "Bogota", + "ip_address": "154.223.16.122", + "port": 27888, + "users": 3, + "max_users": 100, + "game_count": 2, + "version": "elk", + "location": "Colombia" + } + ] diff --git a/opengsq/protocols/kaillera.py b/opengsq/protocols/kaillera.py new file mode 100644 index 0000000..6fbbdaf --- /dev/null +++ b/opengsq/protocols/kaillera.py @@ -0,0 +1,79 @@ +from __future__ import annotations + +import aiohttp + +from opengsq.responses.kaillera import Status +from opengsq.protocol_base import ProtocolBase +from opengsq.protocol_socket import UdpClient + + +class Kaillera(ProtocolBase): + """ + A class used to represent the Kaillera Network Protocol. + """ + + full_name = "Kaillera Network Protocol" + + async def get_status(self) -> bool: + """ + Checks the status of the server by sending a PING message and expecting a PONG response. + + Returns: + bool: True if the server responds with PONG, False otherwise. + """ + response = await UdpClient.communicate(self, b"PING\0") + return response == b"PONG\x00" + + @staticmethod + async def query_master_servers() -> list[Status]: + """ + Queries the master servers for a list of all active servers. + + Returns: + list[Status]: A list of Status objects representing each server. + """ + url = "http://www.kaillera.com/raw_server_list2.php" + + async with aiohttp.ClientSession() as session: + async with session.get(url) as response: + data = await response.text() + + # Format: serverName[LF]ipAddress:port;users/maxusers;gameCount;version;location[LF] + servers = data.strip().split("\n") + master_servers = [] + + for i in range(0, len(servers), 2): + server_name, info = servers[i : i + 2] + items = info.split(";") + ip_address, port = items[0].split(":") + users, maxusers = items[1].split("/") + game_count, version, location = items[2], items[3], items[4] + + master_servers.append( + Status( + server_name, + ip_address, + int(port), + int(users), + int(maxusers), + int(game_count), + version, + location, + ) + ) + + return master_servers + + +if __name__ == "__main__": + import asyncio + + async def main_async(): + master_servers = await Kaillera.query_master_servers() + print(master_servers) + + kaillera = Kaillera(host="112.161.44.113", port=27888, timeout=5.0) + status = await kaillera.get_status() + print(status) + + asyncio.run(main_async()) diff --git a/opengsq/responses/kaillera/__init__.py b/opengsq/responses/kaillera/__init__.py new file mode 100644 index 0000000..2f91dae --- /dev/null +++ b/opengsq/responses/kaillera/__init__.py @@ -0,0 +1 @@ +from .status import Status diff --git a/opengsq/responses/kaillera/status.py b/opengsq/responses/kaillera/status.py new file mode 100644 index 0000000..641bdb5 --- /dev/null +++ b/opengsq/responses/kaillera/status.py @@ -0,0 +1,26 @@ +from __future__ import annotations + +from dataclasses import dataclass + + +@dataclass +class Status: + """ + Represents the status of the server. + """ + + server_name: str + + ip_address: str + + port: int + + users: int + + max_users: int + + game_count: int + + version: str + + location: str diff --git a/tests/protocols/test_kaillera.py b/tests/protocols/test_kaillera.py new file mode 100644 index 0000000..ec8573b --- /dev/null +++ b/tests/protocols/test_kaillera.py @@ -0,0 +1,21 @@ +import pytest +from opengsq.protocols.kaillera import Kaillera + +from ..result_handler import ResultHandler + +handler = ResultHandler(__file__) +# handler.enable_save = True + +test = Kaillera(host="112.161.44.113", port=27888) + + +@pytest.mark.asyncio +async def test_get_status(): + result = await test.get_status() + await handler.save_result("test_get_status", result) + + +@pytest.mark.asyncio +async def test_query_master_servers(): + result = await test.query_master_servers() + await handler.save_result("test_query_master_servers", result)