diff --git a/sampy/client/__init__.py b/sampy/client/__init__.py index 9c851a2..6ce789c 100644 --- a/sampy/client/__init__.py +++ b/sampy/client/__init__.py @@ -5,16 +5,13 @@ from . import base from . import query from . import player -from ..struct.server import ServerConfig - STATE_UNKNOWN = (0, base.BaseClient) STATE_QUERY = (1, query.QueryClient) STATE_PLAYER = (2, player.PlayerClient) class Client: - def __init__(self, config: ServerConfig, socket: socket.socket, ip: str, port: int): - self.config = config - self.socket = socket + def __init__(self, server: "__ServerInstance__", ip: str, port: int): + self.server = server self.ip = ip self.port = port @@ -22,7 +19,7 @@ class Client: def set_state(self, state: tuple): self.state = state - self.client = self.state[1](self.config, self.socket, self.ip, self.port) + self.client = self.state[1](self.server, self.ip, self.port) async def on_packet(self, packet: bytes): if self.state == STATE_UNKNOWN: diff --git a/sampy/client/base.py b/sampy/client/base.py index 00f1460..2976bdb 100644 --- a/sampy/client/base.py +++ b/sampy/client/base.py @@ -1,15 +1,12 @@ import socket import struct -from ..struct.server import ServerConfig - import logging logger = logging.getLogger(__name__) class BaseClient: - def __init__(self, config: ServerConfig, socket: socket.socket, ip: str, port: int): - self.config = config - self.socket = socket + def __init__(self, server: "__ServerInstance__", ip: str, port: int): + self.server = server self.ip = ip self.port = port @@ -17,3 +14,7 @@ class BaseClient: async def on_packet(self, packet: bytes): logger.debug("on_packet(%s)" % packet) + + async def send(self, packet: bytes): + sock: socket.socket = self.server.socket + sock.sendto(packet, (self.ip, self.port)) \ No newline at end of file diff --git a/sampy/client/player.py b/sampy/client/player.py index 0f08c5d..d98110e 100644 --- a/sampy/client/player.py +++ b/sampy/client/player.py @@ -1,14 +1,13 @@ import socket from .base import BaseClient -from ..struct.server import ServerConfig import logging logger = logging.getLogger(__name__) class PlayerClient(BaseClient): - def __init__(self, config: ServerConfig, socket: socket.socket, ip: str, port: int): - super().__init__(config, socket, ip, port) + def __init__(self, server: "__ServerInstance__", ip: str, port: int): + super().__init__(server, ip, port) logger.debug("Client resolved to PlayerClient") async def on_packet(self, packet: bytes): diff --git a/sampy/client/query.py b/sampy/client/query.py index 081c75c..a61ece0 100644 --- a/sampy/client/query.py +++ b/sampy/client/query.py @@ -2,22 +2,111 @@ import socket import struct from .base import BaseClient -from ..struct.server import ServerConfig from ..shared import glob import logging logger = logging.getLogger(__name__) class QueryClient(BaseClient): - def __init__(self, config: ServerConfig, socket: socket.socket, ip: str, port: int): - super().__init__(config, socket, ip, port) + def __init__(self, server: "__ServerInstance__", ip: str, port: int): + super().__init__(server, ip, port) logger.debug("Client resolved to QueryClient") + + self.handlers = { + b"i": self.query_i, + b"r": self.query_r, + b"c": self.query_c, + b"d": self.query_d + } async def on_packet(self, packet: bytes): logger.debug("on_packet(%s)" % packet) - async def query_i(self): - len_hostname = len(self.config.hostname) - len_mode = len(self.config.mode) - len_language = len(self.config.language) + """ + if len(packet) != 11: # Just a ping with some random numbers at the end (14 bytes in total) + await self.send(packet) + return + """ + # ip ~~and port~~ the client connected to; (would be server ip ~~and port~~ if not though proxy) + # This could be used to check if client connected remotely in some way though a proxy + # SA:MP default server drops the connection if port does not match (when its client (not query protocol)) + #server_ip = ".".join((str(x) for x in struct.unpack(b"<4B", packet[4:8]))) + #server_port, = struct.unpack(b" bytes: + len_hostname = len(self.server.config.hostname) + len_mode = len(self.server.config.mode) + len_language = len(self.server.config.language) + + return packet + struct.pack(b" bytes: + data = [] + + rules = await self.server.get_rules() + data.append(len(rules)) + + for k, v in rules.items(): + data += [ + len(k), k, + len(v), v + ] + + return packet + struct.pack(b" bytes: + data = [] + + scores = await self.server.get_players_scores() + data.append(len(scores)) + + for k, v in scores.items(): + data += [ + len(k), k, + v + ] + + return packet + struct.pack(b" bytes: + data = [] + + players = await self.server.get_online_players() + data.append(len(players)) + + for p in players: + data += [ + p["id"], + len(p["nick"]), p["nick"], + p["score"], + p["ping"] + ] + + return packet + struct.pack(b" bytes: + return packet \ No newline at end of file diff --git a/sampy/server.py b/sampy/server.py index 814d542..9ad4c44 100644 --- a/sampy/server.py +++ b/sampy/server.py @@ -22,6 +22,17 @@ class Server: async def on_command(self, cmd: str): logger.debug("on_command(%s)" % cmd) + + async def get_online_players(self): # TODO: Get data from server's client objects + return [ + {"nick": b"Sunpy", "score": 64, "ping": 8, "id": 1} # replace id with function to get player's id + ] + + async def get_rules(self): # TODO + return {b"Rule name sample": b"Rule value", b"weburl": b"https://git.osufx.com/Sunpy/sampy"} + + async def get_players_scores(self): # TODO + return {b"Sunpy": 64, b"username": 123} async def main(self): await self.create_socket() @@ -34,7 +45,7 @@ class Server: if addr not in self.clients: ip, port = addr - self.clients[addr] = Client(self.config, self.socket, ip, port) + self.clients[addr] = Client(self, ip, port) await self.clients[addr].on_packet(data) await asyncio.sleep(0) \ No newline at end of file