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
40 changes: 40 additions & 0 deletions src/MessageBroadcastSubscriber.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?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\command\CommandSender;
use pocketmine\lang\Translatable;

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

/**
* Called when a message is broadcasted on any channel that this receiver is subscribed to.
*
* @see Server::subscribeToBroadcastChannel()
*/
public function onMessage(CommandSender $source, Translatable|string $message, string $channelId) : void;
}
36 changes: 36 additions & 0 deletions src/MinecraftMessageBroadcastSubscriber.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?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\command\CommandSender;
use pocketmine\lang\Translatable;

interface MinecraftMessageBroadcastSubscriber extends MessageBroadcastSubscriber{

public function onTip(CommandSender $source, Translatable|string $message, string $channelId) : void;

public function onPopup(CommandSender $source, Translatable|string $message, string $channelId) : void;

public function onTitle(CommandSender $source, string $title, string $subtitle, int $fadeIn, int $stay, int $fadeOut, string $channelId) : void;
}
88 changes: 55 additions & 33 deletions src/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,11 @@
use pocketmine\timings\TimingsHandler;
use pocketmine\updater\UpdateChecker;
use pocketmine\utils\AssumptionFailedError;
use pocketmine\utils\BroadcastLoggerForwarder;
use pocketmine\utils\Config;
use pocketmine\utils\Filesystem;
use pocketmine\utils\Internet;
use pocketmine\utils\MainLogger;
use pocketmine\utils\BroadcastLoggerForwarder;
use pocketmine\utils\NotCloneable;
use pocketmine\utils\NotSerializable;
use pocketmine\utils\Process;
Expand Down Expand Up @@ -298,8 +298,8 @@
private SignalHandler $signalHandler;

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

Expand Down Expand Up @@ -1056,9 +1056,10 @@
$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);
$this->subscribeToBroadcastChannel(self::BROADCAST_CHANNEL_USERS, $forwarder);

//TODO: move console parts to a separate component
if($this->configGroup->getPropertyBool(Yml::CONSOLE_ENABLE_INPUT, true)){
Expand Down Expand Up @@ -1247,18 +1248,29 @@
return true;
}

private function getBroadcastChannel(string $channelId) : ?MessageChannel{

Check failure on line 1251 in src/Server.php

View workflow job for this annotation

GitHub Actions / PHP 8.1 / PHPStan analysis

Method pocketmine\Server::getBroadcastChannel() has invalid return type pocketmine\MessageChannel.

Check failure on line 1251 in src/Server.php

View workflow job for this annotation

GitHub Actions / PHP 8.1 / PHPStan analysis

Method pocketmine\Server::getBroadcastChannel() has invalid return type pocketmine\MessageChannel.

Check failure on line 1251 in src/Server.php

View workflow job for this annotation

GitHub Actions / PHP 8.2 / PHPStan analysis

Method pocketmine\Server::getBroadcastChannel() has invalid return type pocketmine\MessageChannel.

Check failure on line 1251 in src/Server.php

View workflow job for this annotation

GitHub Actions / PHP 8.2 / PHPStan analysis

Method pocketmine\Server::getBroadcastChannel() has invalid return type pocketmine\MessageChannel.

Check failure on line 1251 in src/Server.php

View workflow job for this annotation

GitHub Actions / PHP 8.3 / PHPStan analysis

Method pocketmine\Server::getBroadcastChannel() has invalid return type pocketmine\MessageChannel.

Check failure on line 1251 in src/Server.php

View workflow job for this annotation

GitHub Actions / PHP 8.3 / PHPStan analysis

Method pocketmine\Server::getBroadcastChannel() has invalid return type pocketmine\MessageChannel.
return $this->broadcastChannels[$channelId] ?? null;
}

public function createBroadcastChannel(string $channelId, ?string $permission) : void{
if(isset($this->broadcastChannels[$channelId])){
throw new \InvalidArgumentException("Channel \"$channelId\" already exists");
}
$this->broadcastChannels[$channelId] = new MessageChannel($permission);

Check failure on line 1259 in src/Server.php

View workflow job for this annotation

GitHub Actions / PHP 8.1 / PHPStan analysis

Access to an undefined property pocketmine\Server::$broadcastChannels.

Check failure on line 1259 in src/Server.php

View workflow job for this annotation

GitHub Actions / PHP 8.1 / PHPStan analysis

Instantiated class pocketmine\MessageChannel not found.

Check failure on line 1259 in src/Server.php

View workflow job for this annotation

GitHub Actions / PHP 8.1 / PHPStan analysis

Access to an undefined property pocketmine\Server::$broadcastChannels.

Check failure on line 1259 in src/Server.php

View workflow job for this annotation

GitHub Actions / PHP 8.1 / PHPStan analysis

Instantiated class pocketmine\MessageChannel not found.

Check failure on line 1259 in src/Server.php

View workflow job for this annotation

GitHub Actions / PHP 8.2 / PHPStan analysis

Access to an undefined property pocketmine\Server::$broadcastChannels.

Check failure on line 1259 in src/Server.php

View workflow job for this annotation

GitHub Actions / PHP 8.2 / PHPStan analysis

Instantiated class pocketmine\MessageChannel not found.

Check failure on line 1259 in src/Server.php

View workflow job for this annotation

GitHub Actions / PHP 8.2 / PHPStan analysis

Access to an undefined property pocketmine\Server::$broadcastChannels.

Check failure on line 1259 in src/Server.php

View workflow job for this annotation

GitHub Actions / PHP 8.2 / PHPStan analysis

Instantiated class pocketmine\MessageChannel not found.

Check failure on line 1259 in src/Server.php

View workflow job for this annotation

GitHub Actions / PHP 8.3 / PHPStan analysis

Access to an undefined property pocketmine\Server::$broadcastChannels.

Check failure on line 1259 in src/Server.php

View workflow job for this annotation

GitHub Actions / PHP 8.3 / PHPStan analysis

Instantiated class pocketmine\MessageChannel not found.

Check failure on line 1259 in src/Server.php

View workflow job for this annotation

GitHub Actions / PHP 8.3 / PHPStan analysis

Access to an undefined property pocketmine\Server::$broadcastChannels.

Check failure on line 1259 in src/Server.php

View workflow job for this annotation

GitHub Actions / PHP 8.3 / PHPStan analysis

Instantiated class pocketmine\MessageChannel not found.
}

/**
* 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, MessageBroadcastSubscriber $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, MessageBroadcastSubscriber $subscriber) : void{
if(isset($this->broadcastSubscribers[$channelId][spl_object_id($subscriber)])){
if(count($this->broadcastSubscribers[$channelId]) === 1){
unset($this->broadcastSubscribers[$channelId]);
Expand All @@ -1271,86 +1283,96 @@
/**
* Unsubscribes from all broadcast channels.
*/
public function unsubscribeFromAllBroadcastChannels(CommandSender $subscriber) : void{
public function unsubscribeFromAllBroadcastChannels(MessageBroadcastSubscriber $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 with permission to
* receive messages from it.
*
* @return CommandSender[]
* @phpstan-return array<int, CommandSender>
* @return MessageBroadcastSubscriber[]
* @phpstan-return array<int, MessageBroadcastSubscriber>
*/
public function getBroadcastChannelSubscribers(string $channelId) : array{
return $this->broadcastSubscribers[$channelId] ?? [];
}

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

Check failure on line 1307 in src/Server.php

View workflow job for this annotation

GitHub Actions / PHP 8.1 / PHPStan analysis

Call to method getPermittedSubscribers() on an unknown class pocketmine\MessageChannel.

Check failure on line 1307 in src/Server.php

View workflow job for this annotation

GitHub Actions / PHP 8.1 / PHPStan analysis

Call to method getPermittedSubscribers() on an unknown class pocketmine\MessageChannel.

Check failure on line 1307 in src/Server.php

View workflow job for this annotation

GitHub Actions / PHP 8.2 / PHPStan analysis

Call to method getPermittedSubscribers() on an unknown class pocketmine\MessageChannel.

Check failure on line 1307 in src/Server.php

View workflow job for this annotation

GitHub Actions / PHP 8.2 / PHPStan analysis

Call to method getPermittedSubscribers() on an unknown class pocketmine\MessageChannel.

Check failure on line 1307 in src/Server.php

View workflow job for this annotation

GitHub Actions / PHP 8.3 / PHPStan analysis

Call to method getPermittedSubscribers() on an unknown class pocketmine\MessageChannel.

Check failure on line 1307 in src/Server.php

View workflow job for this annotation

GitHub Actions / PHP 8.3 / PHPStan analysis

Call to method getPermittedSubscribers() on an unknown class pocketmine\MessageChannel.

foreach($recipients as $recipient){
$recipient->sendMessage($message);
$recipient->onMessage($source, $message, $channelId);
}

return count($recipients);
}

/**
* @return Player[]
* @return MinecraftMessageBroadcastSubscriber[]
*/
private function getPlayerBroadcastSubscribers(string $channelId) : array{
private function getMinecraftBroadcastSubscribers(string $channelId) : array{
/** @var Player[] $players */
$players = [];
foreach($this->broadcastSubscribers[$channelId] as $subscriber){
if($subscriber instanceof Player){
foreach($this->broadcastSubscribers[$channelId] ?? [] as $subscriber){
if($subscriber instanceof MinecraftMessageBroadcastSubscriber){
$players[spl_object_id($subscriber)] = $subscriber;
}
}
return $players;
}

/**
* @param Player[]|null $recipients
* @param MinecraftMessageBroadcastSubscriber[]|null $recipients
*/
public function broadcastTip(string $tip, ?array $recipients = null) : int{
$recipients = $recipients ?? $this->getPlayerBroadcastSubscribers(self::BROADCAST_CHANNEL_USERS);
public function broadcastTip(CommandSender $source, string $tip, string $channelId = self::BROADCAST_CHANNEL_USERS, ?array $recipients = null) : int{
$recipients = $recipients ?? $this->getMinecraftBroadcastSubscribers($channelId);

foreach($recipients as $recipient){
$recipient->sendTip($tip);
$recipient->onTip($source, $tip, $channelId);
}

return count($recipients);
}

/**
* @param Player[]|null $recipients
* @param MinecraftMessageBroadcastSubscriber[]|null $recipients
*/
public function broadcastPopup(string $popup, ?array $recipients = null) : int{
$recipients = $recipients ?? $this->getPlayerBroadcastSubscribers(self::BROADCAST_CHANNEL_USERS);
public function broadcastPopup(CommandSender $source, string $popup, string $channelId = self::BROADCAST_CHANNEL_USERS, ?array $recipients = null) : int{
$recipients = $recipients ?? $this->getMinecraftBroadcastSubscribers($channelId);

foreach($recipients as $recipient){
$recipient->sendPopup($popup);
$recipient->onPopup($source, $popup, $channelId);
}

return count($recipients);
}

/**
* @param int $fadeIn Duration in ticks for fade-in. If -1 is given, client-sided defaults will be used.
* @param int $stay Duration in ticks to stay on screen for
* @param int $fadeOut Duration in ticks for fade-out.
* @param Player[]|null $recipients
* @param int $fadeIn Duration in ticks for fade-in. If -1 is given, client-sided defaults will be used.
* @param int $stay Duration in ticks to stay on screen for
* @param int $fadeOut Duration in ticks for fade-out.
* @param MinecraftMessageBroadcastSubscriber[]|null $recipients
*/
public function broadcastTitle(string $title, string $subtitle = "", int $fadeIn = -1, int $stay = -1, int $fadeOut = -1, ?array $recipients = null) : int{
$recipients = $recipients ?? $this->getPlayerBroadcastSubscribers(self::BROADCAST_CHANNEL_USERS);
public function broadcastTitle(
CommandSender $source,
string $title,
string $subtitle = "",
int $fadeIn = -1,
int $stay = -1,
int $fadeOut = -1,
string $channelId = self::BROADCAST_CHANNEL_USERS,
?array $recipients = null
) : int{
$recipients = $recipients ?? $this->getMinecraftBroadcastSubscribers($channelId);

foreach($recipients as $recipient){
$recipient->sendTitle($title, $subtitle, $fadeIn, $stay, $fadeOut);
$recipient->onTitle($source, $title, $subtitle, $fadeIn, $stay, $fadeOut, $channelId);
}

return count($recipients);
Expand Down
13 changes: 2 additions & 11 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,21 +222,13 @@ 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);
$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);
}
}
$source->getServer()->broadcastMessage($source, $broadcast, Server::BROADCAST_CHANNEL_ADMINISTRATIVE);
}

public function __toString() : string{
Expand Down
5 changes: 4 additions & 1 deletion src/command/defaults/MeCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ public function execute(CommandSender $sender, string $commandLabel, array $args
throw new InvalidCommandSyntaxException();
}

$sender->getServer()->broadcastMessage(KnownTranslationFactory::chat_type_emote($sender instanceof Player ? $sender->getDisplayName() : $sender->getName(), TextFormat::RESET . implode(" ", $args)));
$sender->getServer()->broadcastMessage(
$sender,
KnownTranslationFactory::chat_type_emote($sender instanceof Player ? $sender->getDisplayName() : $sender->getName(), TextFormat::RESET . implode(" ", $args))
);

return true;
}
Expand Down
11 changes: 7 additions & 4 deletions src/command/defaults/SayCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,13 @@ public function execute(CommandSender $sender, string $commandLabel, array $args
throw new InvalidCommandSyntaxException();
}

$sender->getServer()->broadcastMessage(KnownTranslationFactory::chat_type_announcement(
$sender instanceof Player ? $sender->getDisplayName() : ($sender instanceof ConsoleCommandSender ? "Server" : $sender->getName()),
implode(" ", $args)
)->prefix(TextFormat::LIGHT_PURPLE));
$sender->getServer()->broadcastMessage(
$sender,
KnownTranslationFactory::chat_type_announcement(
$sender instanceof Player ? $sender->getDisplayName() : ($sender instanceof ConsoleCommandSender ? "Server" : $sender->getName()),
implode(" ", $args)
)->prefix(TextFormat::LIGHT_PURPLE)
);
return true;
}
}
10 changes: 5 additions & 5 deletions src/event/player/PlayerChatEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@

namespace pocketmine\event\player;

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

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

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

/**
* @param CommandSender[] $recipients
* @param MessageBroadcastSubscriber[] $recipients
*/
public function setRecipients(array $recipients) : void{
Utils::validateArrayValueType($recipients, function(CommandSender $_) : void{});
Utils::validateArrayValueType($recipients, function(MessageBroadcastSubscriber $_) : void{});
$this->recipients = $recipients;
}
}
Loading
Loading