diff --git a/plugins/player_manager.py b/plugins/player_manager.py index d05dea6..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 @@ -603,10 +603,16 @@ 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) + )) + 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 @@ -628,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: {}" @@ -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: @@ -980,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)) 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.") 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