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...
This commit is contained in:
Dylan K. Taylor 2023-02-13 11:32:32 +00:00
parent 5d0388e747
commit 2d56aa50b9
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
2 changed files with 70 additions and 38 deletions

View File

@ -40,20 +40,22 @@ use function count;
* could be a hacker posing as another player. * could be a hacker posing as another player.
*/ */
class PlayerPreLoginEvent extends Event{ class PlayerPreLoginEvent extends Event{
public const KICK_REASON_PLUGIN = 0; public const KICK_FLAG_PLUGIN = 0;
public const KICK_REASON_SERVER_FULL = 1; public const KICK_FLAG_SERVER_FULL = 1;
public const KICK_REASON_SERVER_WHITELISTED = 2; public const KICK_FLAG_SERVER_WHITELISTED = 2;
public const KICK_REASON_BANNED = 3; public const KICK_FLAG_BANNED = 3;
public const KICK_REASON_PRIORITY = [ public const KICK_FLAG_PRIORITY = [
self::KICK_REASON_PLUGIN, //Plugin reason should always take priority over anything else self::KICK_FLAG_PLUGIN, //Plugin reason should always take priority over anything else
self::KICK_REASON_SERVER_FULL, self::KICK_FLAG_SERVER_FULL,
self::KICK_REASON_SERVER_WHITELISTED, self::KICK_FLAG_SERVER_WHITELISTED,
self::KICK_REASON_BANNED self::KICK_FLAG_BANNED
]; ];
/** @var Translatable[]|string[] reason const => associated message */ /** @var Translatable[]|string[] reason const => associated message */
protected array $kickReasons = []; protected array $disconnectReasons = [];
/** @var Translatable[]|string[] */
protected array $disconnectScreenMessages = [];
public function __construct( public function __construct(
private PlayerInfo $playerInfo, 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[] * @return int[]
*/ */
public function getKickReasons() : array{ public function getKickFlags() : array{
return array_keys($this->kickReasons); 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{ public function isKickFlagSet(int $flag) : bool{
return isset($this->kickReasons[$flag]); return isset($this->disconnectReasons[$flag]);
} }
/** /**
* Sets a reason to disallow the player to continue authenticating, with a message. * 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. * 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{ public function setKickFlag(int $flag, Translatable|string $disconnectReason, Translatable|string|null $disconnectScreenMessage = null) : void{
$this->kickReasons[$flag] = $message; $this->disconnectReasons[$flag] = $disconnectReason;
$this->disconnectScreenMessages[$flag] = $disconnectScreenMessage ?? $disconnectReason;
} }
/** /**
@ -117,43 +123,69 @@ class PlayerPreLoginEvent extends Event{
* *
* @param int $flag Specific flag to clear. * @param int $flag Specific flag to clear.
*/ */
public function clearKickReason(int $flag) : void{ public function clearKickFlag(int $flag) : void{
unset($this->kickReasons[$flag]); unset($this->disconnectReasons[$flag], $this->disconnectScreenMessages[$flag]);
} }
/** /**
* Clears all pre-assigned kick reasons, allowing the player to continue logging in. * Clears all pre-assigned kick reasons, allowing the player to continue logging in.
*/ */
public function clearAllKickReasons() : void{ public function clearAllKickFlags() : void{
$this->kickReasons = []; $this->disconnectReasons = [];
$this->disconnectScreenMessages = [];
} }
/** /**
* Returns whether the player is allowed to continue logging in. * Returns whether the player is allowed to continue logging in.
*/ */
public function isAllowed() : bool{ 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{ public function getDisconnectReason(int $flag) : Translatable|string|null{
return $this->kickReasons[$flag] ?? null; return $this->disconnectReasons[$flag] ?? null;
} }
/** /**
* Returns the final kick message which will be shown on the disconnect screen. * 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.
* Note: Only one message (the highest priority one) will be shown. See priority order to decide how to set your */
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. * messages.
* *
* @see PlayerPreLoginEvent::KICK_REASON_PRIORITY * @see PlayerPreLoginEvent::KICK_FLAG_PRIORITY
*/ */
public function getFinalKickMessage() : Translatable|string{ public function getFinalDisconnectReason() : Translatable|string{
foreach(self::KICK_REASON_PRIORITY as $p){ foreach(self::KICK_FLAG_PRIORITY as $p){
if(isset($this->kickReasons[$p])){ if(isset($this->disconnectReasons[$p])){
return $this->kickReasons[$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];
} }
} }

View File

@ -117,10 +117,10 @@ class LoginPacketHandler extends PacketHandler{
$this->server->requiresAuthentication() $this->server->requiresAuthentication()
); );
if($this->server->getNetwork()->getValidConnectionCount() > $this->server->getMaxPlayers()){ 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())){ 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; $banMessage = null;
@ -132,12 +132,12 @@ class LoginPacketHandler extends PacketHandler{
$banMessage = KnownTranslationFactory::pocketmine_disconnect_ban($banReason !== "" ? $banReason : KnownTranslationFactory::pocketmine_disconnect_ban_ip()); $banMessage = KnownTranslationFactory::pocketmine_disconnect_ban($banReason !== "" ? $banReason : KnownTranslationFactory::pocketmine_disconnect_ban_ip());
} }
if($banMessage !== null){ if($banMessage !== null){
$ev->setKickReason(PlayerPreLoginEvent::KICK_REASON_BANNED, $banMessage); $ev->setKickFlag(PlayerPreLoginEvent::KICK_FLAG_BANNED, $banMessage);
} }
$ev->call(); $ev->call();
if(!$ev->isAllowed()){ if(!$ev->isAllowed()){
$this->session->disconnect($ev->getFinalKickMessage()); $this->session->disconnect($ev->getFinalDisconnectReason(), $ev->getFinalDisconnectScreenMessage());
return true; return true;
} }