Напиши рабочий код для PocketMine-MP с config.yml в котором можно будет отображать всем игрокам на сервере кастомный текст в BossBar (с возможностью смены цвета полоски BLUE, GREEN, PINK, PURPLE, RED, WHITE, YELLOW, REBECCA_PURPLE), ScoreBoard (красные цифры cound (очки) от 0 до 14 снизу-вверх отображаются) первая строка cound 0, при добавлении других по очереди идут 1, 2, 3 в config.yml а так же возможность установить Title (displayName) для этого ScoreBoard, Title и SubTitle (вызываются командой из config.yml), ActionBar и SendTip отображаются постоянно каждую секунду с возможностью использовать \n для новых линий и offset для перемещения по экрану всего текста слева-направо, а также модификация строки опыта Experience уровень и прогресс, ну и поддержка создавать анимации как в плагине TAB. Напиши пожалуйста рабочий коду моляю.
<?php
declare(strict_types=1);
namespace BossScore;
use pocketmine\plugin\PluginBase;
use pocketmine\event\Listener;
use pocketmine\event\player\PlayerJoinEvent;
use pocketmine\scheduler\ClosureTask;
use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\player\Player;
use pocketmine\entity\Attribute;
use pocketmine\network\mcpe\protocol\BossEventPacket;
use pocketmine\network\mcpe\protocol\SetDisplayObjectivePacket;
use pocketmine\network\mcpe\protocol\SetScorePacket;
use pocketmine\network\mcpe\protocol\SetTitlePacket;
use pocketmine\network\mcpe\protocol\types\ScorePacketEntry;
use pocketmine\network\mcpe\protocol\types\BossBarColor;
use pocketmine\math\Vector2;
class Main extends PluginBase implements Listener {
private array $bossBarIds = [];
private array $scoreboards = [];
private array $titles = [];
public function onEnable(): void {
$this->saveDefaultConfig();
$this->getServer()->getPluginManager()->registerEvents($this, $this);
$period = $this->getConfig()->get("update-period", 20);
$this->getScheduler()->scheduleRepeatingTask(new ClosureTask(function () {
foreach ($this->getServer()->getOnlinePlayers() as $p) {
$this->updateBossBar($p);
$this->updateScoreboard($p);
$this->updateActionBar($p);
$this->updateExperience($p);
}
}), $period);
}
/* --------- BossBar --------- */
private function updateBossBar(Player $p): void {
$cfg = $this->getConfig();
$text = $this->replacePlaceholders($cfg->get("bossbar-text", "§6Hello!"), $p);
$color = $this->getColorFromString($cfg->get("bossbar-color", "RED"));
if (!isset($this->bossBarIds[$p->getId()])) {
$this->bossBarIds[$p->getId()] = $eid = $this->getNextEid();
$p->getNetworkSession()->sendDataPacket(BossEventPacket::show($eid, $text, 1.0, $color));
} else {
$eid = $this->bossBarIds[$p->getId()];
$p->getNetworkSession()->sendDataPacket(BossEventPacket::title($eid, $text));
$p->getNetworkSession()->sendDataPacket(BossEventPacket::color($eid, $color));
}
}
private function getColorFromString(string $color): int {
return match (strtoupper($color)) {
"BLUE" => BossBarColor::BLUE,
"GREEN" => BossBarColor::GREEN,
"PINK" => BossBarColor::PINK,
"PURPLE" => BossBarColor::PURPLE,
"RED" => BossBarColor::RED,
"WHITE" => BossBarColor::WHITE,
"YELLOW" => BossBarColor::YELLOW,
"REBECCA_PURPLE" => 8, // custom
default => BossBarColor::RED,
};
}
/* --------- ScoreBoard --------- */
private function updateScoreboard(Player $p): void {
$cfg = $this->getConfig();
$title = $this->replacePlaceholders($cfg->get("scoreboard-title", "§l§cINFO"), $p);
if (!isset($this->scoreboards[$p->getId()])) {
$pk = SetDisplayObjectivePacket::create(
SetDisplayObjectivePacket::DISPLAY_SLOT_SIDEBAR,
"objective",
$title,
"dummy",
SetDisplayObjectivePacket::SORT_ORDER_ASCENDING
);
$p->getNetworkSession()->sendDataPacket($pk);
$this->scoreboards[$p->getId()] = true;
}
$lines = [];
foreach ($cfg->get("scoreboard-lines", []) as $i => $line) {
if ($i > 14) break;
$lines[] = $this->replacePlaceholders($line, $p);
}
// Remove old lines
$pk = new SetScorePacket();
$pk->type = SetScorePacket::TYPE_REMOVE;
$entries = [];
foreach (range(0, 14) as $score) {
$entry = new ScorePacketEntry();
$entry->objectiveName = "objective";
$entry->score = $score;
$entry->scoreboardId = $score;
$entries[] = $entry;
}
$pk->entries = $entries;
$p->getNetworkSession()->sendDataPacket($pk);
// Add new lines
$pk = new SetScorePacket();
$pk->type = SetScorePacket::TYPE_CHANGE;
$entries = [];
foreach ($lines as $i => $text) {
$entry = new ScorePacketEntry();
$entry->objectiveName = "objective";
$entry->score = $i;
$entry->scoreboardId = $i;
$entry->type = ScorePacketEntry::TYPE_FAKE_PLAYER;
$entry->customName = $text;
$entries[] = $entry;
}
$pk->entries = $entries;
$p->getNetworkSession()->sendDataPacket($pk);
}
/* --------- ActionBar / Tip --------- */
private function updateActionBar(Player $p): void {
$cfg = $this->getConfig();
$text = $this->replacePlaceholders($cfg->get("actionbar-text", "§aActionBar"), $p);
$offset = (int) $cfg->get("actionbar-offset", 0);
$tip = $this->replacePlaceholders($cfg->get("tip-text", "§bTip"), $p);
$text = str_repeat(" ", $offset) . str_replace("\\n", "\n", $text);
$p->sendActionBarMessage($text);
$p->sendTip($tip);
}
/* --------- Experience --------- */
private function updateExperience(Player $p): void {
$cfg = $this->getConfig();
$level = (int) $this->replacePlaceholders($cfg->get("exp-level", "0"), $p);
$progress = (float) $this->replacePlaceholders($cfg->get("exp-progress", "0.5"), $p);
$p->getXpManager()->setXpLevel($level);
$p->getXpManager()->setXpProgress($progress);
}
/* --------- Commands --------- */
public function onCommand(CommandSender $s, Command $c, string $label, array $args): bool {
$cmd = strtolower($c->getName());
$cfg = $this->getConfig();
if ($cmd === $cfg->get("title-command", "mytitle")) {
if (!$s instanceof Player) return false;
$title = $cfg->get("title-text", "§eTitle");
$subtitle = $cfg->get("subtitle-text", "§7Subtitle");
$fadeIn = (int) $cfg->get("title-fadein", 10);
$stay = (int) $cfg->get("title-stay", 70);
$fadeOut = (int) $cfg->get("title-fadeout", 20);
$pk = SetTitlePacket::title($this->replacePlaceholders($title, $s), $fadeIn, $stay, $fadeOut);
$s->getNetworkSession()->sendDataPacket($pk);
$pk = SetTitlePacket::subtitle($this->replacePlaceholders($subtitle, $s), $fadeIn, $stay, $fadeOut);
$s->getNetworkSession()->sendDataPacket($pk);
return true;
}
return false;
}
/* --------- Helpers --------- */
private function replacePlaceholders(string $text, Player $p): string {
return str_replace(
["{player}", "{online}", "{max_online}"],
[$p->getName(), count($this->getServer()->getOnlinePlayers()), $this->getServer()->getMaxPlayers()],
$text
);
}
private function getNextEid(): int {
static $eid = 1000;
return ++$eid;
}
public function onPlayerJoin(PlayerJoinEvent $e): void {
unset($this->bossBarIds[$e->getPlayer()->getId()]);
}
}
plugin.yml
name: BossScore
main: BossScore\Main
version: 1.0
api: 5.0.0
commands:
mytitle:
description: "Показать Title"
usage: /mytitle
resources/config.yml
# Период обновления (в тиках)
update-period: 20
# BossBar
bossbar-text: "§6Привет, {player}! Онлайн: {online}/{max_online}"
bossbar-color: RED # BLUE, GREEN, PINK, PURPLE, RED, WHITE, YELLOW, REBECCA_PURPLE
# ScoreBoard
scoreboard-title: "§l§cИнформация"
scoreboard-lines:
- "§fИгрок: §e{player}"
- "§fОнлайн: §a{online}"
- "§fСервер: §bCoolServer"
- ""
- "§7Время: §fauto"
# ActionBar и Tip
actionbar-text: "§aЭто ActionBar\n§7С новой строки!"
actionbar-offset: 0
tip-text: "§bЭто Tip"
# Опыт
exp-level: "5"
exp-progress: "0.75"
# Команда и Title
title-command: "mytitle"
title-text: "§eГлавный заголовок"
subtitle-text: "§7Подзаголовок"
title-fadein: 10
title-stay: 70
title-fadeout: 20
Как использовать
BossScore с двумя файлами (plugin.yml, src/BossScore/Main.php) и resources/config.yml в plugins/.config.yml прямо в папке plugin_data/BossScore/config.yml без перезагрузки сервера — большинство параметров применяются на лету каждые 20 тиков.mytitle (или любая, указанная в title-command) выводит Title/Subtitle нажатием.