From 2d56aa50b9469a53ec6bfbddc2f5337624dbf170 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Mon, 13 Feb 2023 11:32:32 +0000 Subject: [PATCH] A bunch of mostly inseparable changes to PlayerPreLoginEvent including support for separated disconnect reasons and disconnect screen messages (closes #4512) While the refactoring of kick reason -> kick flag wasn't exactly in my agenda, I realized that these changes would become pretty confusing and inconsistent with other events if they weren't refactored. Hopefully I don't have to break this API again for a while... --- src/event/player/PlayerPreLoginEvent.php | 100 ++++++++++++------ .../mcpe/handler/LoginPacketHandler.php | 8 +- 2 files changed, 70 insertions(+), 38 deletions(-) diff --git a/src/event/player/PlayerPreLoginEvent.php b/src/event/player/PlayerPreLoginEvent.php index 8a3bbec9f..5a69c0e17 100644 --- a/src/event/player/PlayerPreLoginEvent.php +++ b/src/event/player/PlayerPreLoginEvent.php @@ -40,20 +40,22 @@ use function count; * could be a hacker posing as another player. */ class PlayerPreLoginEvent extends Event{ - public const KICK_REASON_PLUGIN = 0; - public const KICK_REASON_SERVER_FULL = 1; - public const KICK_REASON_SERVER_WHITELISTED = 2; - public const KICK_REASON_BANNED = 3; + public const KICK_FLAG_PLUGIN = 0; + public const KICK_FLAG_SERVER_FULL = 1; + public const KICK_FLAG_SERVER_WHITELISTED = 2; + public const KICK_FLAG_BANNED = 3; - public const KICK_REASON_PRIORITY = [ - self::KICK_REASON_PLUGIN, //Plugin reason should always take priority over anything else - self::KICK_REASON_SERVER_FULL, - self::KICK_REASON_SERVER_WHITELISTED, - self::KICK_REASON_BANNED + public const KICK_FLAG_PRIORITY = [ + self::KICK_FLAG_PLUGIN, //Plugin reason should always take priority over anything else + self::KICK_FLAG_SERVER_FULL, + self::KICK_FLAG_SERVER_WHITELISTED, + self::KICK_FLAG_BANNED ]; /** @var Translatable[]|string[] reason const => associated message */ - protected array $kickReasons = []; + protected array $disconnectReasons = []; + /** @var Translatable[]|string[] */ + protected array $disconnectScreenMessages = []; public function __construct( private PlayerInfo $playerInfo, @@ -88,27 +90,31 @@ class PlayerPreLoginEvent extends Event{ } /** - * Returns an array of kick reasons currently assigned. + * Returns an array of kick flags currently assigned. * * @return int[] */ - public function getKickReasons() : array{ - return array_keys($this->kickReasons); + public function getKickFlags() : array{ + return array_keys($this->disconnectReasons); } /** - * Returns whether the given kick reason is set for this event. + * Returns whether the given kick flag is set for this event. */ - public function isKickReasonSet(int $flag) : bool{ - return isset($this->kickReasons[$flag]); + public function isKickFlagSet(int $flag) : bool{ + return isset($this->disconnectReasons[$flag]); } /** * Sets a reason to disallow the player to continue authenticating, with a message. * This can also be used to change kick messages for already-set flags. + * + * @param Translatable|string $disconnectReason Shown in the server log - this should be a short one-line message + * @param Translatable|string|null $disconnectScreenMessage Shown on the player's disconnection screen (null will use the reason) */ - public function setKickReason(int $flag, Translatable|string $message) : void{ - $this->kickReasons[$flag] = $message; + public function setKickFlag(int $flag, Translatable|string $disconnectReason, Translatable|string|null $disconnectScreenMessage = null) : void{ + $this->disconnectReasons[$flag] = $disconnectReason; + $this->disconnectScreenMessages[$flag] = $disconnectScreenMessage ?? $disconnectReason; } /** @@ -117,43 +123,69 @@ class PlayerPreLoginEvent extends Event{ * * @param int $flag Specific flag to clear. */ - public function clearKickReason(int $flag) : void{ - unset($this->kickReasons[$flag]); + public function clearKickFlag(int $flag) : void{ + unset($this->disconnectReasons[$flag], $this->disconnectScreenMessages[$flag]); } /** * Clears all pre-assigned kick reasons, allowing the player to continue logging in. */ - public function clearAllKickReasons() : void{ - $this->kickReasons = []; + public function clearAllKickFlags() : void{ + $this->disconnectReasons = []; + $this->disconnectScreenMessages = []; } /** * Returns whether the player is allowed to continue logging in. */ public function isAllowed() : bool{ - return count($this->kickReasons) === 0; + return count($this->disconnectReasons) === 0; } /** - * Returns the kick message provided for the given kick flag, or null if not set. + * Returns the disconnect reason provided for the given kick flag, or null if not set. + * This is the message which will be shown in the server log and on the console. */ - public function getKickMessage(int $flag) : Translatable|string|null{ - return $this->kickReasons[$flag] ?? null; + public function getDisconnectReason(int $flag) : Translatable|string|null{ + return $this->disconnectReasons[$flag] ?? null; } /** - * Returns the final kick message which will be shown on the disconnect screen. - * - * Note: Only one message (the highest priority one) will be shown. See priority order to decide how to set your + * Returns the disconnect screen message provided for the given kick flag, or null if not set. + * This is the message shown to the player on the disconnect screen. + */ + public function getDisconnectScreenMessage(int $flag) : Translatable|string|null{ + return $this->disconnectScreenMessages[$flag] ?? null; + } + + /** + * Resolves the message that will be shown in the server log if the player is kicked. + * Only one message (the highest priority one) will be shown. See priority order to decide how to set your * messages. * - * @see PlayerPreLoginEvent::KICK_REASON_PRIORITY + * @see PlayerPreLoginEvent::KICK_FLAG_PRIORITY */ - public function getFinalKickMessage() : Translatable|string{ - foreach(self::KICK_REASON_PRIORITY as $p){ - if(isset($this->kickReasons[$p])){ - return $this->kickReasons[$p]; + public function getFinalDisconnectReason() : Translatable|string{ + foreach(self::KICK_FLAG_PRIORITY as $p){ + if(isset($this->disconnectReasons[$p])){ + return $this->disconnectReasons[$p]; + } + } + + return ""; + } + + /** + * Resolves the message that will be shown on the player's disconnect screen if they are kicked. + * Only one message (the highest priority one) will be shown. See priority order to decide how to set your + * messages. + * + * @see PlayerPreLoginEvent::KICK_FLAG_PRIORITY + */ + public function getFinalDisconnectScreenMessage() : Translatable|string{ + foreach(self::KICK_FLAG_PRIORITY as $p){ + if(isset($this->disconnectScreenMessages[$p])){ + return $this->disconnectScreenMessages[$p]; } } diff --git a/src/network/mcpe/handler/LoginPacketHandler.php b/src/network/mcpe/handler/LoginPacketHandler.php index 744896b4d..acc425099 100644 --- a/src/network/mcpe/handler/LoginPacketHandler.php +++ b/src/network/mcpe/handler/LoginPacketHandler.php @@ -117,10 +117,10 @@ class LoginPacketHandler extends PacketHandler{ $this->server->requiresAuthentication() ); if($this->server->getNetwork()->getValidConnectionCount() > $this->server->getMaxPlayers()){ - $ev->setKickReason(PlayerPreLoginEvent::KICK_REASON_SERVER_FULL, KnownTranslationFactory::disconnectionScreen_serverFull()); + $ev->setKickFlag(PlayerPreLoginEvent::KICK_FLAG_SERVER_FULL, KnownTranslationFactory::disconnectionScreen_serverFull()); } if(!$this->server->isWhitelisted($playerInfo->getUsername())){ - $ev->setKickReason(PlayerPreLoginEvent::KICK_REASON_SERVER_WHITELISTED, KnownTranslationFactory::pocketmine_disconnect_whitelisted()); + $ev->setKickFlag(PlayerPreLoginEvent::KICK_FLAG_SERVER_WHITELISTED, KnownTranslationFactory::pocketmine_disconnect_whitelisted()); } $banMessage = null; @@ -132,12 +132,12 @@ class LoginPacketHandler extends PacketHandler{ $banMessage = KnownTranslationFactory::pocketmine_disconnect_ban($banReason !== "" ? $banReason : KnownTranslationFactory::pocketmine_disconnect_ban_ip()); } if($banMessage !== null){ - $ev->setKickReason(PlayerPreLoginEvent::KICK_REASON_BANNED, $banMessage); + $ev->setKickFlag(PlayerPreLoginEvent::KICK_FLAG_BANNED, $banMessage); } $ev->call(); if(!$ev->isAllowed()){ - $this->session->disconnect($ev->getFinalKickMessage()); + $this->session->disconnect($ev->getFinalDisconnectReason(), $ev->getFinalDisconnectScreenMessage()); return true; }