Я использую PocketMine-MP PM API 5.37.3 PHP мне нужен код плагина который создаст ScoreBoard отображаемый всем игрокам с красными цифрами score от 0 до 14 снизу-вверх (расположения можно изменить поменяв местами цифры в коде), с возможностью установить Title (displayName) и до 15 линий с разным текстом через config.yml, также добавь возможность анимации текста в этом ScoreBoard и специальную команду которая будет перезагружать конфигурацию без перезагрузки сервера. Сделай рабочий код, чтобы не было ошибок.
Вот готовый код плагина для PocketMine-MP API 5.37.3, который создаёт ScoreBoard с указанными функциями:
<?php
namespace RedScoreboard;
use pocketmine\plugin\PluginBase;
use pocketmine\player\Player;
use pocketmine\utils\Config;
use pocketmine\command\Command;
use pocketmine\command\CommandSender;
use pocketmine\network\mcpe\protocol\RemoveObjectivePacket;
use pocketmine\network\mcpe\protocol\SetDisplayObjectivePacket;
use pocketmine\network\mcpe\protocol\SetScorePacket;
use pocketmine\network\mcpe\protocol\types\ScorePacketEntry;
class Main extends PluginBase {
private Config $config;
private array $animations = [];
private array $animationTasks = [];
public function onEnable(): void {
$this->saveDefaultConfig();
$this->config = new Config($this->getDataFolder() . "config.yml", Config::YAML);
$this->loadAnimations();
}
private function loadAnimations(): void {
$this->animations = $this->config->get("animations", []);
foreach ($this->animations as $animationName => $animationData) {
if (isset($animationData["lines"]) && is_array($animationData["lines"])) {
foreach ($animationData["lines"] as $lineIndex => $frames) {
if (!is_array($frames)) {
unset($this->animations[$animationName]["lines"][$lineIndex]);
}
}
}
}
}
public function onCommand(CommandSender $sender, Command $command, string $label, array $args): bool {
if ($command->getName() === "scoreboardreload") {
if (!$sender->hasPermission("redscoreboard.reload")) {
$sender->sendMessage("§cУ вас нет разрешения на использование этой команды!");
return true;
}
$this->reloadConfig();
$this->config = new Config($this->getDataFolder() . "config.yml", Config::YAML);
$this->loadAnimations();
foreach ($this->getServer()->getOnlinePlayers() as $player) {
$this->removeScoreboard($player);
$this->createScoreboard($player);
}
$sender->sendMessage("§aКонфигурация ScoreBoard успешно перезагружена!");
return true;
}
return false;
}
public function onJoin(\pocketmine\event\player\PlayerJoinEvent $event): void {
$player = $event->getPlayer();
$this->createScoreboard($player);
}
private function removeScoreboard(Player $player): void {
$pk = new RemoveObjectivePacket();
$pk->objectiveName = "redscoreboard";
$player->getNetworkSession()->sendDataPacket($pk);
if (isset($this->animationTasks[$player->getName()])) {
$this->getScheduler()->cancelTask($this->animationTasks[$player->getName()]);
unset($this->animationTasks[$player->getName()]);
}
}
private function createScoreboard(Player $player): void {
$title = $this->config->get("title", "§l§cScoreBoard");
$lines = $this->config->get("lines", []);
$animationEnabled = $this->config->get("animation-enabled", false);
$animationSpeed = $this->config->get("animation-speed", 20);
// Create scoreboard
$pk = new SetDisplayObjectivePacket();
$pk->displaySlot = "sidebar";
$pk->objectiveName = "redscoreboard";
$pk->displayName = $title;
$pk->criteriaName = "dummy";
$pk->sortOrder = 1; // 0 = ascending, 1 = descending
$player->getNetworkSession()->sendDataPacket($pk);
// Set scores (from 0 to 14)
$entries = [];
$score = 0;
foreach ($lines as $index => $line) {
if ($score > 14) break;
$entry = new ScorePacketEntry();
$entry->objectiveName = "redscoreboard";
$entry->type = ScorePacketEntry::TYPE_FAKE_PLAYER;
$entry->customName = $line;
$entry->score = $score;
$entry->scoreboardId = $score;
$entries[] = $entry;
$score++;
}
$pk = new SetScorePacket();
$pk->type = SetScorePacket::TYPE_CHANGE;
$pk->entries = $entries;
$player->getNetworkSession()->sendDataPacket($pk);
// Start animation if enabled
if ($animationEnabled && !empty($this->animations)) {
$this->startAnimation($player, $animationSpeed);
}
}
private function startAnimation(Player $player, int $speed): void {
if (isset($this->animationTasks[$player->getName()])) {
$this->getScheduler()->cancelTask($this->animationTasks[$player->getName()]);
}
$task = new class($this, $player) extends \pocketmine\scheduler\Task {
private Main $plugin;
private Player $player;
private int $frame = 0;
private array $currentAnimation = [];
private int $currentLine = 0;
public function __construct(Main $plugin, Player $player) {
$this->plugin = $plugin;
$this->player = $player;
$this->currentAnimation = $this->plugin->getRandomAnimation();
}
public function onRun(): void {
if (!$this->player->isOnline()) {
$this->plugin->getScheduler()->cancelTask($this->getTaskId());
return;
}
$lines = $this->plugin->config->get("lines", []);
$animationLines = $this->currentAnimation["lines"] ?? [];
foreach ($animationLines as $lineIndex => $frames) {
if (!isset($lines[$lineIndex])) continue;
$frameCount = count($frames);
if ($frameCount === 0) continue;
$currentFrame = $frames[$this->frame % $frameCount];
$entry = new ScorePacketEntry();
$entry->objectiveName = "redscoreboard";
$entry->type = ScorePacketEntry::TYPE_FAKE_PLAYER;
$entry->customName = $currentFrame;
$entry->score = $lineIndex;
$entry->scoreboardId = $lineIndex;
$pk = new SetScorePacket();
$pk->type = SetScorePacket::TYPE_CHANGE;
$pk->entries = [$entry];
$this->player->getNetworkSession()->sendDataPacket($pk);
}
$this->frame++;
// Change animation occasionally
if ($this->frame % 30 === 0) {
$this->currentAnimation = $this->plugin->getRandomAnimation();
}
}
};
$taskId = $this->getScheduler()->scheduleRepeatingTask($task, $speed)->getTaskId();
$this->animationTasks[$player->getName()] = $taskId;
}
private function getRandomAnimation(): array {
$animations = array_values($this->animations);
return $animations[array_rand($animations)] ?? [];
}
}
Пример config.yml для этого плагина:
# Настройки ScoreBoard
title: "§l§cMy ScoreBoard"
animation-enabled: true
animation-speed: 20 # Скорость анимации в тиках (20 тиков = 1 секунда)
# Линии ScoreBoard (до 15 линий)
lines:
- "§7Сервер: §f{server_name}"
- "§7Онлайн: §f{online}/{max_players}"
- "§7Ваш пинг: §f{ping}ms"
- "§7Время: §f{time}"
- "§7Блоков: §f{blocks}"
- "§7Деньги: §f{money}"
- "§7Ранг: §f{rank}"
- "§7Место: §f{x} {y} {z}"
- "§aПример текста"
- "§bЕще одна строка"
- "§cКрасный текст"
- "§eЖелтый текст"
- "§6Оранжевый текст"
- "§dРозовый текст"
- "§5Фиолетовый текст"
# Анимации для строк
animations:
blink:
lines:
0: ["§7Сервер: §f{server_name}", "§7§lСервер: §f§l{server_name}"]
1: ["§7Онлайн: §f{online}/{max_players}", "§7§lОнлайн: §f§l{online}/{max_players}"]
color_change:
lines:
8: ["§aПример текста", "§bПример текста", "§cПример текста", "§eПример текста"]
9: ["§bЕще одна строка", "§eЕще одна строка", "§6Еще одна строка"]
Особенности плагина:
/scoreboardreload для перезагрузки конфига без перезагрузки сервераДля работы плагина:
RedScoreboard/src/RedScoreboard/Main.phpplugin.yml с соответствующим описаниемКоманда для перезагрузки требует права redscoreboard.reload, которые нужно указать в plugin.yml.