Source code for mcstatus.responses.query

from __future__ import annotations

from dataclasses import asdict, dataclass
from typing import Any, TYPE_CHECKING

from mcstatus.motd import Motd

if TYPE_CHECKING:
    from typing_extensions import Self

    from mcstatus.responses._raw import RawQueryResponse

__all__ = [
    "QueryPlayers",
    "QueryResponse",
    "QuerySoftware",
]


[docs] @dataclass(frozen=True) class QueryResponse: """The response object for :meth:`JavaServer.query() <mcstatus.server.JavaServer.query>`.""" raw: RawQueryResponse """Raw response from the server. This is :class:`~typing.TypedDict` actually, please see sources to find what is here. """ motd: Motd """The MOTD of the server. Also known as description. .. seealso:: :doc:`/api/motd_parsing`. """ map_name: str """The name of the map. Default is ``world``.""" players: QueryPlayers """The players information.""" software: QuerySoftware """The software information.""" ip: str """The IP address the server is listening/was contacted on.""" port: int """The port the server is listening/was contacted on.""" game_type: str = "SMP" """The game type of the server. Hardcoded to ``SMP`` (survival multiplayer).""" game_id: str = "MINECRAFT" """The game ID of the server. Hardcoded to ``MINECRAFT``.""" @classmethod def build(cls, raw: RawQueryResponse, players_list: list[str]) -> Self: return cls( raw=raw, motd=Motd.parse(raw["hostname"], bedrock=False), map_name=raw["map"], players=QueryPlayers.build(raw, players_list), software=QuerySoftware.build(raw["version"], raw["plugins"]), ip=raw["hostip"], port=int(raw["hostport"]), game_type=raw["gametype"], game_id=raw["game_id"], )
[docs] def as_dict(self) -> dict[str, Any]: """Return the dataclass as JSON-serializable :class:`dict`. Do note that this method doesn't return :class:`string <str>` but :class:`dict`, so you can do some processing on returned value. Difference from :attr:`~mcstatus.responses.JavaStatusResponse.raw` is in that, :attr:`~mcstatus.responses.JavaStatusResponse.raw` returns raw response in the same format as we got it. This method returns the response in a more user-friendly JSON serializable format (for example, :attr:`~mcstatus.responses.BaseStatusResponse.motd` is returned as a :func:`Minecraft string <mcstatus.motd.Motd.to_minecraft>` and not :class:`dict`). """ as_dict = asdict(self) as_dict["motd"] = self.motd.simplify().to_minecraft() as_dict["players"] = asdict(self.players) as_dict["software"] = asdict(self.software) return as_dict
[docs] @dataclass(frozen=True) class QueryPlayers: """Class for storing information about players on the server.""" online: int """The number of online players.""" max: int """The maximum allowed number of players (server slots).""" list: list[str] """The list of online players.""" @classmethod def build(cls, raw: RawQueryResponse, players_list: list[str]) -> Self: return cls( online=int(raw["numplayers"]), max=int(raw["maxplayers"]), list=players_list, )
[docs] @dataclass(frozen=True) class QuerySoftware: """Class for storing information about software on the server.""" version: str """The version of the software.""" brand: str """The brand of the software. Like `Paper <https://papermc.io>`_ or `Spigot <https://www.spigotmc.org>`_.""" plugins: list[str] """The list of plugins. Can be an empty list if hidden.""" @classmethod def build(cls, version: str, plugins: str) -> Self: brand, parsed_plugins = cls._parse_plugins(plugins) return cls( version=version, brand=brand, plugins=parsed_plugins, ) @staticmethod def _parse_plugins(plugins: str) -> tuple[str, list[str]]: """Parse plugins string to list. Returns: :class:`tuple` with two elements. First is brand of server (:attr:`.brand`) and second is a list of :attr:`plugins`. """ brand = "vanilla" parsed_plugins = [] if plugins: parts = plugins.split(":", 1) brand = parts[0].strip() if len(parts) == 2: parsed_plugins = [s.strip() for s in parts[1].split(";")] return brand, parsed_plugins