Conanjurer generation

This commit is contained in:
2026-06-04 19:13:50 +02:00
parent 1f271b4c71
commit f6ccdb3e34
13 changed files with 576 additions and 0 deletions
@@ -0,0 +1,55 @@
"""Cienka, odporna na rozłączenia otoczka na klienta Source RCON.
Conan Exiles wystawia standardowy Source RCON (TCP). Używamy aiomcrcon,
który implementuje ten protokół. Reconnect na wypadek restartów serwera.
"""
from __future__ import annotations
import asyncio
import logging
from aiomcrcon import Client as _Rcon # Source RCON over TCP
log = logging.getLogger("rcon")
class RconClient:
def __init__(self, host: str, port: int, password: str):
self._host, self._port, self._pw = host, port, password
self._client: _Rcon | None = None
self._lock = asyncio.Lock()
async def _ensure(self) -> _Rcon:
if self._client is None:
c = _Rcon(self._host, self._port, self._pw)
await c.connect()
self._client = c
log.info("RCON połączony %s:%s", self._host, self._port)
return self._client
async def command(self, cmd: str) -> str:
"""Wyślij komendę do serwera Conana. Zwraca odpowiedź serwera.
To jest KANAŁ Discord -> Conan. Np. command("broadcast Witajcie!")
wyświetli komunikat wszystkim graczom w grze.
"""
async with self._lock:
for attempt in (1, 2):
try:
client = await self._ensure()
resp, _ = await client.send_cmd(cmd)
return resp
except Exception as e: # rozłączenie/restart serwera
log.warning("RCON błąd (próba %s): %s", attempt, e)
await self.close()
if attempt == 2:
raise
await asyncio.sleep(1.0)
return ""
async def close(self) -> None:
if self._client is not None:
try:
await self._client.close()
except Exception:
pass
self._client = None