Skip to content
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

New broadcast subscriber API #5353

Closed
wants to merge 9 commits into from
39 changes: 39 additions & 0 deletions src/ChatBroadcastSubscriber.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/

declare(strict_types=1);

namespace pocketmine;

use pocketmine\lang\Translatable;

/**
* This interface can be implemented in order to receive messages from the server's global broadcast channels.
*/
interface ChatBroadcastSubscriber{

/**
* Called when a message is broadcasted on any channel that this receiver is subscribed to.
*
* @see Server::subscribeToBroadcastChannel()
*/
public function onBroadcast(string $channelId, Translatable|string $message) : void;
}
22 changes: 11 additions & 11 deletions src/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,8 @@ class Server{
private SignalHandler $signalHandler;

/**
* @var CommandSender[][]
* @phpstan-var array<string, array<int, CommandSender>>
* @var ChatBroadcastSubscriber[][]
* @phpstan-var array<string, array<int, ChatBroadcastSubscriber>>
*/
private array $broadcastSubscribers = [];

Expand Down Expand Up @@ -1056,7 +1056,7 @@ public function __construct(
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_donate(TextFormat::AQUA . "https://patreon.com/pocketminemp" . TextFormat::RESET)));
$this->logger->info($this->language->translate(KnownTranslationFactory::pocketmine_server_startFinished(strval(round(microtime(true) - $this->startTime, 3)))));

$forwarder = new BroadcastLoggerForwarder($this, $this->logger, $this->language);
$forwarder = new BroadcastLoggerForwarder($this->logger, $this->language);
$this->subscribeToBroadcastChannel(self::BROADCAST_CHANNEL_ADMINISTRATIVE, $forwarder);
$this->subscribeToBroadcastChannel(self::BROADCAST_CHANNEL_USERS, $forwarder);

Expand Down Expand Up @@ -1251,14 +1251,14 @@ private function startupPrepareNetworkInterfaces() : bool{
* Subscribes to a particular message broadcast channel.
* The channel ID can be any arbitrary string.
*/
public function subscribeToBroadcastChannel(string $channelId, CommandSender $subscriber) : void{
public function subscribeToBroadcastChannel(string $channelId, ChatBroadcastSubscriber $subscriber) : void{
$this->broadcastSubscribers[$channelId][spl_object_id($subscriber)] = $subscriber;
}

/**
* Unsubscribes from a particular message broadcast channel.
*/
public function unsubscribeFromBroadcastChannel(string $channelId, CommandSender $subscriber) : void{
public function unsubscribeFromBroadcastChannel(string $channelId, ChatBroadcastSubscriber $subscriber) : void{
if(isset($this->broadcastSubscribers[$channelId][spl_object_id($subscriber)])){
if(count($this->broadcastSubscribers[$channelId]) === 1){
unset($this->broadcastSubscribers[$channelId]);
Expand All @@ -1271,30 +1271,30 @@ public function unsubscribeFromBroadcastChannel(string $channelId, CommandSender
/**
* Unsubscribes from all broadcast channels.
*/
public function unsubscribeFromAllBroadcastChannels(CommandSender $subscriber) : void{
public function unsubscribeFromAllBroadcastChannels(ChatBroadcastSubscriber $subscriber) : void{
foreach(Utils::stringifyKeys($this->broadcastSubscribers) as $channelId => $recipients){
$this->unsubscribeFromBroadcastChannel($channelId, $subscriber);
}
}

/**
* Returns a list of all the CommandSenders subscribed to the given broadcast channel.
* Returns a list of all the broadcast subscribers subscribed to the given broadcast channel.
*
* @return CommandSender[]
* @phpstan-return array<int, CommandSender>
* @return ChatBroadcastSubscriber[]
* @phpstan-return array<int, ChatBroadcastSubscriber>
*/
public function getBroadcastChannelSubscribers(string $channelId) : array{
return $this->broadcastSubscribers[$channelId] ?? [];
}

/**
* @param CommandSender[]|null $recipients
* @param ChatBroadcastSubscriber[]|null $recipients
*/
public function broadcastMessage(Translatable|string $message, ?array $recipients = null) : int{
$recipients = $recipients ?? $this->getBroadcastChannelSubscribers(self::BROADCAST_CHANNEL_USERS);

foreach($recipients as $recipient){
$recipient->sendMessage($message);
$recipient->onBroadcast(self::BROADCAST_CHANNEL_USERS, $message);
}

return count($recipients);
Expand Down
15 changes: 6 additions & 9 deletions src/command/Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
use pocketmine\lang\Translatable;
use pocketmine\permission\PermissionManager;
use pocketmine\Server;
use pocketmine\utils\BroadcastLoggerForwarder;
use pocketmine\utils\TextFormat;
use function explode;
use function implode;
Expand Down Expand Up @@ -223,19 +222,17 @@ public function setUsage(Translatable|string $usage) : void{
}

public static function broadcastCommandMessage(CommandSender $source, Translatable|string $message, bool $sendToSource = true) : void{
$users = $source->getServer()->getBroadcastChannelSubscribers(Server::BROADCAST_CHANNEL_ADMINISTRATIVE);
$result = KnownTranslationFactory::chat_type_admin($source->getName(), $message);
$colored = $result->prefix(TextFormat::GRAY . TextFormat::ITALIC);
$subscribers = $source->getServer()->getBroadcastChannelSubscribers(Server::BROADCAST_CHANNEL_ADMINISTRATIVE);
$broadcast = KnownTranslationFactory::chat_type_admin($source->getName(), $message);

if($sendToSource){
$source->sendMessage($message);
}

foreach($users as $user){
if($user instanceof BroadcastLoggerForwarder){
$user->sendMessage($result);
}elseif($user !== $source){
$user->sendMessage($colored);
foreach($subscribers as $user){
//TODO: this check is flaky, since the sender might have broadcast subscribers that we don't know about
if($user !== $source){
dktapps marked this conversation as resolved.
Show resolved Hide resolved
$user->onBroadcast(Server::BROADCAST_CHANNEL_ADMINISTRATIVE, $broadcast);
}
}
}
Expand Down
10 changes: 5 additions & 5 deletions src/event/player/PlayerChatEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

namespace pocketmine\event\player;

use pocketmine\command\CommandSender;
use pocketmine\ChatBroadcastSubscriber;
use pocketmine\event\Cancellable;
use pocketmine\event\CancellableTrait;
use pocketmine\player\chat\ChatFormatter;
Expand All @@ -37,7 +37,7 @@ class PlayerChatEvent extends PlayerEvent implements Cancellable{
use CancellableTrait;

/**
* @param CommandSender[] $recipients
* @param ChatBroadcastSubscriber[] $recipients
*/
public function __construct(
Player $player,
Expand Down Expand Up @@ -72,17 +72,17 @@ public function setFormatter(ChatFormatter $formatter) : void{
}

/**
* @return CommandSender[]
* @return ChatBroadcastSubscriber[]
*/
public function getRecipients() : array{
return $this->recipients;
}

/**
* @param CommandSender[] $recipients
* @param ChatBroadcastSubscriber[] $recipients
*/
public function setRecipients(array $recipients) : void{
Utils::validateArrayValueType($recipients, function(CommandSender $_) : void{});
Utils::validateArrayValueType($recipients, function(ChatBroadcastSubscriber $_) : void{});
$this->recipients = $recipients;
}
}
14 changes: 13 additions & 1 deletion src/player/Player.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
use pocketmine\block\BlockTypeTags;
use pocketmine\block\UnknownBlock;
use pocketmine\block\VanillaBlocks;
use pocketmine\ChatBroadcastSubscriber;
use pocketmine\command\CommandSender;
use pocketmine\crafting\CraftingGrid;
use pocketmine\data\java\GameModeIdMap;
Expand Down Expand Up @@ -167,7 +168,7 @@
/**
* Main class that handles networking, recovery, and packet sending to the server part
*/
class Player extends Human implements CommandSender, ChunkListener, IPlayer{
class Player extends Human implements ChatBroadcastSubscriber, CommandSender, ChunkListener, IPlayer{
use PermissibleDelegateTrait;

private const MOVES_PER_TICK = 2;
Expand Down Expand Up @@ -2130,6 +2131,17 @@ public function setTitleDuration(int $fadeIn, int $stay, int $fadeOut) : void{
}
}

public function onBroadcast(string $channelId, Translatable|string $message) : void{
if($channelId === Server::BROADCAST_CHANNEL_ADMINISTRATIVE){
if($message instanceof Translatable){
$message = $message->prefix(TextFormat::GRAY . TextFormat::ITALIC);
}else{
$message = TextFormat::GRAY . TextFormat::ITALIC . $message;
}
}
$this->sendMessage($message);
}

/**
* Sends a direct chat message to a player
*/
Expand Down
40 changes: 4 additions & 36 deletions src/utils/BroadcastLoggerForwarder.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,58 +23,26 @@

namespace pocketmine\utils;

use pocketmine\command\CommandSender;
use pocketmine\ChatBroadcastSubscriber;
use pocketmine\lang\Language;
use pocketmine\lang\Translatable;
use pocketmine\permission\PermissibleBase;
use pocketmine\permission\PermissibleDelegateTrait;
use pocketmine\Server;
use const PHP_INT_MAX;

/**
* Forwards any messages it receives via sendMessage() to the given logger. Used for forwarding chat messages and
* command audit log messages to the server log file.
*
* Unfortunately, broadcast subscribers are currently required to implement CommandSender, so this class has to include
* a lot of useless methods.
*/
final class BroadcastLoggerForwarder implements CommandSender{
use PermissibleDelegateTrait;
final class BroadcastLoggerForwarder implements ChatBroadcastSubscriber{

public function __construct(
private Server $server, //annoying useless dependency
private \Logger $logger,
private Language $language
){
//this doesn't need any permissions
$this->perm = new PermissibleBase([]);
}

public function getLanguage() : Language{
return $this->language;
}
){}

public function sendMessage(Translatable|string $message) : void{
public function onBroadcast(string $channelId, Translatable|string $message) : void{
if($message instanceof Translatable){
$this->logger->info($this->language->translate($message));
}else{
$this->logger->info($message);
}
}

public function getServer() : Server{
return $this->server;
}

public function getName() : string{
return "Broadcast Logger Forwarder";
}

public function getScreenLineHeight() : int{
return PHP_INT_MAX;
}

public function setScreenLineHeight(?int $height) : void{
//NOOP
}
}