Почему не отображается летающий текст

Написал плагин на хранилища испытаний. Проблема в том, что левитирующий текст над ними не отображается. Если что я только начал изучать php и pocketmine! Это один из моих первых плагинов. Не засирайте плз. Вот код:

<?php

namespace TrialKey;

use pocketmine\block\Block;
use pocketmine\event\Listener;
use pocketmine\event\player\PlayerInteractEvent;
use pocketmine\item\StringToItemParser;
use pocketmine\item\VanillaItems;
use pocketmine\world\Position;
use pocketmine\scheduler\Task;
use pocketmine\player\Player;
use pocketmine\plugin\PluginBase;
use pocketmine\utils\Config;
use pocketmine\world\particle\FloatingTextParticle;
use pocketmine\math\Vector3;
use pocketmine\utils\TextFormat;

class Main extends PluginBase implements Listener {

    private Config $storageConfig;
    private array $storagePositions = [];
    private array $cooldowns = [];
    private array $textParticles = [];
    private ?int $updateTaskId = null;

    protected function onEnable(): void {
        $this->getServer()->getPluginManager()->registerEvents($this, $this);
        
        // Создаем/загружаем конфиг с позициями хранилищ
        $this->storageConfig = new Config($this->getDataFolder() . "storages.yml", Config::YAML);
        $this->storagePositions = $this->storageConfig->getAll();
        foreach ($this->storagePositions as $posStr => $particle) {
            $this->createFloatingText($posStr);
        }
        $this->getScheduler()->scheduleRepeatingTask(new class($this) extends Task {
            private Main $plugin;
            public function __construct(Main $plugin) {
                $this->plugin = $plugin;
            }
            public function onRun(): void {
                $this->plugin->updateAllFloatingTexts();
            }
        }, 20); // 20 тиков = 1 секунда
    }
    public function updateAllFloatingTexts(): void {
        foreach ($this->textParticles as $posStr => $particle) {
            $this->updateFloatingText($posStr);
        }
    }
    private function getCooldownText(string $posStr): string {
        if (isset($this->cooldowns[$posStr])) {
            $remaining = $this->cooldowns[$posStr] - time();
            if ($remaining > 0) {
                return TextFormat::YELLOW . "Доступно через: " . $remaining . " сек";
            }
        }
        return TextFormat::GREEN . "Доступно сейчас";
    }
    protected function onDisable(): void {
        // Сохраняем позиции хранилищ при выключении
        $this->storageConfig->setAll($this->storagePositions);
        $this->storageConfig->save();
    }
    private function createFloatingText(string $posStr): void {
        $pos = $this->stringToBlockPos($posStr);
        $this->getServer()->getWorldManager()->loadWorld("test");
        $world = $this->getServer()->getWorldManager()->getWorldByName("test");
        
        $vector = new Position($pos['x'], $pos['y'] + 1.5, $pos['z'], $world);
        $text = TextFormat::BOLD . TextFormat::GOLD . "ХРАНИЛИЩЕ ИСПЫТАНИЙ\n" . TextFormat::RESET;
        $text .= $this->getCooldownText($posStr);
        
        $this->textParticles[$posStr] = new FloatingTextParticle($text, "");
        $world->addParticle($vector, $this->textParticles[$posStr]);
        
    }
    
    private function updateFloatingText(string $posStr): void {
        $text = TextFormat::BOLD . TextFormat::GOLD . "ХРАНИЛИЩЕ ИСПЫТАНИЙ\n" . TextFormat::RESET;
        if (isset($this->cooldowns[$posStr])) {
            $remaining = $this->cooldowns[$posStr] - time();
            if ($remaining > 0) {
                $text .= TextFormat::YELLOW . "Доступно через: " . $remaining . " сек";
                $this->textParticles[$posStr]->setText($text);
                $this->textParticles[$posStr]->setInvisible(false);
                return;
            }
            // Удаляем кулдаун если время истекло
            unset($this->cooldowns[$posStr]);
        }

        $text .= TextFormat::GREEN . "Доступно сейчас";
        $this->textParticles[$posStr]->setText($text);
        $this->textParticles[$posStr]->setInvisible(false);
    }

    public function onInteract(PlayerInteractEvent $event): void {
        $player = $event->getPlayer();
        $block = $event->getBlock();
        $item = $event->getItem();
        $blockPos = $this->blockToString($block);
        
        //if ($player->hasPermission("trialkey.admin")) {
            //$player->sendMessage("Вторая стадия!");
            // Если оператор - устанавливаем/удаляем хранилище
            //if (isset($this->storagePositions[$blockPos])) {
                //unset($this->storagePositions[$blockPos]);
                //$player->sendMessage("§aХранилище удалено с этой позиции");
            //} else {
                //$player->sendMessage("Третья стадия!");
                //$this->storagePositions[$blockPos] = true;
                //$player->sendMessage("§aХранилище установлено на этой позиции");
            //}
            //$event->cancel();
            //return;
        //}
        
        // Проверяем, что игрок нажал ПКМ по хранилищу
        if (isset($this->storagePositions[$blockPos])) {
            // Проверяем наличие ключа
            if (isset($this->cooldowns[$blockPos]) && ($remaining = $this->cooldowns[$blockPos] - time()) > 0) {
                $player->sendMessage("§cЭто хранилище можно открыть через §e" . $remaining . "§c секунд");
                $event->cancel();
                return;
            }
            $trialKey = StringToItemParser::getInstance()->parse("trial_key");
            $inventory = $player->getInventory();
            $item = $event->getItem();
            if ($item->equals($trialKey, false, false)) {
                $inventory->removeItem($item->setCount(1));
                $this->openStorage($player);
                $this->cooldowns[$blockPos] = time() + 60;
                $this->updateFloatingText($blockPos);
                $event->cancel();
            } else {
                $player->sendMessage("§cДля открытия хранилища вам нужно держать ключ испытаний в руке!");
            }
        }
    }
    
    private function openStorage(Player $player): void {
        $reward = match(mt_rand(1, 3)) {
            1 => VanillaItems::DIAMOND()->setCount(3),
            2 => VanillaItems::NETHERITE_HELMET(),
            3 => VanillaItems::TOTEM(),
            default => VanillaItems::DIAMOND()->setCount(1)
        };
        
        $player->getInventory()->addItem($reward);
        $player->sendMessage("§aВы получили награду: " . $reward->getName());
    }
    private function stringToBlockPos(string $posStr): array {
        $parts = explode(":", $posStr);
        return [
            'x' => (int)$parts[0],
            'y' => (int)$parts[1],
            'z' => (int)$parts[2],
            'world' => $parts[3]
        ];
    }
    private function blockToString(Block $block): string {
        return $block->getPosition()->getFloorX() . ":" . 
               $block->getPosition()->getFloorY() . ":" . 
               $block->getPosition()->getFloorZ() . ":" . 
               $block->getPosition()->getWorld()->getFolderName();
    }
}

спроси у ии, он тебе поможет :smiling_face_with_three_hearts:

Логи ошибок?

author by ChatGPT
че ты пишешь?

ну он крутой

АХАХАХХАХА. Я щас проорал. Ты серьезно? Да, я за основу взял плагин cubecases и документалку пм. Но какой нахер chatgpt? Единственный раз, когда я заюзал ии это чтобы самим решить проблему, перед тем как сюда строчить.

Значит автор этого плагина писал его при помощи ChatGPT, это очевидно по коду

Братан, ты тоже очень крутой. Наверное я бы не стал писать на форум, если бы не спросил у ии? Он пишет, что нужно добавить какую-то доп проверку. Ладно пох. Вообщем и целом я решил проблему. Там надо было отправлять игроку частицы на каждом апдейте

Эта тема была автоматически закрыта через 12 часов после последнего ответа. В ней больше нельзя отвечать.