-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Non-ascii player name causes RCON showplayers
break
#4
Comments
Thanks for this report, this is great. I really want to disable polling and will look into that. As for testing with non-ascii I will have to look into that some more. I'm not sure about support by various libraries either. |
It looks like non-ascii character support is a problem to be resolved in Palworld itself. gorcon/rcon-cli#35 I will continue looking for workarounds in the meantime. Do you know of any other tools/libraries (non-python) that work fine? |
I'm leaving this error here for reference. When a Player has a name using non-ascii, it results in this error:
The best I can tell is, Palworld's RCON implementation is truncating the player names or ends of the string for some reason when they have non-ascii characters which results in the "Received [too] few bytes". The size of the ShowPlayers response must be calculated before they are sent across the wire. |
Thanks for the check! I haven't tested any other rcon library, but even though some library can handle non-ascii chars, player id will be trimmed, so.. looks like it's best to wait palworld patch ... |
I still plan on disabling polling as requested in this issue. Should have that ready today or tomorrow. |
Polling/caching is no longer used as of v1.1.0 https://github.com/palworldlol/palworld-exporter/releases/tag/v1.1.0 |
Even using this modified rcon.py code to attempt a base64 decoding fails: import base64
import logging
import csv
import re
from abc import ABC, abstractmethod
from typing import ContextManager, Generic, List, TypeVar
from rcon import Console
from palworld_exporter.providers.data import Player, ServerInfo
class RCONContext(ContextManager):
"""
A context-aware class that returns an instance of a RCON Console.
"""
def __init__(self, host, port, password, timeout=20):
self._host = host
self._port = port
self._password = password
self._timeout = timeout
self._first_connection_made = False
def _get_console(self):
return Console(self._host, self._password, self._port, self._timeout)
def _check_encoding(self, response):
"""Check if the response is base64-encoded and return a boolean."""
try:
decoded_response = base64.b64decode(response)
return base64.b64encode(decoded_response).decode("utf-8") == response
except Exception:
return False
def _decode_if_needed(self, response):
"""Decode the response if it was base64 encoded."""
if self._check_encoding(response):
return base64.b64decode(response).decode("utf-8")
return response
def __enter__(self) -> Console:
self._console = self._get_console()
if not self._first_connection_made:
logging.info('RCON Connection success')
self._first_connection_made = True
logging.debug('RCON collector opened connection')
return self._console
def __exit__(self, exc_type, exc_value, exc_traceback):
if self._console:
self._console.close()
logging.debug('RCON collector closed connection')
T = TypeVar('T')
class RCONProvider(ABC, Generic[T]):
@abstractmethod
def fetch(self) -> T:
raise NotImplementedError
class PlayersProvider(RCONProvider[List[Player]]):
"""
Get active Player information.
"""
def __init__(self, rcon_ctx: RCONContext, ignore_logging_in: bool):
self._rcon_ctx = rcon_ctx
self._ignore_logging_in = ignore_logging_in
def _cmd_showplayers(self):
with self._rcon_ctx as conn:
try:
result = conn.command("ShowPlayers")
logging.debug(f"Raw ShowPlayers response: {result}")
if not result or len(result.strip()) < 10:
raise Exception("Received invalid or empty response from ShowPlayers.")
# Attempt UTF-8 decode and fall back to other encodings if necessary
result = self._decode_if_needed(result)
return result
except Exception as e:
logging.error(f"Error while fetching ShowPlayers: {e}")
return "" # Return empty string in case of error
def _decode_if_needed(self, result: bytes):
try:
# Attempt UTF-8 decode
return result.decode('utf-8', errors='replace')
except UnicodeDecodeError:
logging.warning("UTF-8 decoding failed, attempting Latin-1 decoding.")
# Fallback to Latin-1 or Windows-1252 encoding if UTF-8 fails
return result.decode('latin-1', errors='replace')
def fetch(self) -> List[Player]:
player_resp = self._cmd_showplayers()
if player_resp:
player_reader = csv.reader(player_resp.split('\n'))
fields = next(player_reader)
if fields:
players = []
for row in player_reader:
if row:
if row[1] == '00000000' and self._ignore_logging_in:
logging.debug(f'Excluding player {row[0]}')
continue
players.append(Player(row[0], row[1], row[2]))
return players
else:
logging.warning('Empty field list from ShowPlayers')
return []
else:
logging.warning('Empty or null response from ShowPlayers')
return []
class ServerInfoProvider(RCONProvider[ServerInfo]):
"""
Get Server information including name and version.
"""
def __init__(self, rcon_ctx: RCONContext):
self._rcon_ctx = rcon_ctx
self._info_re = re.compile(r"\[v(?P<version>.*?)\] (?P<name>.*$)")
def _cmd_info(self):
with self._rcon_ctx as conn:
result = conn.command("Info")
# Decode if base64-encoded
return self._rcon_ctx._decode_if_needed(result)
def fetch(self) -> ServerInfo:
info_resp = self._cmd_info()
info = self._info_re.search(info_resp)
if info:
version = info.group("version")
name = info.group("name").strip()
return ServerInfo(name, version)
else:
logging.warn('No response from Info RCON command')
return ServerInfo('unknown', 'unknown') 2024-12-26:12:29:36.280 WARNING [rcon.py:114] Empty or null response from ShowPlayers
2024-12-26:12:29:51.383 ERROR [rcon.py:84] Error while fetching ShowPlayers: Received few bytes!
|
Problem
In Source RCON protocol, packet body is defined as Null-terminated ASCII String. But we can set palworld player name as non-ascii characters(ex. Korean, Chinese, Cyrillic, ...) and this sets
showplayers
response packet body as non-ascii character, finally RCON client is failed or stuck.Similar issues:
I think this should be mainly handled by RCON client.
But it looks like exporter's polling is somewhat problematic.
This is timeline of my server when non-ascii name user joined. After user joined, somehow player count is keep exported(which is outdated) and players info is not exported. (2~3 persons playing in the server at the time)
Suggestion
The text was updated successfully, but these errors were encountered: