From e471395e263de718f2f5b444eb8753eec0c826e0 Mon Sep 17 00:00:00 2001 From: Mofurka <94404509+Mofurka@users.noreply.github.com> Date: Sun, 6 Apr 2025 09:26:47 +0500 Subject: [PATCH 1/4] Fixed player crash when kick Fixed a bug with players crashing when kicked. Thanks to https://github.com/Novaenia for the tip --- plugins/player_manager.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/plugins/player_manager.py b/plugins/player_manager.py index d05dea6..bffecd5 100644 --- a/plugins/player_manager.py +++ b/plugins/player_manager.py @@ -603,6 +603,12 @@ def kick_player(self, player, reason=""): self.players_online.remove(player.uuid) return try: + world_stop_packet = build_packet(packets["world_stop"], + WorldStop.build( + dict(reason=reason) + )) + self.background(player.connection.raw_write(world_stop_packet)) + kick_packet = build_packet(packets["server_disconnect"], ServerDisconnect.build( dict(reason=reason))) @@ -955,8 +961,7 @@ async def _kick(self, data, connection): :return: Null. """ - # FIXME: Kick is currently broken. Kicking someone will cause their - # starbound client to crash (overkill). + # FIXED: NO MORE CRASHES try: alias = data[0] except IndexError: From e44cde25997c494a643468f1624a7e0bece23946 Mon Sep 17 00:00:00 2001 From: Mofurka <94404509+Mofurka@users.noreply.github.com> Date: Sun, 6 Apr 2025 12:05:45 +0500 Subject: [PATCH 2/4] Memory Leak Fix I tracked through tracemalloc that the link still remains, and when using opensb, each player's entry increases the memory by 58-60 megabytes. If the player exits, the memory is not cleared and increases each time. Such a small fix now really does not allow the memory to increase by 50-60 MB, but only by 200-300 KB --- utilities.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/utilities.py b/utilities.py index 1a075eb..0f71067 100644 --- a/utilities.py +++ b/utilities.py @@ -394,8 +394,12 @@ def background(coro): # To prevent keeping references to finished tasks forever, # make each task remove its own reference from the set after # completion: - task.add_done_callback(background_tasks.discard) - + def _done_callback(t): + background_tasks.discard(t) + + + task.add_done_callback(_done_callback) + background_tasks.add(task) return task From 1d2f773280e2fa5e035e2167528f25f693142ef6 Mon Sep 17 00:00:00 2001 From: Mofurka <94404509+Mofurka@users.noreply.github.com> Date: Sun, 6 Apr 2025 13:47:54 +0500 Subject: [PATCH 3/4] Update player_manager.py --- plugins/player_manager.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plugins/player_manager.py b/plugins/player_manager.py index bffecd5..d137522 100644 --- a/plugins/player_manager.py +++ b/plugins/player_manager.py @@ -594,7 +594,7 @@ def build_inherits(inherits): return final - def kick_player(self, player, reason=""): + async def kick_player(self, player, reason=""): if player.client_id == -1 or player.connection is None: player.connection = None player.logged_in = False @@ -607,12 +607,12 @@ def kick_player(self, player, reason=""): WorldStop.build( dict(reason=reason) )) - self.background(player.connection.raw_write(world_stop_packet)) - + await player.connection.raw_write(world_stop_packet) kick_packet = build_packet(packets["server_disconnect"], ServerDisconnect.build( dict(reason=reason))) - self.background(player.connection.raw_write(kick_packet)) + await player.connection.raw_write(kick_packet) + player.connection.active = False except AttributeError as e: # Ignore errors in sending the packet. self.logger.debug("Error occurred while kicking user. {}".format(e)) player.connection = None @@ -634,7 +634,7 @@ def ban_by_ip(self, ip, reason, connection): banned_plr = self.get_player_by_ip(ip, check_logged_in=True) if banned_plr: kickstr = "You were kicked.\nReason: {}".format(reason) - self.kick_player(banned_plr, kickstr) + self.background(self.kick_player(banned_plr, kickstr)) ban = IPBan(ip, reason, connection.player.alias) self.shelf["bans"][ip] = ban send_message(connection, "Banned IP: {} with reason: {}" @@ -985,7 +985,7 @@ async def _kick(self, data, connection): send_message(connection, "Player {} is not currently logged in.".format(alias)) return - self.kick_player(p, reason) + self.background(self.kick_player(p, reason)) broadcast(self, "^red;{} has been kicked for reason: " "{}^reset;".format(alias, reason)) From fcb3aa09c6029335c96b4d993e905e5d5c20522d Mon Sep 17 00:00:00 2001 From: Mofurka <94404509+Mofurka@users.noreply.github.com> Date: Sun, 6 Apr 2025 13:49:14 +0500 Subject: [PATCH 4/4] Update server.py --- server.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/server.py b/server.py index a3fe3d0..c6602b4 100644 --- a/server.py +++ b/server.py @@ -48,6 +48,9 @@ def __init__(self, reader, writer, config, factory): self._client_read_future = None self._server_write_future = None self._client_write_future = None + + self.active = True + logger.info("Received connection from {}".format(self.client_ip)) def start_zstd(self): @@ -169,8 +172,13 @@ async def send_message(self, message, *messages, mode=ChatReceiveMode.BROADCAST, logger.exception(err) async def raw_write(self, data): - self._writer.write(data) - await self._writer.drain() + if not self.active: + return # stop writing + try: + self._writer.write(data) + await self._writer.drain() + except Exception as e: + logger.error(f"Exception in raw_write: {e}") async def client_raw_write(self, data): self._client_writer.write(data) @@ -355,4 +363,4 @@ async def main(): try: asyncio.run(main()) except KeyboardInterrupt: - logger.info("Exited due to interrupt.") \ No newline at end of file + logger.info("Exited due to interrupt.")