From 9034258d0b5f5926163f4ed65af1ec49d49677a5 Mon Sep 17 00:00:00 2001 From: FoxWorn3365 Date: Sun, 25 Jun 2023 23:44:19 +0200 Subject: [PATCH 1/4] Fixed some bugs and added some features # THIS IS NOT A RELASE, IS A DEV VERSION AND IT'S FULL OF BUGS! ## Added - Now from the shop info you can summon the shop - Now in the shop info if the shop is an adminshop the chest will became a barrier - New entity save system - Added support for custom items ## Bug fix - Now at the start an autorepair will be initialized and will repair any error - Fixed bug for Customitems - Fixed some bugs - Fixed the item remove button ## TODO - /sk rename - Entity spawn stability (duplication) - idk --- plugin.yml | 2 +- src/FoxWorn3365/Shopkeepers/Core.php | 54 ++-- src/FoxWorn3365/Shopkeepers/EntityManager.php | 4 +- .../Shopkeepers/Menu/EditItemMenu.php | 10 +- src/FoxWorn3365/Shopkeepers/Menu/ListMenu.php | 7 +- .../Shopkeepers/Menu/ShopConfigMenu.php | 8 + .../Shopkeepers/Menu/ShopInfoMenu.php | 34 ++- .../Shopkeepers/entity/Shopkeeper.php | 21 +- src/FoxWorn3365/Shopkeepers/shop/Manager.php | 3 +- src/FoxWorn3365/Shopkeepers/utils/Factory.php | 21 ++ .../Shopkeepers/utils/ItemUtils.php | 10 + src/FoxWorn3365/Shopkeepers/utils/Utils.php | 75 +++++- src/muqsit/invmenu/InvMenu.php | 182 ++++++++++++++ src/muqsit/invmenu/InvMenuEventHandler.php | 97 ++++++++ src/muqsit/invmenu/InvMenuHandler.php | 46 ++++ .../invmenu/inventory/InvMenuInventory.php | 23 ++ .../inventory/SharedInvMenuSynchronizer.php | 32 +++ .../inventory/SharedInventoryNotifier.php | 31 +++ .../inventory/SharedInventorySynchronizer.php | 28 +++ src/muqsit/invmenu/session/InvMenuInfo.php | 17 ++ src/muqsit/invmenu/session/PlayerManager.php | 64 +++++ src/muqsit/invmenu/session/PlayerSession.php | 102 ++++++++ .../network/NetworkStackLatencyEntry.php | 21 ++ .../invmenu/session/network/PlayerNetwork.php | 230 ++++++++++++++++++ .../handler/ClosurePlayerNetworkHandler.php | 22 ++ .../network/handler/PlayerNetworkHandler.php | 13 + .../handler/PlayerNetworkHandlerRegistry.php | 39 +++ .../DeterministicInvMenuTransaction.php | 60 +++++ .../transaction/InvMenuTransaction.php | 43 ++++ .../transaction/InvMenuTransactionResult.php | 48 ++++ .../transaction/SimpleInvMenuTransaction.php | 57 +++++ .../invmenu/type/ActorFixedInvMenuType.php | 44 ++++ .../type/BlockActorFixedInvMenuType.php | 54 ++++ .../invmenu/type/BlockFixedInvMenuType.php | 41 ++++ ...ublePairableBlockActorFixedInvMenuType.php | 70 ++++++ src/muqsit/invmenu/type/FixedInvMenuType.php | 18 ++ src/muqsit/invmenu/type/InvMenuType.php | 17 ++ src/muqsit/invmenu/type/InvMenuTypeIds.php | 12 + .../invmenu/type/InvMenuTypeRegistry.php | 72 ++++++ .../type/graphic/ActorInvMenuGraphic.php | 71 ++++++ .../type/graphic/BlockActorInvMenuGraphic.php | 70 ++++++ .../type/graphic/BlockInvMenuGraphic.php | 59 +++++ .../invmenu/type/graphic/InvMenuGraphic.php | 28 +++ .../type/graphic/MultiBlockInvMenuGraphic.php | 65 +++++ .../type/graphic/PositionedInvMenuGraphic.php | 12 + .../ActorInvMenuGraphicNetworkTranslator.php | 22 ++ .../BlockInvMenuGraphicNetworkTranslator.php | 33 +++ .../InvMenuGraphicNetworkTranslator.php | 14 ++ .../MultiInvMenuGraphicNetworkTranslator.php | 25 ++ ...dowTypeInvMenuGraphicNetworkTranslator.php | 20 ++ .../invmenu/type/util/InvMenuTypeBuilders.php | 29 +++ .../invmenu/type/util/InvMenuTypeHelper.php | 52 ++++ .../builder/ActorFixedInvMenuTypeBuilder.php | 38 +++ .../builder/ActorInvMenuTypeBuilderTrait.php | 45 ++++ ...imationDurationInvMenuTypeBuilderTrait.php | 19 ++ .../BlockActorFixedInvMenuTypeBuilder.php | 35 +++ .../builder/BlockFixedInvMenuTypeBuilder.php | 22 ++ .../builder/BlockInvMenuTypeBuilderTrait.php | 22 ++ ...rableBlockActorFixedInvMenuTypeBuilder.php | 35 +++ .../builder/FixedInvMenuTypeBuilderTrait.php | 21 ++ ...orkTranslatableInvMenuTypeBuilderTrait.php | 37 +++ .../type/util/builder/InvMenuTypeBuilder.php | 12 + 62 files changed, 2479 insertions(+), 39 deletions(-) create mode 100644 src/muqsit/invmenu/InvMenu.php create mode 100644 src/muqsit/invmenu/InvMenuEventHandler.php create mode 100644 src/muqsit/invmenu/InvMenuHandler.php create mode 100644 src/muqsit/invmenu/inventory/InvMenuInventory.php create mode 100644 src/muqsit/invmenu/inventory/SharedInvMenuSynchronizer.php create mode 100644 src/muqsit/invmenu/inventory/SharedInventoryNotifier.php create mode 100644 src/muqsit/invmenu/inventory/SharedInventorySynchronizer.php create mode 100644 src/muqsit/invmenu/session/InvMenuInfo.php create mode 100644 src/muqsit/invmenu/session/PlayerManager.php create mode 100644 src/muqsit/invmenu/session/PlayerSession.php create mode 100644 src/muqsit/invmenu/session/network/NetworkStackLatencyEntry.php create mode 100644 src/muqsit/invmenu/session/network/PlayerNetwork.php create mode 100644 src/muqsit/invmenu/session/network/handler/ClosurePlayerNetworkHandler.php create mode 100644 src/muqsit/invmenu/session/network/handler/PlayerNetworkHandler.php create mode 100644 src/muqsit/invmenu/session/network/handler/PlayerNetworkHandlerRegistry.php create mode 100644 src/muqsit/invmenu/transaction/DeterministicInvMenuTransaction.php create mode 100644 src/muqsit/invmenu/transaction/InvMenuTransaction.php create mode 100644 src/muqsit/invmenu/transaction/InvMenuTransactionResult.php create mode 100644 src/muqsit/invmenu/transaction/SimpleInvMenuTransaction.php create mode 100644 src/muqsit/invmenu/type/ActorFixedInvMenuType.php create mode 100644 src/muqsit/invmenu/type/BlockActorFixedInvMenuType.php create mode 100644 src/muqsit/invmenu/type/BlockFixedInvMenuType.php create mode 100644 src/muqsit/invmenu/type/DoublePairableBlockActorFixedInvMenuType.php create mode 100644 src/muqsit/invmenu/type/FixedInvMenuType.php create mode 100644 src/muqsit/invmenu/type/InvMenuType.php create mode 100644 src/muqsit/invmenu/type/InvMenuTypeIds.php create mode 100644 src/muqsit/invmenu/type/InvMenuTypeRegistry.php create mode 100644 src/muqsit/invmenu/type/graphic/ActorInvMenuGraphic.php create mode 100644 src/muqsit/invmenu/type/graphic/BlockActorInvMenuGraphic.php create mode 100644 src/muqsit/invmenu/type/graphic/BlockInvMenuGraphic.php create mode 100644 src/muqsit/invmenu/type/graphic/InvMenuGraphic.php create mode 100644 src/muqsit/invmenu/type/graphic/MultiBlockInvMenuGraphic.php create mode 100644 src/muqsit/invmenu/type/graphic/PositionedInvMenuGraphic.php create mode 100644 src/muqsit/invmenu/type/graphic/network/ActorInvMenuGraphicNetworkTranslator.php create mode 100644 src/muqsit/invmenu/type/graphic/network/BlockInvMenuGraphicNetworkTranslator.php create mode 100644 src/muqsit/invmenu/type/graphic/network/InvMenuGraphicNetworkTranslator.php create mode 100644 src/muqsit/invmenu/type/graphic/network/MultiInvMenuGraphicNetworkTranslator.php create mode 100644 src/muqsit/invmenu/type/graphic/network/WindowTypeInvMenuGraphicNetworkTranslator.php create mode 100644 src/muqsit/invmenu/type/util/InvMenuTypeBuilders.php create mode 100644 src/muqsit/invmenu/type/util/InvMenuTypeHelper.php create mode 100644 src/muqsit/invmenu/type/util/builder/ActorFixedInvMenuTypeBuilder.php create mode 100644 src/muqsit/invmenu/type/util/builder/ActorInvMenuTypeBuilderTrait.php create mode 100644 src/muqsit/invmenu/type/util/builder/AnimationDurationInvMenuTypeBuilderTrait.php create mode 100644 src/muqsit/invmenu/type/util/builder/BlockActorFixedInvMenuTypeBuilder.php create mode 100644 src/muqsit/invmenu/type/util/builder/BlockFixedInvMenuTypeBuilder.php create mode 100644 src/muqsit/invmenu/type/util/builder/BlockInvMenuTypeBuilderTrait.php create mode 100644 src/muqsit/invmenu/type/util/builder/DoublePairableBlockActorFixedInvMenuTypeBuilder.php create mode 100644 src/muqsit/invmenu/type/util/builder/FixedInvMenuTypeBuilderTrait.php create mode 100644 src/muqsit/invmenu/type/util/builder/GraphicNetworkTranslatableInvMenuTypeBuilderTrait.php create mode 100644 src/muqsit/invmenu/type/util/builder/InvMenuTypeBuilder.php diff --git a/plugin.yml b/plugin.yml index 5047dad..c37bcaa 100644 --- a/plugin.yml +++ b/plugin.yml @@ -1,5 +1,5 @@ name: Shopkeepers -version: 0.8.2 +version: 0.9.0 api: 5.0.0 main: FoxWorn3365\Shopkeepers\Core diff --git a/src/FoxWorn3365/Shopkeepers/Core.php b/src/FoxWorn3365/Shopkeepers/Core.php index b0e276f..1b89022 100644 --- a/src/FoxWorn3365/Shopkeepers/Core.php +++ b/src/FoxWorn3365/Shopkeepers/Core.php @@ -43,6 +43,7 @@ use pocketmine\event\entity\EntityDamageByEntityEvent; use pocketmine\event\player\PlayerJoinEvent; use pocketmine\event\server\DataPacketReceiveEvent; +use pocketmine\event\entity\EntitySpawnEvent; // Packets use pocketmine\network\mcpe\protocol\ActorEventPacket as EntityEventPacket; @@ -77,8 +78,8 @@ class Core extends PluginBase implements Listener { protected float $server = 5.0; protected const NOT_PERM_MSG = "§cSorry but you don't have permissions to use this command!\nPlease contact your server administrator"; - protected const AUTHOR = "FoxWorn3365"; - protected const VERSION = "0.8.2-pre-relase"; + public const AUTHOR = "FoxWorn3365"; + public const VERSION = "0.9-pre"; public function onLoad() : void { $this->menu = new \stdClass; @@ -122,19 +123,11 @@ public function onPlayerEntityInteract(Interaction $event) : void { if ($entity instanceof Shopkeeper) { $data = $entity->getConfig(); if ($data->author === $event->getPlayer()->getName() && !$event->getPlayer()->isSneaking()) { - // Open the shopkeeper's inventory RN! + // Open the shopkeeper's ~~inventory~~ info page RN! $cm = new ConfigManager($data->author, $this->getDataFolder()); $cm->setSingleKey($data->shop); - if ($cm->get()->{$data->shop}->admin) { - // Admin shops don't have inventory so open the normal trade menu and runnnn - $manager = new Manager($cm); - $this->trades->{$event->getPlayer()->getName()} = new \stdClass; - $this->trades->{$event->getPlayer()->getName()}->config = $data; - $manager->send($event->getPlayer(), $entity); - } else { - $menu = new ShopInventoryMenu($cm); - $menu->create()->send($event->getPlayer()); - } + $menu = new ShopInfoMenu($cm); + $menu->create()->send($event->getPlayer()); } else { // It's a shopkeeper! // BEAUTIFUL! @@ -149,7 +142,18 @@ public function onPlayerEntityInteract(Interaction $event) : void { } } - public function onCommand(CommandSender $sender, Command $command, $label, array $args) : bool{ + public function onEntitySpawn(EntitySpawnEvent $event) : void { + if ($event->getEntity() instanceof Shopkeeper) { + // Add the shopkeeper to entity interface + if (!$event->getEntity()->hasCustomShopkeeperEntityId()) { + $entity = $event->getEntity(); + $entity->setCustomShopkeeperEntityId(Utils::randomizer(10)); + $this->entities->add($event->getEntity()); + } + } + } + + public function onCommand(CommandSender $sender, Command $command, $label, array $args) : bool { if (!($sender instanceof Player)) { $sender->sendMessage("This command can be only executed by in-game players!"); return false; @@ -256,7 +260,7 @@ public function onCommand(CommandSender $sender, Command $command, $label, array $villager->setNameTagAlwaysVisible($shop->get()->{$name}->namevisible); $villager->setConfig($shopdata); $villager->spawnToAll(); - $this->entities->add($villager); + // Will be managed by EntitySpawnEvent $this->entities->add($villager); return true; } elseif ($args[0] === "remove" || $args[0] === "despawn") { $sender->sendMessage("To remove a shopkeeper just hit it!"); @@ -315,13 +319,20 @@ public function onPacket(DataPacketReceiveEvent $event) : void { $event->getOrigin()->getPlayer()->sendMessage("§cYour inventory is full!"); return; } else { + print_r($result); + if ($result->getId() === 25266) { + // Is a custom item + $item = NbtManager::decode(Utils::comparator($this->trades->{$event->getOrigin()->getPlayer()->getName()}->item, $result->getCount(), $cm->get()->{$cm->getSingleKey()}->items)); + } else { + $translator = new TypeConverter(); + $item = $translator->netItemStackToCore($result); + } + /* if ($this->server < 5) { $translator = new TypeConverter(); $item = $translator->netItemStackToCore($result); - } else { - $translator = (new TypeConverter())->getItemTranslator(); - $item = $translator->fromNetworkId($result->getId(), $result->getMeta(), $result->getBlockRuntimeId()); } + */ $item->setCount($result->getCount()); // Before set this we need to check and update the villager's inventory $total = $result->getCount(); @@ -354,14 +365,17 @@ public function onPacket(DataPacketReceiveEvent $event) : void { if ($total > 0) { return; } + + if (gettype($inventoryInsideConfig) !== 'array') { + Utils::errorLogger($this->getDataFolder(), "ERROR", "InventoryInsideConfig at Core.php#364 was an object and not an array!\nPlase report this with an issue!"); + $inventoryInsideConfig = []; + } $object = $cm->get()->{$cm->getSingleKey()}; $object->inventory = $inventoryInsideConfig; $cm->set($cm->getSingleKey(), $object); } $this->trades->{$event->getOrigin()->getPlayer()->getName()}->items[] = $item; - // Remove this item from the entity's inventory - //$itemglobal = $item; } } } diff --git a/src/FoxWorn3365/Shopkeepers/EntityManager.php b/src/FoxWorn3365/Shopkeepers/EntityManager.php index d7d2ae5..a929433 100644 --- a/src/FoxWorn3365/Shopkeepers/EntityManager.php +++ b/src/FoxWorn3365/Shopkeepers/EntityManager.php @@ -80,6 +80,7 @@ public function generateEntityHash(Shopkeeper $shop) : string { 'pitch' => $shop->getLocation()->getPitch(), 'world' => $shop->getWorld()->getId(), 'config' => base64_encode(json_encode($shop->getConfig())), + 'id' => $shop->getCustomShopkeeperEntityId(), 'nametag' => base64_encode(json_encode([ 'visible' => $shop->isNameTagAlwaysVisible(), 'tag' => $shop->getNameTag() @@ -112,8 +113,7 @@ public function loadPlayer(Player $player) : void { protected static function createEntity(string $rawdata, Server $server) : Shopkeeper { $data = (object)json_decode(base64_decode($rawdata)); $location = new Location($data->x, $data->y, $data->z, $server->getWorldManager()->getWorld($data->world), $data->yaw, $data->pitch); - $entity = new Shopkeeper($location); - $entity->setConfig(json_decode(base64_decode($data->config))); + $entity = new Shopkeeper($location, json_decode(base64_decode($data->config)), $data->id); $tags = json_decode(base64_decode($data->nametag)); $entity->setNameTag($tags->tag); $entity->setNameTagAlwaysVisible($tags->visible); diff --git a/src/FoxWorn3365/Shopkeepers/Menu/EditItemMenu.php b/src/FoxWorn3365/Shopkeepers/Menu/EditItemMenu.php index f8e64fb..c701dce 100644 --- a/src/FoxWorn3365/Shopkeepers/Menu/EditItemMenu.php +++ b/src/FoxWorn3365/Shopkeepers/Menu/EditItemMenu.php @@ -135,13 +135,15 @@ function edit() : InvMenu { // Now let's analyze the slot switch ($action->getSlot()) { - case 7: + case 17: // Oh crap, we need to delete this! $config->items[$index] = null; - unset($config->items[$index]); - $cm->set($cm->getSingleKey(), json_encode($config)); + $cm->set($cm->getSingleKey(), $config); + return $transaction->discard(); + /* $retmenu = new EditMenu($cm, $cm->getSingleKey()); $retmenu->create()->send($transaction->getPlayer()); + */ break; case 1: $item = $inventory->getItem(10); @@ -163,7 +165,7 @@ function edit() : InvMenu { $object->buy = SerializedItem::encode($item); } break; - case 4: + case 4: $item = $inventory->getItem(13); if ($item->getCount()+1 > 64) { $transaction->getPlayer()->sendMessage("§cYou can't sell more than 64 items!"); diff --git a/src/FoxWorn3365/Shopkeepers/Menu/ListMenu.php b/src/FoxWorn3365/Shopkeepers/Menu/ListMenu.php index 431d9fd..d1fc5ec 100644 --- a/src/FoxWorn3365/Shopkeepers/Menu/ListMenu.php +++ b/src/FoxWorn3365/Shopkeepers/Menu/ListMenu.php @@ -65,7 +65,12 @@ public function create() : InvMenu { break; } $nameassociations[$slotindex] = $name; - $inventory->setItem($slotindex, Factory::item(388, 0, "{$name}\nStatus: §2Active")); + if ($config->admin) { + $shop = "§2true"; + } else { + $shop = "§4false"; + } + $inventory->setItem($slotindex, Factory::egg("§l{$name}\n\n§lTrades: §r" . count($config->items) . "/9\n§lAdmin shop:§r {$shop}")); $slotindex++; } diff --git a/src/FoxWorn3365/Shopkeepers/Menu/ShopConfigMenu.php b/src/FoxWorn3365/Shopkeepers/Menu/ShopConfigMenu.php index baf0428..0302f85 100644 --- a/src/FoxWorn3365/Shopkeepers/Menu/ShopConfigMenu.php +++ b/src/FoxWorn3365/Shopkeepers/Menu/ShopConfigMenu.php @@ -54,6 +54,9 @@ public function create() : InvMenu { Draw::line(0, 8, $inventory, Factory::item(160, 8, "")); Draw::line(18, 26, $inventory, Factory::item(160, 8, "")); + $inventory->clear(4); + $inventory->setItem(4, Factory::egg($this->cm->getSingleKey() . "\n§oClick to return back!")); + // Pass first option if ($this->config->namevisible) { $inventory->setItem(10, Factory::item(35, 5, "Shop's name Visible\nStatus: §2§lActive\n§r§oClick to disable!")); @@ -117,6 +120,11 @@ public function create() : InvMenu { $config->admin = true; } break; + case 4: + // Return back to the ShopInfoMenu menu + $menu = new ShopInfoMenu($cm); + $menu->create()->send($transaction->getPlayer()); + break; } $cm->set($cm->getSingleKey(), $config); diff --git a/src/FoxWorn3365/Shopkeepers/Menu/ShopInfoMenu.php b/src/FoxWorn3365/Shopkeepers/Menu/ShopInfoMenu.php index d9ca220..6f53c3c 100644 --- a/src/FoxWorn3365/Shopkeepers/Menu/ShopInfoMenu.php +++ b/src/FoxWorn3365/Shopkeepers/Menu/ShopInfoMenu.php @@ -30,6 +30,8 @@ use FoxWorn3365\Shopkeepers\utils\Factory; use FoxWorn3365\Shopkeepers\ConfigManager; +use FoxWorn3365\Shopkeepers\entity\Shopkeeper; + class ShopInfoMenu { protected InvMenu $menu; protected ConfigManager $cm; @@ -44,7 +46,7 @@ function __construct(ConfigManager $cm) { } public function create() : InvMenu { - $this->menu->setName("'{$this->cm->getSingleKey()}' shop - Info"); + $this->menu->setName("View shop {$this->cm->getSingleKey()}"); $inventory = $this->menu->getInventory(); // Draw the useful line @@ -52,7 +54,7 @@ public function create() : InvMenu { // Now set the villager egg with name in the middle (slot 4) $inventory->clear(4); - $inventory->setItem(4, Factory::item(388, 0, $this->cm->getSingleKey())); + $inventory->setItem(4, Factory::egg($this->cm->getSingleKey())); // Now set the informations $inventory->setItem(10, Factory::item(377, 0, 'Shop config')); @@ -60,16 +62,25 @@ public function create() : InvMenu { // Villager inventory if (!$this->config->admin) { $inventory->setItem(13, Factory::item(54, 0, "Shop inventory")); + } else { + $inventory->setItem(13, Factory::barrier("§cShop inventory\n§rDisabled!\n§oThis is an admin shop!")); // ID: -161 Meta: 0 BRID: 10390 } + // Summon option + $inventory->setItem(21, Factory::egg("Summon")); + + // Misteryous option + $inventory->setItem(23, Factory::barrier("§oUnknown\n\nv1.0")); + // Edit Shopkeepers trades $st = Utils::getItem("minecraft:smithing_table"); $st->setCustomName("§rEdit shop trades"); $inventory->setItem(16, $st); $cm = $this->cm; + $config = $this->config; - $this->menu->setListener(function($transaction) use ($cm) { + $this->menu->setListener(function($transaction) use ($cm, $config) { $slot = $transaction->getAction()->getSlot(); switch ($slot) { case 10: @@ -96,6 +107,23 @@ public function create() : InvMenu { $edit = new EditMenu($cm, $cm->getSingleKey()); $edit->create()->send($transaction->getPlayer()); break; + case 21: + if (!$transaction->getPlayer()->hasPermission("shopkeepers.shop.summon")) { + $transaction->getPlayer()->removeCurrentWindow(); + $transaction->getPlayer()->sendMessage(self::NOT_PERM_MSG); + break; + } + // Summon entity + $shopdata = new \stdClass; + $shopdata->author = $transaction->getPlayer()->getName(); + $shopdata->shop = $cm->getSingleKey(); + $villager = new Shopkeeper($transaction->getPlayer()->getLocation()); + $villager->setNameTag($cm->getSingleKey()); + $villager->setNameTagAlwaysVisible($config->namevisible); + $villager->setConfig($shopdata); + $villager->spawnToAll(); + $transaction->getPlayer()->removeCurrentWindow(); + break; } return $transaction->discard(); }); diff --git a/src/FoxWorn3365/Shopkeepers/entity/Shopkeeper.php b/src/FoxWorn3365/Shopkeepers/entity/Shopkeeper.php index 0e8b9b5..a9dc164 100644 --- a/src/FoxWorn3365/Shopkeepers/entity/Shopkeeper.php +++ b/src/FoxWorn3365/Shopkeepers/entity/Shopkeeper.php @@ -25,14 +25,16 @@ use pocketmine\entity\EntitySizeInfo; class Shopkeeper extends Villager { - public ?object $shopconfig; + public ?object $shopconfig = null; + public ?int $customShopkeeperEntityId = null; - public function __construct(Location $loc, ?object $generalizedConfig = null) { + public function __construct(Location $loc, ?object $generalizedConfig = null, ?int $customId = null) { parent::__construct($loc, null); $this->setCanSaveWithChunk(false); $this->shopconfig = $generalizedConfig; + $this->customShopkeeperEntityId = $customId; } public function getName(): string { @@ -54,4 +56,19 @@ public function setConfig(object $config) : void { public function getConfig() : object { return $this->shopconfig; } + + public function setCustomShopkeeperEntityId(int $id) : void { + $this->setCustomShopkeeperEntityId = $id; + } + + public function getCustomShopkeeperEntityId() : ?int { + return $this->customShopkeeperEntityId; + } + + public function hasCustomShopkeeperEntityId() : bool { + if ($this->customShopkeeperEntityId === null) { + return false; + } + return true; + } } \ No newline at end of file diff --git a/src/FoxWorn3365/Shopkeepers/shop/Manager.php b/src/FoxWorn3365/Shopkeepers/shop/Manager.php index fdf04dd..3e40470 100644 --- a/src/FoxWorn3365/Shopkeepers/shop/Manager.php +++ b/src/FoxWorn3365/Shopkeepers/shop/Manager.php @@ -49,7 +49,8 @@ public function send(Player $player, Shopkeeper $entity) : void { $this->player = $player; $this->entity = $entity; foreach ($this->config->items as $itemconfig) { - if (!(!empty($itemconfig->sell) && !empty($itemconfig->buy))) { + if ($itemconfig === null) { continue; } + if (!(!empty($itemconfig->sell) && !empty($itemconfig->buy)) && gettype($this->config->inventory) !== 'array') { continue; } $this->container->add($itemconfig->sell, $itemconfig->buy, $this->config->inventory, $this->config->admin); diff --git a/src/FoxWorn3365/Shopkeepers/utils/Factory.php b/src/FoxWorn3365/Shopkeepers/utils/Factory.php index 83865ad..74a076d 100644 --- a/src/FoxWorn3365/Shopkeepers/utils/Factory.php +++ b/src/FoxWorn3365/Shopkeepers/utils/Factory.php @@ -42,4 +42,25 @@ public static function item(int $id, int $meta, string $name, int $count = 1) : $item->setCount($count); return $item; } + + public static function rawItem(int $id, int $meta, string $name, int $count = 1) : ?Item { + $item = Utils::getIntItem($id, $meta); + $item->setCustomName($name); + $item->setCount($count); + return $item; + } + + public static function egg(string $name, int $count = 1) : ?Item { + $egg = ItemUtils::decode(451, 0, 0); + $egg->setCustomName("§r{$name}"); + $egg->setCount($count); + return $egg; + } + + public static function barrier(string $name, int $count = 1) : ?Item { + $barrier = ItemUtils::decode(-161, 0, 10390); + $barrier->setCustomName("§r{$name}"); + $barrier->setCount($count); + return $barrier; + } } \ No newline at end of file diff --git a/src/FoxWorn3365/Shopkeepers/utils/ItemUtils.php b/src/FoxWorn3365/Shopkeepers/utils/ItemUtils.php index 80712a3..966aac1 100644 --- a/src/FoxWorn3365/Shopkeepers/utils/ItemUtils.php +++ b/src/FoxWorn3365/Shopkeepers/utils/ItemUtils.php @@ -61,4 +61,14 @@ public static final function typeDecode(object $object) : ?Item { public static final function stringParser(string $string) : ?Item { return (new StringToItemParser())->parse($string); } + + public static function getId(Item $item) : int { + $translator = (new TypeConverter())->getItemTranslator(); + return $translator->toNetworkIdQuiet($item)[0]; + } + + public static function getMeta(Item $item) : int { + $translator = (new TypeConverter())->getItemTranslator(); + return $translator->toNetworkIdQuiet($item)[1]; + } } \ No newline at end of file diff --git a/src/FoxWorn3365/Shopkeepers/utils/Utils.php b/src/FoxWorn3365/Shopkeepers/utils/Utils.php index c265430..cf47cf3 100644 --- a/src/FoxWorn3365/Shopkeepers/utils/Utils.php +++ b/src/FoxWorn3365/Shopkeepers/utils/Utils.php @@ -26,8 +26,8 @@ use pocketmine\item\Item; use pocketmine\item\VanillaItems; -class Utils { - static function getItem(string $itemid) { +final class Utils { + public static function getItem(string $itemid) : mixed { try { return LegacyStringToItemParser::getInstance()->parse(trim($itemid)); } catch (LegacyStringToItemParserException) { @@ -35,7 +35,7 @@ static function getItem(string $itemid) { } } - static function getIntItem(int $id, int $meta = 0) { + public static function getIntItem(int $id, int $meta = 0) : mixed { $itemid = "{$id}:{$meta}"; try { return LegacyStringToItemParser::getInstance()->parse(trim($itemid)); @@ -44,7 +44,7 @@ static function getIntItem(int $id, int $meta = 0) { } } - static function errorLogger(string $data_dir, string $severity, string $reason) : void { + public static function errorLogger(string $data_dir, string $severity, string $reason) : void { if (file_exists("{$data_dir}error.txt")) { $stream = file_get_contents("{$data_dir}error.txt"); } else { @@ -54,7 +54,7 @@ static function errorLogger(string $data_dir, string $severity, string $reason) file_put_contents("{$data_dir}error.txt", $stream); } - static function integrityChecker(string $data_dir) : void { + public static function integrityChecker(string $data_dir) : void { foreach (glob("{$data_dir}*.json") as $file) { $content = file_get_contents($file); if (empty($content) || $content == " ") { @@ -65,8 +65,73 @@ static function integrityChecker(string $data_dir) : void { self::errorLogger($data_dir, "ERROR", "Invalid JSON in file {$file}!"); // Remove the dangerous file @unlink($file); + } else { + // Correct the file + self::shopTypeChecker($data_dir, json_decode($content), $file); } } // Perfect, ready to go! } + + public static function shopTypeChecker(string $data_dir, object $object, string $file) : void { + $end = clone $object; + foreach ($object as $name => $shop_a) { + $shop = clone $shop_a; + if (gettype($shop->admin) !== 'boolean') { + self::errorLogger($data_dir, "NOTICE", "Value of 'admin' inside shop '{$name}', file '{$file}' is not a boolean! Corrected"); + $shop->admin = false; + } + + if (gettype($shop->namevisible) !== 'boolean') { + self::errorLogger($data_dir, "NOTICE", "Value of 'namevisible' inside shop '{$name}', file '{$file}' is not a boolean! Corrected"); + $shop->namevisible = false; + } + + if (gettype($shop->items) !== 'array') { + // Oh shit is not array! + if (gettype($shop->items) === 'object') { + self::errorLogger($data_dir, "NOTICE", "Value of 'items' inside shop '{$name}', file '{$file}' is an object! Corrected"); + $it = []; + foreach ($shop->items as $item) { + $it[] = $item; + } + $shop->items = $it; + //var_dump($shop->items); + } else { + self::errorLogger($data_dir, "WARNING", "Value of 'items' inside shop '{$name}', file '{$file}' is not a correct value! Neutralized"); + $shop->items = []; + } + } + + if (gettype($shop->inventory) !== 'array') { + // Oh shit is not array! + if (gettype($shop->inventory) === 'object') { + self::errorLogger($data_dir, "NOTICE", "Value of 'inventory' inside shop '{$name}', file '{$file}' is an object! Corrected"); + $shop->inventory = (array)$shop->inventory; + } else { + self::errorLogger($data_dir, "WARNING", "Value of 'inventory' inside shop '{$name}', file '{$file}' is not a correct value! Neutralized"); + $shop->inventory = []; + } + } + // Update the shop + $end->{$name} = $shop; + } + file_put_contents($file, json_encode($end)); + } + + public static function comparator(Item $buy, int $sellcount, array $items) : string { + foreach ($items as $item) { + if (SerializedItem::decode($item->buy)->equals($buy) && SerializedItem::decode($item->sell)->getCount() === $sellcount) { + return $item->sell; + } + } + } + + public static function randomizer(int $lenght) : int { + $buffer = ""; + for ($a = 0; $a < $lenght; $a++) { + $buffer .= rand(0, 9); + } + return (int)$buffer; + } } \ No newline at end of file diff --git a/src/muqsit/invmenu/InvMenu.php b/src/muqsit/invmenu/InvMenu.php new file mode 100644 index 0000000..4e49b1b --- /dev/null +++ b/src/muqsit/invmenu/InvMenu.php @@ -0,0 +1,182 @@ +get($identifier), ...$args); + } + + /** + * @param (Closure(DeterministicInvMenuTransaction) : void)|null $listener + * @return Closure(InvMenuTransaction) : InvMenuTransactionResult + */ + public static function readonly(?Closure $listener = null) : Closure{ + return static function(InvMenuTransaction $transaction) use($listener) : InvMenuTransactionResult{ + $result = $transaction->discard(); + if($listener !== null){ + $listener(new DeterministicInvMenuTransaction($transaction, $result)); + } + return $result; + }; + } + + readonly public InvMenuType $type; + protected ?string $name = null; + protected ?Closure $listener = null; + protected ?Closure $inventory_close_listener = null; + protected Inventory $inventory; + protected ?SharedInvMenuSynchronizer $synchronizer = null; + + public function __construct(InvMenuType $type, ?Inventory $custom_inventory = null){ + if(!InvMenuHandler::isRegistered()){ + throw new LogicException("Tried creating menu before calling " . InvMenuHandler::class . "::register()"); + } + $this->type = $type; + $this->inventory = $this->type->createInventory(); + $this->setInventory($custom_inventory); + } + + /** + * @deprecated Access {@see InvMenu::$type} directly + * @return InvMenuType + */ + public function getType() : InvMenuType{ + return $this->type; + } + + public function getName() : ?string{ + return $this->name; + } + + public function setName(?string $name) : self{ + $this->name = $name; + return $this; + } + + /** + * @param (Closure(InvMenuTransaction) : InvMenuTransactionResult)|null $listener + * @return self + */ + public function setListener(?Closure $listener) : self{ + $this->listener = $listener; + return $this; + } + + /** + * @param (Closure(Player, Inventory) : void)|null $listener + * @return self + */ + public function setInventoryCloseListener(?Closure $listener) : self{ + $this->inventory_close_listener = $listener; + return $this; + } + + /** + * @param Player $player + * @param string|null $name + * @param (Closure(bool) : void)|null $callback + */ + final public function send(Player $player, ?string $name = null, ?Closure $callback = null) : void{ + $player->removeCurrentWindow(); + + $session = InvMenuHandler::getPlayerManager()->get($player); + $network = $session->network; + + // Avoid players from spamming InvMenu::send() and other similar + // requests and filling up queued tasks in memory. + // It would be better if this check were implemented by plugins, + // however I suppose it is more convenient if done within InvMenu... + if($network->getPending() >= 8){ + $network->dropPending(); + }else{ + $network->dropPendingOfType(PlayerNetwork::DELAY_TYPE_OPERATION); + } + + $network->waitUntil(PlayerNetwork::DELAY_TYPE_OPERATION, 0, function(bool $success) use($player, $session, $name, $callback) : bool{ + if(!$success){ + if($callback !== null){ + $callback(false); + } + return false; + } + + $graphic = $this->type->createGraphic($this, $player); + if($graphic !== null){ + $session->setCurrentMenu(new InvMenuInfo($this, $graphic, $name), static function(bool $success) use($callback) : void{ + if($callback !== null){ + $callback($success); + } + }); + }else{ + if($callback !== null){ + $callback(false); + } + } + return false; + }); + } + + public function getInventory() : Inventory{ + return $this->inventory; + } + + public function setInventory(?Inventory $custom_inventory) : void{ + if($this->synchronizer !== null){ + $this->synchronizer->destroy(); + $this->synchronizer = null; + } + + if($custom_inventory !== null){ + $this->synchronizer = new SharedInvMenuSynchronizer($this, $custom_inventory); + } + } + + /** + * @internal use InvMenu::send() instead. + * + * @param Player $player + * @return bool + */ + public function sendInventory(Player $player) : bool{ + return $player->setCurrentWindow($this->getInventory()); + } + + public function handleInventoryTransaction(Player $player, Item $out, Item $in, SlotChangeAction $action, InventoryTransaction $transaction) : InvMenuTransactionResult{ + $inv_menu_txn = new SimpleInvMenuTransaction($player, $out, $in, $action, $transaction); + return $this->listener !== null ? ($this->listener)($inv_menu_txn) : $inv_menu_txn->continue(); + } + + public function onClose(Player $player) : void{ + if($this->inventory_close_listener !== null){ + ($this->inventory_close_listener)($player, $this->getInventory()); + } + + InvMenuHandler::getPlayerManager()->get($player)->removeCurrentMenu(); + } +} diff --git a/src/muqsit/invmenu/InvMenuEventHandler.php b/src/muqsit/invmenu/InvMenuEventHandler.php new file mode 100644 index 0000000..ea48f69 --- /dev/null +++ b/src/muqsit/invmenu/InvMenuEventHandler.php @@ -0,0 +1,97 @@ +getPacket(); + if($packet instanceof NetworkStackLatencyPacket){ + $player = $event->getOrigin()->getPlayer(); + if($player !== null){ + $this->player_manager->getNullable($player)?->network->notify($packet->timestamp); + } + } + } + + /** + * @param InventoryCloseEvent $event + * @priority MONITOR + */ + public function onInventoryClose(InventoryCloseEvent $event) : void{ + $player = $event->getPlayer(); + $session = $this->player_manager->getNullable($player); + if($session === null){ + return; + } + + $current = $session->getCurrent(); + if($current !== null && $event->getInventory() === $current->menu->getInventory()){ + $current->menu->onClose($player); + } + $session->network->waitUntil(PlayerNetwork::DELAY_TYPE_ANIMATION_WAIT, 325, static fn(bool $success) : bool => false); + } + + /** + * @param InventoryTransactionEvent $event + * @priority NORMAL + */ + public function onInventoryTransaction(InventoryTransactionEvent $event) : void{ + $transaction = $event->getTransaction(); + $player = $transaction->getSource(); + + $player_instance = $this->player_manager->get($player); + $current = $player_instance->getCurrent(); + if($current === null){ + return; + } + + $inventory = $current->menu->getInventory(); + $network_stack_callbacks = []; + foreach($transaction->getActions() as $action){ + if(!($action instanceof SlotChangeAction) || $action->getInventory() !== $inventory){ + continue; + } + + $result = $current->menu->handleInventoryTransaction($player, $action->getSourceItem(), $action->getTargetItem(), $action, $transaction); + $network_stack_callback = $result->post_transaction_callback; + if($network_stack_callback !== null){ + $network_stack_callbacks[] = $network_stack_callback; + } + if($result->cancelled){ + $event->cancel(); + break; + } + } + + if(count($network_stack_callbacks) > 0){ + $player_instance->network->wait(PlayerNetwork::DELAY_TYPE_ANIMATION_WAIT, static function(bool $success) use($player, $network_stack_callbacks) : bool{ + if($success){ + foreach($network_stack_callbacks as $callback){ + $callback($player); + } + } + return false; + }); + } + } +} diff --git a/src/muqsit/invmenu/InvMenuHandler.php b/src/muqsit/invmenu/InvMenuHandler.php new file mode 100644 index 0000000..9c5cc9a --- /dev/null +++ b/src/muqsit/invmenu/InvMenuHandler.php @@ -0,0 +1,46 @@ +getName()} attempted to register " . self::class . " twice."); + } + + self::$registrant = $plugin; + self::$type_registry = new InvMenuTypeRegistry(); + self::$player_manager = new PlayerManager(self::getRegistrant()); + Server::getInstance()->getPluginManager()->registerEvents(new InvMenuEventHandler(self::getPlayerManager()), $plugin); + } + + public static function isRegistered() : bool{ + return self::$registrant instanceof Plugin; + } + + public static function getRegistrant() : Plugin{ + return self::$registrant ?? throw new LogicException("Cannot obtain registrant before registration"); + } + + public static function getTypeRegistry() : InvMenuTypeRegistry{ + return self::$type_registry; + } + + public static function getPlayerManager() : PlayerManager{ + return self::$player_manager; + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/inventory/InvMenuInventory.php b/src/muqsit/invmenu/inventory/InvMenuInventory.php new file mode 100644 index 0000000..d13b1fa --- /dev/null +++ b/src/muqsit/invmenu/inventory/InvMenuInventory.php @@ -0,0 +1,23 @@ +holder = new Position(0, 0, 0, null); + } + + public function getHolder() : Position{ + return $this->holder; + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/inventory/SharedInvMenuSynchronizer.php b/src/muqsit/invmenu/inventory/SharedInvMenuSynchronizer.php new file mode 100644 index 0000000..7609b8e --- /dev/null +++ b/src/muqsit/invmenu/inventory/SharedInvMenuSynchronizer.php @@ -0,0 +1,32 @@ +inventory = $inventory; + + $menu_inventory = $menu->getInventory(); + $this->synchronizer = new SharedInventorySynchronizer($menu_inventory); + $inventory->getListeners()->add($this->synchronizer); + + $this->notifier = new SharedInventoryNotifier($this->inventory, $this->synchronizer); + $menu_inventory->setContents($inventory->getContents()); + $menu_inventory->getListeners()->add($this->notifier); + } + + public function destroy() : void{ + $this->synchronizer->getSynchronizingInventory()->getListeners()->remove($this->notifier); + $this->inventory->getListeners()->remove($this->synchronizer); + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/inventory/SharedInventoryNotifier.php b/src/muqsit/invmenu/inventory/SharedInventoryNotifier.php new file mode 100644 index 0000000..0bf39d9 --- /dev/null +++ b/src/muqsit/invmenu/inventory/SharedInventoryNotifier.php @@ -0,0 +1,31 @@ +inventory->getListeners()->remove($this->synchronizer); + $this->inventory->setContents($inventory->getContents()); + $this->inventory->getListeners()->add($this->synchronizer); + } + + public function onSlotChange(Inventory $inventory, int $slot, Item $old_item) : void{ + if($slot < $inventory->getSize()){ + $this->inventory->getListeners()->remove($this->synchronizer); + $this->inventory->setItem($slot, $inventory->getItem($slot)); + $this->inventory->getListeners()->add($this->synchronizer); + } + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/inventory/SharedInventorySynchronizer.php b/src/muqsit/invmenu/inventory/SharedInventorySynchronizer.php new file mode 100644 index 0000000..d41d992 --- /dev/null +++ b/src/muqsit/invmenu/inventory/SharedInventorySynchronizer.php @@ -0,0 +1,28 @@ +inventory; + } + + public function onContentChange(Inventory $inventory, array $old_contents) : void{ + $this->inventory->setContents($inventory->getContents()); + } + + public function onSlotChange(Inventory $inventory, int $slot, Item $old_item) : void{ + $this->inventory->setItem($slot, $inventory->getItem($slot)); + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/session/InvMenuInfo.php b/src/muqsit/invmenu/session/InvMenuInfo.php new file mode 100644 index 0000000..b9c1915 --- /dev/null +++ b/src/muqsit/invmenu/session/InvMenuInfo.php @@ -0,0 +1,17 @@ +network_handler_registry = new PlayerNetworkHandlerRegistry(); + + $plugin_manager = Server::getInstance()->getPluginManager(); + $plugin_manager->registerEvent(PlayerLoginEvent::class, function(PlayerLoginEvent $event) : void{ + $this->create($event->getPlayer()); + }, EventPriority::MONITOR, $registrant); + $plugin_manager->registerEvent(PlayerQuitEvent::class, function(PlayerQuitEvent $event) : void{ + $this->destroy($event->getPlayer()); + }, EventPriority::MONITOR, $registrant); + } + + private function create(Player $player) : void{ + $this->sessions[$player->getId()] = new PlayerSession($player, new PlayerNetwork( + $player->getNetworkSession(), + $this->network_handler_registry->get($player->getPlayerInfo()->getExtraData()["DeviceOS"] ?? -1) + )); + } + + private function destroy(Player $player) : void{ + if(isset($this->sessions[$player_id = $player->getId()])){ + $this->sessions[$player_id]->finalize(); + unset($this->sessions[$player_id]); + } + } + + public function get(Player $player) : PlayerSession{ + return $this->sessions[$player->getId()]; + } + + public function getNullable(Player $player) : ?PlayerSession{ + return $this->sessions[$player->getId()] ?? null; + } + + /** + * @deprecated Access {@see PlayerManager::$network_handler_registry} directly + * @return PlayerNetworkHandlerRegistry + */ + public function getNetworkHandlerRegistry() : PlayerNetworkHandlerRegistry{ + return $this->network_handler_registry; + } +} diff --git a/src/muqsit/invmenu/session/PlayerSession.php b/src/muqsit/invmenu/session/PlayerSession.php new file mode 100644 index 0000000..d546e8d --- /dev/null +++ b/src/muqsit/invmenu/session/PlayerSession.php @@ -0,0 +1,102 @@ +current !== null){ + $this->current->graphic->remove($this->player); + $this->player->removeCurrentWindow(); + } + $this->network->finalize(); + } + + public function getCurrent() : ?InvMenuInfo{ + return $this->current; + } + + /** + * @internal use InvMenu::send() instead. + * + * @param InvMenuInfo|null $current + * @param (Closure(bool) : void)|null $callback + */ + public function setCurrentMenu(?InvMenuInfo $current, ?Closure $callback = null) : void{ + if($this->current !== null){ + $this->current->graphic->remove($this->player); + } + + $this->current = $current; + + if($this->current !== null){ + $current_id = spl_object_id($this->current); + $this->current->graphic->send($this->player, $this->current->graphic_name); + $this->network->waitUntil(PlayerNetwork::DELAY_TYPE_OPERATION, $this->current->graphic->getAnimationDuration(), function(bool $success) use($callback, $current_id) : bool{ + $current = $this->current; + if($current !== null && spl_object_id($current) === $current_id){ + if($success){ + $this->network->onBeforeSendMenu($this, $current); + $result = $current->graphic->sendInventory($this->player, $current->menu->getInventory()); + if($result){ + if($callback !== null){ + $callback(true); + } + return false; + } + } + + $this->removeCurrentMenu(); + } + if($callback !== null){ + $callback(false); + } + return false; + }); + }else{ + $this->network->wait(PlayerNetwork::DELAY_TYPE_ANIMATION_WAIT, static function(bool $success) use($callback) : bool{ + if($callback !== null){ + $callback($success); + } + return false; + }); + } + } + + /** + * @deprecated Access {@see PlayerSession::$network} directly + * @return PlayerNetwork + */ + public function getNetwork() : PlayerNetwork{ + return $this->network; + } + + /** + * @internal use Player::removeCurrentWindow() instead + * @return bool + */ + public function removeCurrentMenu() : bool{ + if($this->current !== null){ + $this->setCurrentMenu(null); + return true; + } + return false; + } +} diff --git a/src/muqsit/invmenu/session/network/NetworkStackLatencyEntry.php b/src/muqsit/invmenu/session/network/NetworkStackLatencyEntry.php new file mode 100644 index 0000000..21eef61 --- /dev/null +++ b/src/muqsit/invmenu/session/network/NetworkStackLatencyEntry.php @@ -0,0 +1,21 @@ +timestamp = $timestamp; + $this->then = $then; + $this->network_timestamp = $network_timestamp ?? $timestamp; + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/session/network/PlayerNetwork.php b/src/muqsit/invmenu/session/network/PlayerNetwork.php new file mode 100644 index 0000000..0e905c3 --- /dev/null +++ b/src/muqsit/invmenu/session/network/PlayerNetwork.php @@ -0,0 +1,230 @@ +|null) */ + private Closure $container_open_callback; + + private ?NetworkStackLatencyEntry $current = null; + private int $graphic_wait_duration = 200; + + /** @var SplQueue */ + private SplQueue $queue; + + /** @var array */ + private array $entry_types = []; + + public function __construct( + readonly private NetworkSession $network_session, + readonly private PlayerNetworkHandler $handler + ){ + $this->queue = new SplQueue(); + $this->nullifyContainerOpenCallback(); + } + + public function finalize() : void{ + $this->dropPending(); + $this->network_session->getInvManager()?->getContainerOpenCallbacks()->remove($this->container_open_callback); + $this->nullifyContainerOpenCallback(); + } + + public function getGraphicWaitDuration() : int{ + return $this->graphic_wait_duration; + } + + /** + * Duration (in milliseconds) to wait between sending the graphic (block) + * and sending the inventory. + * + * @param int $graphic_wait_duration + */ + public function setGraphicWaitDuration(int $graphic_wait_duration) : void{ + if($graphic_wait_duration < 0){ + throw new InvalidArgumentException("graphic_wait_duration must be >= 0, got {$graphic_wait_duration}"); + } + + $this->graphic_wait_duration = $graphic_wait_duration; + } + + public function getPending() : int{ + return $this->queue->count(); + } + + public function dropPending() : void{ + foreach($this->queue as $entry){ + ($entry->then)(false); + } + $this->queue = new SplQueue(); + $this->entry_types = []; + $this->setCurrent(null); + } + + /** + * @param self::DELAY_TYPE_* $type + */ + public function dropPendingOfType(int $type) : void{ + $previous = $this->queue; + $this->queue = new SplQueue(); + foreach($previous as $entry){ + if($this->entry_types[$id = spl_object_id($entry)] === $type){ + ($entry->then)(false); + unset($this->entry_types[$id]); + }else{ + $this->queue->enqueue($entry); + } + } + } + + /** + * @param self::DELAY_TYPE_* $type + * @param Closure(bool) : bool $then + */ + public function wait(int $type, Closure $then) : void{ + $entry = $this->handler->createNetworkStackLatencyEntry($then); + if($this->current !== null){ + $this->queue->enqueue($entry); + $this->entry_types[spl_object_id($entry)] = $type; + }else{ + $this->setCurrent($entry); + } + } + + /** + * Waits at least $wait_ms before calling $then(true). + * + * @param self::DELAY_TYPE_* $type + * @param int $wait_ms + * @param Closure(bool) : bool $then + */ + public function waitUntil(int $type, int $wait_ms, Closure $then) : void{ + if($wait_ms <= 0 && $this->queue->isEmpty()){ + $then(true); + return; + } + + $elapsed_ms = 0.0; + $this->wait($type, function(bool $success) use($wait_ms, $then, &$elapsed_ms) : bool{ + if($this->current === null){ + $then(false); + return false; + } + + $elapsed_ms += (microtime(true) * 1000) - $this->current->sent_at; + if(!$success || $elapsed_ms >= $wait_ms){ + $then($success); + return false; + } + + return true; + }); + } + + private function setCurrent(?NetworkStackLatencyEntry $entry) : void{ + if($this->current !== null){ + $this->processCurrent(false); + } + + $this->current = $entry; + if($entry !== null){ + unset($this->entry_types[spl_object_id($entry)]); + if($this->network_session->sendDataPacket(NetworkStackLatencyPacket::create($entry->network_timestamp, true))){ + $entry->sent_at = microtime(true) * 1000; + }else{ + $this->processCurrent(false); + } + } + } + + private function processCurrent(bool $success) : void{ + if($this->current !== null){ + $current = $this->current; + $repeat = ($current->then)($success); + $this->current = null; + if($repeat && $success){ + $this->setCurrent($current); + }elseif(!$this->queue->isEmpty()){ + $this->setCurrent($this->queue->dequeue()); + } + } + } + + public function notify(int $timestamp) : void{ + if($this->current !== null && $timestamp === $this->current->timestamp){ + $this->processCurrent(true); + } + } + + public function onBeforeSendMenu(PlayerSession $session, InvMenuInfo $info) : void{ + $translator = $info->graphic->getNetworkTranslator(); + if($translator === null){ + return; + } + + $callbacks = $this->network_session->getInvManager()?->getContainerOpenCallbacks(); + if($callbacks === null){ + return; + } + + $callbacks->remove($this->container_open_callback); + + // Take priority over other container open callbacks. + // PocketMine's default container open callback disallows any BlockInventory + // from having a custom callback + $previous = $callbacks->toArray(); + $callbacks->clear(); + $callbacks->add($this->container_open_callback = function(int $window_id, Inventory $inventory) use($info, $session, $translator, $previous, $callbacks) : ?array{ + $callbacks->remove($this->container_open_callback); + $this->nullifyContainerOpenCallback(); + if($inventory === $info->menu->getInventory()){ + $packets = null; + foreach($previous as $callback){ + $packets = $callback($window_id, $inventory); + if($packets !== null){ + break; + } + } + + $packets ??= [ContainerOpenPacket::blockInv( + $window_id, + WindowTypes::CONTAINER, + $inventory instanceof BlockInventory ? BlockPosition::fromVector3($inventory->getHolder()) : new BlockPosition(0, 0, 0) + )]; + + foreach($packets as $packet){ + if($packet instanceof ContainerOpenPacket){ + $translator->translate($session, $info, $packet); + } + } + return $packets; + } + return null; + }, ...$previous); + } + + private function nullifyContainerOpenCallback() : void{ + $this->container_open_callback = static fn(int $window_id, Inventory $inventory) : ?array => null; + } +} diff --git a/src/muqsit/invmenu/session/network/handler/ClosurePlayerNetworkHandler.php b/src/muqsit/invmenu/session/network/handler/ClosurePlayerNetworkHandler.php new file mode 100644 index 0000000..6b2314d --- /dev/null +++ b/src/muqsit/invmenu/session/network/handler/ClosurePlayerNetworkHandler.php @@ -0,0 +1,22 @@ +creator)($then); + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/session/network/handler/PlayerNetworkHandler.php b/src/muqsit/invmenu/session/network/handler/PlayerNetworkHandler.php new file mode 100644 index 0000000..fc38d87 --- /dev/null +++ b/src/muqsit/invmenu/session/network/handler/PlayerNetworkHandler.php @@ -0,0 +1,13 @@ +registerDefault(new ClosurePlayerNetworkHandler(static function(Closure $then) : NetworkStackLatencyEntry{ + return new NetworkStackLatencyEntry(mt_rand() * 1000 /* TODO: remove this hack */, $then); + })); + $this->register(DeviceOS::PLAYSTATION, new ClosurePlayerNetworkHandler(static function(Closure $then) : NetworkStackLatencyEntry{ + $timestamp = mt_rand(); + return new NetworkStackLatencyEntry($timestamp, $then, $timestamp * 1000); + })); + } + + public function registerDefault(PlayerNetworkHandler $handler) : void{ + $this->default = $handler; + } + + public function register(int $os_id, PlayerNetworkHandler $handler) : void{ + $this->game_os_handlers[$os_id] = $handler; + } + + public function get(int $os_id) : PlayerNetworkHandler{ + return $this->game_os_handlers[$os_id] ?? $this->default; + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/transaction/DeterministicInvMenuTransaction.php b/src/muqsit/invmenu/transaction/DeterministicInvMenuTransaction.php new file mode 100644 index 0000000..8a0371e --- /dev/null +++ b/src/muqsit/invmenu/transaction/DeterministicInvMenuTransaction.php @@ -0,0 +1,60 @@ +result->then($callback); + } + + public function getPlayer() : Player{ + return $this->inner->getPlayer(); + } + + public function getOut() : Item{ + return $this->inner->getOut(); + } + + public function getIn() : Item{ + return $this->inner->getIn(); + } + + public function getItemClicked() : Item{ + return $this->inner->getItemClicked(); + } + + public function getItemClickedWith() : Item{ + return $this->inner->getItemClickedWith(); + } + + public function getAction() : SlotChangeAction{ + return $this->inner->getAction(); + } + + public function getTransaction() : InventoryTransaction{ + return $this->inner->getTransaction(); + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/transaction/InvMenuTransaction.php b/src/muqsit/invmenu/transaction/InvMenuTransaction.php new file mode 100644 index 0000000..7db7694 --- /dev/null +++ b/src/muqsit/invmenu/transaction/InvMenuTransaction.php @@ -0,0 +1,43 @@ +cancelled; + } + + /** + * Notify when we have escaped from the event stack trace and the + * client's network stack trace. + * Useful for sending forms and other stuff that cant be sent right + * after closing inventory. + * + * @param (Closure(Player) : void)|null $callback + * @return self + */ + public function then(?Closure $callback) : self{ + $this->post_transaction_callback = $callback; + return $this; + } + + /** + * @deprecated Access {@see InvMenuTransactionResult::$post_transaction_callback} directly + * @return (Closure(Player) : void)|null + */ + public function getPostTransactionCallback() : ?Closure{ + return $this->post_transaction_callback; + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/transaction/SimpleInvMenuTransaction.php b/src/muqsit/invmenu/transaction/SimpleInvMenuTransaction.php new file mode 100644 index 0000000..59dcb48 --- /dev/null +++ b/src/muqsit/invmenu/transaction/SimpleInvMenuTransaction.php @@ -0,0 +1,57 @@ +player; + } + + public function getOut() : Item{ + return $this->out; + } + + public function getIn() : Item{ + return $this->in; + } + + public function getItemClicked() : Item{ + return $this->getOut(); + } + + public function getItemClickedWith() : Item{ + return $this->getIn(); + } + + public function getAction() : SlotChangeAction{ + return $this->action; + } + + public function getTransaction() : InventoryTransaction{ + return $this->transaction; + } + + public function continue() : InvMenuTransactionResult{ + return new InvMenuTransactionResult(false); + } + + public function discard() : InvMenuTransactionResult{ + return new InvMenuTransactionResult(true); + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/ActorFixedInvMenuType.php b/src/muqsit/invmenu/type/ActorFixedInvMenuType.php new file mode 100644 index 0000000..d4b5f74 --- /dev/null +++ b/src/muqsit/invmenu/type/ActorFixedInvMenuType.php @@ -0,0 +1,44 @@ + $actor_metadata + * @param int $size + * @param InvMenuGraphicNetworkTranslator|null $network_translator + */ + public function __construct( + readonly private string $actor_identifier, + readonly private int $actor_runtime_identifier, + readonly private array $actor_metadata, + readonly private int $size, + readonly private ?InvMenuGraphicNetworkTranslator $network_translator = null + ){} + + public function getSize() : int{ + return $this->size; + } + + public function createGraphic(InvMenu $menu, Player $player) : ?InvMenuGraphic{ + return new ActorInvMenuGraphic($this->actor_identifier, $this->actor_runtime_identifier, $this->actor_metadata, $this->network_translator); + } + + public function createInventory() : Inventory{ + return new InvMenuInventory($this->size); + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/BlockActorFixedInvMenuType.php b/src/muqsit/invmenu/type/BlockActorFixedInvMenuType.php new file mode 100644 index 0000000..8303f94 --- /dev/null +++ b/src/muqsit/invmenu/type/BlockActorFixedInvMenuType.php @@ -0,0 +1,54 @@ +size; + } + + public function createGraphic(InvMenu $menu, Player $player) : ?InvMenuGraphic{ + $position = $player->getPosition(); + $origin = $position->addVector(InvMenuTypeHelper::getBehindPositionOffset($player))->floor(); + if(!InvMenuTypeHelper::isValidYCoordinate($origin->y)){ + return null; + } + + $graphics = [new BlockActorInvMenuGraphic($this->block, $origin, BlockActorInvMenuGraphic::createTile($this->tile_id, $menu->getName()), $this->network_translator, $this->animation_duration)]; + foreach(InvMenuTypeHelper::findConnectedBlocks("Chest", $position->getWorld(), $origin, Facing::HORIZONTAL) as $side){ + $graphics[] = new BlockInvMenuGraphic(VanillaBlocks::BARRIER(), $side); + } + + return count($graphics) > 1 ? new MultiBlockInvMenuGraphic($graphics) : $graphics[0]; + } + + public function createInventory() : Inventory{ + return new InvMenuInventory($this->size); + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/BlockFixedInvMenuType.php b/src/muqsit/invmenu/type/BlockFixedInvMenuType.php new file mode 100644 index 0000000..e29d291 --- /dev/null +++ b/src/muqsit/invmenu/type/BlockFixedInvMenuType.php @@ -0,0 +1,41 @@ +size; + } + + public function createGraphic(InvMenu $menu, Player $player) : ?InvMenuGraphic{ + $origin = $player->getPosition()->addVector(InvMenuTypeHelper::getBehindPositionOffset($player))->floor(); + if(!InvMenuTypeHelper::isValidYCoordinate($origin->y)){ + return null; + } + + return new BlockInvMenuGraphic($this->block, $origin, $this->network_translator); + } + + public function createInventory() : Inventory{ + return new InvMenuInventory($this->size); + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/DoublePairableBlockActorFixedInvMenuType.php b/src/muqsit/invmenu/type/DoublePairableBlockActorFixedInvMenuType.php new file mode 100644 index 0000000..fd8ccb6 --- /dev/null +++ b/src/muqsit/invmenu/type/DoublePairableBlockActorFixedInvMenuType.php @@ -0,0 +1,70 @@ +size; + } + + public function createGraphic(InvMenu $menu, Player $player) : ?InvMenuGraphic{ + $position = $player->getPosition(); + $origin = $position->addVector(InvMenuTypeHelper::getBehindPositionOffset($player))->floor(); + if(!InvMenuTypeHelper::isValidYCoordinate($origin->y)){ + return null; + } + + $graphics = []; + $menu_name = $menu->getName(); + $world = $position->getWorld(); + foreach([ + [$origin, $origin->east(), [Facing::NORTH, Facing::SOUTH, Facing::WEST]], + [$origin->east(), $origin, [Facing::NORTH, Facing::SOUTH, Facing::EAST]] + ] as [$origin_pos, $pair_pos, $connected_sides]){ + $graphics[] = new BlockActorInvMenuGraphic( + $this->block, + $origin_pos, + BlockActorInvMenuGraphic::createTile($this->tile_id, $menu_name) + ->setInt(Chest::TAG_PAIRX, $pair_pos->x) + ->setInt(Chest::TAG_PAIRZ, $pair_pos->z), + $this->network_translator, + $this->animation_duration + ); + foreach(InvMenuTypeHelper::findConnectedBlocks("Chest", $world, $origin_pos, $connected_sides) as $side){ + $graphics[] = new BlockInvMenuGraphic(VanillaBlocks::BARRIER(), $side); + } + } + + return count($graphics) > 1 ? new MultiBlockInvMenuGraphic($graphics) : $graphics[0]; + } + + public function createInventory() : Inventory{ + return new InvMenuInventory($this->size); + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/FixedInvMenuType.php b/src/muqsit/invmenu/type/FixedInvMenuType.php new file mode 100644 index 0000000..7f6a5cc --- /dev/null +++ b/src/muqsit/invmenu/type/FixedInvMenuType.php @@ -0,0 +1,18 @@ + */ + private array $types = []; + + /** @var array */ + private array $identifiers = []; + + public function __construct(){ + $this->register(InvMenuTypeIds::TYPE_CHEST, InvMenuTypeBuilders::BLOCK_ACTOR_FIXED() + ->setBlock(VanillaBlocks::CHEST()) + ->setSize(27) + ->setBlockActorId("Chest") + ->build()); + + $this->register(InvMenuTypeIds::TYPE_DOUBLE_CHEST, InvMenuTypeBuilders::DOUBLE_PAIRABLE_BLOCK_ACTOR_FIXED() + ->setBlock(VanillaBlocks::CHEST()) + ->setSize(54) + ->setBlockActorId("Chest") + ->setAnimationDuration(75) + ->build()); + + $this->register(InvMenuTypeIds::TYPE_HOPPER, InvMenuTypeBuilders::BLOCK_ACTOR_FIXED() + ->setBlock(VanillaBlocks::HOPPER()) + ->setSize(5) + ->setBlockActorId("Hopper") + ->setNetworkWindowType(WindowTypes::HOPPER) + ->build()); + } + + public function register(string $identifier, InvMenuType $type) : void{ + if(isset($this->types[$identifier])){ + unset($this->identifiers[spl_object_id($this->types[$identifier])], $this->types[$identifier]); + } + + $this->types[$identifier] = $type; + $this->identifiers[spl_object_id($type)] = $identifier; + } + + public function exists(string $identifier) : bool{ + return isset($this->types[$identifier]); + } + + public function get(string $identifier) : InvMenuType{ + return $this->types[$identifier]; + } + + public function getIdentifier(InvMenuType $type) : string{ + return $this->identifiers[spl_object_id($type)]; + } + + public function getOrNull(string $identifier) : ?InvMenuType{ + return $this->types[$identifier] ?? null; + } + + /** + * @return array + */ + public function getAll() : array{ + return $this->types; + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/graphic/ActorInvMenuGraphic.php b/src/muqsit/invmenu/type/graphic/ActorInvMenuGraphic.php new file mode 100644 index 0000000..89c8e81 --- /dev/null +++ b/src/muqsit/invmenu/type/graphic/ActorInvMenuGraphic.php @@ -0,0 +1,71 @@ + $actor_metadata + * @param InvMenuGraphicNetworkTranslator|null $network_translator + * @param int $animation_duration + */ + public function __construct( + readonly private string $actor_identifier, + readonly private int $actor_runtime_identifier, + readonly private array $actor_metadata, + readonly private ?InvMenuGraphicNetworkTranslator $network_translator = null, + readonly private int $animation_duration = 0 + ){} + + public function send(Player $player, ?string $name) : void{ + $metadata = $this->actor_metadata; + if($name !== null){ + $metadata[EntityMetadataProperties::NAMETAG] = new StringMetadataProperty($name); + } + $player->getNetworkSession()->sendDataPacket(AddActorPacket::create( + $this->actor_runtime_identifier, + $this->actor_runtime_identifier, + $this->actor_identifier, + $player->getPosition()->asVector3(), + null, + 0.0, + 0.0, + 0.0, + 0.0, + [], + $metadata, + new PropertySyncData([], []), + [] + )); + } + + public function sendInventory(Player $player, Inventory $inventory) : bool{ + return $player->setCurrentWindow($inventory); + } + + public function remove(Player $player) : void{ + $player->getNetworkSession()->sendDataPacket(RemoveActorPacket::create($this->actor_runtime_identifier)); + } + + public function getNetworkTranslator() : ?InvMenuGraphicNetworkTranslator{ + return $this->network_translator; + } + + public function getAnimationDuration() : int{ + return $this->animation_duration; + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/graphic/BlockActorInvMenuGraphic.php b/src/muqsit/invmenu/type/graphic/BlockActorInvMenuGraphic.php new file mode 100644 index 0000000..34ef106 --- /dev/null +++ b/src/muqsit/invmenu/type/graphic/BlockActorInvMenuGraphic.php @@ -0,0 +1,70 @@ +setString(Tile::TAG_ID, $tile_id); + if($name !== null){ + $tag->setString(Nameable::TAG_CUSTOM_NAME, $name); + } + return $tag; + } + + readonly private BlockInvMenuGraphic $block_graphic; + readonly private Vector3 $position; + readonly private CompoundTag $tile; + readonly private ?InvMenuGraphicNetworkTranslator $network_translator; + readonly private int $animation_duration; + + public function __construct(Block $block, Vector3 $position, CompoundTag $tile, ?InvMenuGraphicNetworkTranslator $network_translator = null, int $animation_duration = 0){ + $this->block_graphic = new BlockInvMenuGraphic($block, $position); + $this->position = $position; + $this->tile = $tile; + $this->network_translator = $network_translator; + $this->animation_duration = $animation_duration; + } + + public function getPosition() : Vector3{ + return $this->position; + } + + public function send(Player $player, ?string $name) : void{ + $this->block_graphic->send($player, $name); + if($name !== null){ + $this->tile->setString(Nameable::TAG_CUSTOM_NAME, $name); + } + $player->getNetworkSession()->sendDataPacket(BlockActorDataPacket::create(BlockPosition::fromVector3($this->position), new CacheableNbt($this->tile))); + } + + public function sendInventory(Player $player, Inventory $inventory) : bool{ + return $player->setCurrentWindow($inventory); + } + + public function remove(Player $player) : void{ + $this->block_graphic->remove($player); + } + + public function getNetworkTranslator() : ?InvMenuGraphicNetworkTranslator{ + return $this->network_translator; + } + + public function getAnimationDuration() : int{ + return $this->animation_duration; + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/graphic/BlockInvMenuGraphic.php b/src/muqsit/invmenu/type/graphic/BlockInvMenuGraphic.php new file mode 100644 index 0000000..3a8003b --- /dev/null +++ b/src/muqsit/invmenu/type/graphic/BlockInvMenuGraphic.php @@ -0,0 +1,59 @@ +position; + } + + public function send(Player $player, ?string $name) : void{ + $player->getNetworkSession()->sendDataPacket(UpdateBlockPacket::create(BlockPosition::fromVector3($this->position), TypeConverter::getInstance()->getBlockTranslator()->internalIdToNetworkId($this->block->getStateId()), UpdateBlockPacket::FLAG_NETWORK, UpdateBlockPacket::DATA_LAYER_NORMAL)); + } + + public function sendInventory(Player $player, Inventory $inventory) : bool{ + return $player->setCurrentWindow($inventory); + } + + public function remove(Player $player) : void{ + $network = $player->getNetworkSession(); + $world = $player->getWorld(); + $runtime_block_mapping = TypeConverter::getInstance(); + $block = $world->getBlockAt($this->position->x, $this->position->y, $this->position->z); + $network->sendDataPacket(UpdateBlockPacket::create(BlockPosition::fromVector3($this->position), $runtime_block_mapping->getBlockTranslator()->internalIdToNetworkId($block->getStateId()), UpdateBlockPacket::FLAG_NETWORK, UpdateBlockPacket::DATA_LAYER_NORMAL), true); + + $tile = $world->getTileAt($this->position->x, $this->position->y, $this->position->z); + if($tile instanceof Spawnable){ + $network->sendDataPacket(BlockActorDataPacket::create(BlockPosition::fromVector3($this->position), $tile->getSerializedSpawnCompound()), true); + } + } + + public function getNetworkTranslator() : ?InvMenuGraphicNetworkTranslator{ + return $this->network_translator; + } + + public function getAnimationDuration() : int{ + return $this->animation_duration; + } +} diff --git a/src/muqsit/invmenu/type/graphic/InvMenuGraphic.php b/src/muqsit/invmenu/type/graphic/InvMenuGraphic.php new file mode 100644 index 0000000..8c263d7 --- /dev/null +++ b/src/muqsit/invmenu/type/graphic/InvMenuGraphic.php @@ -0,0 +1,28 @@ +graphics); + if($first === false){ + throw new LogicException("Tried sending inventory from a multi graphic consisting of zero entries"); + } + + return $first; + } + + public function send(Player $player, ?string $name) : void{ + foreach($this->graphics as $graphic){ + $graphic->send($player, $name); + } + } + + public function sendInventory(Player $player, Inventory $inventory) : bool{ + return $this->first()->sendInventory($player, $inventory); + } + + public function remove(Player $player) : void{ + foreach($this->graphics as $graphic){ + $graphic->remove($player); + } + } + + public function getNetworkTranslator() : ?InvMenuGraphicNetworkTranslator{ + return $this->first()->getNetworkTranslator(); + } + + public function getPosition() : Vector3{ + return $this->first()->getPosition(); + } + + public function getAnimationDuration() : int{ + $max = 0; + foreach($this->graphics as $graphic){ + $duration = $graphic->getAnimationDuration(); + if($duration > $max){ + $max = $duration; + } + } + return $max; + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/graphic/PositionedInvMenuGraphic.php b/src/muqsit/invmenu/type/graphic/PositionedInvMenuGraphic.php new file mode 100644 index 0000000..8b3c83d --- /dev/null +++ b/src/muqsit/invmenu/type/graphic/PositionedInvMenuGraphic.php @@ -0,0 +1,12 @@ +actorUniqueId = $this->actor_runtime_id; + $packet->blockPosition = new BlockPosition(0, 0, 0); + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/graphic/network/BlockInvMenuGraphicNetworkTranslator.php b/src/muqsit/invmenu/type/graphic/network/BlockInvMenuGraphicNetworkTranslator.php new file mode 100644 index 0000000..3406800 --- /dev/null +++ b/src/muqsit/invmenu/type/graphic/network/BlockInvMenuGraphicNetworkTranslator.php @@ -0,0 +1,33 @@ +graphic; + if(!($graphic instanceof PositionedInvMenuGraphic)){ + throw new InvalidArgumentException("Expected " . PositionedInvMenuGraphic::class . ", got " . get_class($graphic)); + } + + $pos = $graphic->getPosition(); + $packet->blockPosition = new BlockPosition((int) $pos->x, (int) $pos->y, (int) $pos->z); + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/graphic/network/InvMenuGraphicNetworkTranslator.php b/src/muqsit/invmenu/type/graphic/network/InvMenuGraphicNetworkTranslator.php new file mode 100644 index 0000000..5ead44f --- /dev/null +++ b/src/muqsit/invmenu/type/graphic/network/InvMenuGraphicNetworkTranslator.php @@ -0,0 +1,14 @@ +translators as $translator){ + $translator->translate($session, $current, $packet); + } + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/graphic/network/WindowTypeInvMenuGraphicNetworkTranslator.php b/src/muqsit/invmenu/type/graphic/network/WindowTypeInvMenuGraphicNetworkTranslator.php new file mode 100644 index 0000000..af389da --- /dev/null +++ b/src/muqsit/invmenu/type/graphic/network/WindowTypeInvMenuGraphicNetworkTranslator.php @@ -0,0 +1,20 @@ +windowType = $this->window_type; + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/util/InvMenuTypeBuilders.php b/src/muqsit/invmenu/type/util/InvMenuTypeBuilders.php new file mode 100644 index 0000000..a749a14 --- /dev/null +++ b/src/muqsit/invmenu/type/util/InvMenuTypeBuilders.php @@ -0,0 +1,29 @@ +getDirectionVector(); + $size = $player->size; + $offset->x *= -(1 + $size->getWidth()); + $offset->y *= -(1 + $size->getHeight()); + $offset->z *= -(1 + $size->getWidth()); + return $offset; + } + + public static function isValidYCoordinate(float $y) : bool{ + return $y >= self::NETWORK_WORLD_Y_MIN && $y <= self::NETWORK_WORLD_Y_MAX; + } + + /** + * @param string $tile_id + * @param World $world + * @param Vector3 $position + * @param list $sides + * @return Generator + */ + public static function findConnectedBlocks(string $tile_id, World $world, Vector3 $position, array $sides) : Generator{ + if($tile_id === "Chest"){ + // setting a single chest at the spot of a pairable chest sends the client a double chest + // https://github.com/Muqsit/InvMenu/issues/207 + foreach($sides as $side){ + $pos = $position->getSide($side); + $tile = $world->getTileAt($pos->x, $pos->y, $pos->z); + if($tile instanceof Chest && $tile->getPair() !== null){ + yield $pos; + } + } + } + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/util/builder/ActorFixedInvMenuTypeBuilder.php b/src/muqsit/invmenu/type/util/builder/ActorFixedInvMenuTypeBuilder.php new file mode 100644 index 0000000..a43d4f5 --- /dev/null +++ b/src/muqsit/invmenu/type/util/builder/ActorFixedInvMenuTypeBuilder.php @@ -0,0 +1,38 @@ +getActorMetadata(); + $metadata->setFloat(EntityMetadataProperties::BOUNDING_BOX_HEIGHT, 0.01); + $metadata->setFloat(EntityMetadataProperties::BOUNDING_BOX_WIDTH, 0.01); + $metadata->setGenericFlag(EntityMetadataFlags::INVISIBLE, true); + } + + public function setNetworkWindowType(int $window_type) : self{ + $this->parentSetNetworkWindowType($window_type); + $this->getActorMetadata()->setByte(EntityMetadataProperties::CONTAINER_TYPE, $window_type); + return $this; + } + + public function setSize(int $size) : self{ + $this->parentSetSize($size); + $this->getActorMetadata()->setInt(EntityMetadataProperties::CONTAINER_BASE_SIZE, $size); + return $this; + } + + public function build() : ActorFixedInvMenuType{ + return new ActorFixedInvMenuType($this->getActorIdentifier(), $this->getActorRuntimeIdentifier(), $this->getActorMetadata()->getAll(), $this->getSize(), $this->getGraphicNetworkTranslator()); + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/util/builder/ActorInvMenuTypeBuilderTrait.php b/src/muqsit/invmenu/type/util/builder/ActorInvMenuTypeBuilderTrait.php new file mode 100644 index 0000000..1face00 --- /dev/null +++ b/src/muqsit/invmenu/type/util/builder/ActorInvMenuTypeBuilderTrait.php @@ -0,0 +1,45 @@ +actor_runtime_identifier ?? $this->setActorRuntimeIdentifier(Entity::nextRuntimeId())->getActorRuntimeIdentifier(); + } + + public function setActorRuntimeIdentifier(int $actor_runtime_identifier) : self{ + $this->actor_runtime_identifier = $actor_runtime_identifier; + $this->addGraphicNetworkTranslator(new ActorInvMenuGraphicNetworkTranslator($this->actor_runtime_identifier)); + return $this; + } + + public function getActorMetadata() : EntityMetadataCollection{ + return $this->actor_metadata ?? $this->setActorMetadata(new EntityMetadataCollection())->getActorMetadata(); + } + + public function setActorMetadata(EntityMetadataCollection $actor_metadata) : self{ + $this->actor_metadata = $actor_metadata; + return $this; + } + + public function getActorIdentifier() : string{ + return $this->actor_identifier ?? $this->setActorIdentifier(EntityIds::CHEST_MINECART)->getActorIdentifier(); + } + + public function setActorIdentifier(string $actor_identifier) : self{ + $this->actor_identifier = $actor_identifier; + return $this; + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/util/builder/AnimationDurationInvMenuTypeBuilderTrait.php b/src/muqsit/invmenu/type/util/builder/AnimationDurationInvMenuTypeBuilderTrait.php new file mode 100644 index 0000000..e062297 --- /dev/null +++ b/src/muqsit/invmenu/type/util/builder/AnimationDurationInvMenuTypeBuilderTrait.php @@ -0,0 +1,19 @@ +animation_duration = $animation_duration; + return $this; + } + + protected function getAnimationDuration() : int{ + return $this->animation_duration; + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/util/builder/BlockActorFixedInvMenuTypeBuilder.php b/src/muqsit/invmenu/type/util/builder/BlockActorFixedInvMenuTypeBuilder.php new file mode 100644 index 0000000..e3cb3fb --- /dev/null +++ b/src/muqsit/invmenu/type/util/builder/BlockActorFixedInvMenuTypeBuilder.php @@ -0,0 +1,35 @@ +addGraphicNetworkTranslator(BlockInvMenuGraphicNetworkTranslator::instance()); + } + + public function setBlockActorId(string $block_actor_id) : self{ + $this->block_actor_id = $block_actor_id; + return $this; + } + + private function getBlockActorId() : string{ + return $this->block_actor_id ?? throw new LogicException("No block actor ID was specified"); + } + + public function build() : BlockActorFixedInvMenuType{ + return new BlockActorFixedInvMenuType($this->getBlock(), $this->getSize(), $this->getBlockActorId(), $this->getGraphicNetworkTranslator(), $this->getAnimationDuration()); + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/util/builder/BlockFixedInvMenuTypeBuilder.php b/src/muqsit/invmenu/type/util/builder/BlockFixedInvMenuTypeBuilder.php new file mode 100644 index 0000000..afef7a2 --- /dev/null +++ b/src/muqsit/invmenu/type/util/builder/BlockFixedInvMenuTypeBuilder.php @@ -0,0 +1,22 @@ +addGraphicNetworkTranslator(BlockInvMenuGraphicNetworkTranslator::instance()); + } + + public function build() : BlockFixedInvMenuType{ + return new BlockFixedInvMenuType($this->getBlock(), $this->getSize(), $this->getGraphicNetworkTranslator()); + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/util/builder/BlockInvMenuTypeBuilderTrait.php b/src/muqsit/invmenu/type/util/builder/BlockInvMenuTypeBuilderTrait.php new file mode 100644 index 0000000..26ad398 --- /dev/null +++ b/src/muqsit/invmenu/type/util/builder/BlockInvMenuTypeBuilderTrait.php @@ -0,0 +1,22 @@ +block = $block; + return $this; + } + + protected function getBlock() : Block{ + return $this->block ?? throw new LogicException("No block was provided"); + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/util/builder/DoublePairableBlockActorFixedInvMenuTypeBuilder.php b/src/muqsit/invmenu/type/util/builder/DoublePairableBlockActorFixedInvMenuTypeBuilder.php new file mode 100644 index 0000000..a66dd3a --- /dev/null +++ b/src/muqsit/invmenu/type/util/builder/DoublePairableBlockActorFixedInvMenuTypeBuilder.php @@ -0,0 +1,35 @@ +addGraphicNetworkTranslator(BlockInvMenuGraphicNetworkTranslator::instance()); + } + + public function setBlockActorId(string $block_actor_id) : self{ + $this->block_actor_id = $block_actor_id; + return $this; + } + + private function getBlockActorId() : string{ + return $this->block_actor_id ?? throw new LogicException("No block actor ID was specified"); + } + + public function build() : DoublePairableBlockActorFixedInvMenuType{ + return new DoublePairableBlockActorFixedInvMenuType($this->getBlock(), $this->getSize(), $this->getBlockActorId(), $this->getGraphicNetworkTranslator(), $this->getAnimationDuration()); + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/util/builder/FixedInvMenuTypeBuilderTrait.php b/src/muqsit/invmenu/type/util/builder/FixedInvMenuTypeBuilderTrait.php new file mode 100644 index 0000000..a46a26a --- /dev/null +++ b/src/muqsit/invmenu/type/util/builder/FixedInvMenuTypeBuilderTrait.php @@ -0,0 +1,21 @@ +size = $size; + return $this; + } + + protected function getSize() : int{ + return $this->size ?? throw new LogicException("No size was provided"); + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/util/builder/GraphicNetworkTranslatableInvMenuTypeBuilderTrait.php b/src/muqsit/invmenu/type/util/builder/GraphicNetworkTranslatableInvMenuTypeBuilderTrait.php new file mode 100644 index 0000000..31b0d64 --- /dev/null +++ b/src/muqsit/invmenu/type/util/builder/GraphicNetworkTranslatableInvMenuTypeBuilderTrait.php @@ -0,0 +1,37 @@ +graphic_network_translators[] = $translator; + return $this; + } + + public function setNetworkWindowType(int $window_type) : self{ + $this->addGraphicNetworkTranslator(new WindowTypeInvMenuGraphicNetworkTranslator($window_type)); + return $this; + } + + protected function getGraphicNetworkTranslator() : ?InvMenuGraphicNetworkTranslator{ + if(count($this->graphic_network_translators) === 0){ + return null; + } + + if(count($this->graphic_network_translators) === 1){ + return $this->graphic_network_translators[array_key_first($this->graphic_network_translators)]; + } + + return new MultiInvMenuGraphicNetworkTranslator($this->graphic_network_translators); + } +} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/util/builder/InvMenuTypeBuilder.php b/src/muqsit/invmenu/type/util/builder/InvMenuTypeBuilder.php new file mode 100644 index 0000000..ae07040 --- /dev/null +++ b/src/muqsit/invmenu/type/util/builder/InvMenuTypeBuilder.php @@ -0,0 +1,12 @@ + Date: Mon, 26 Jun 2023 14:25:07 +0200 Subject: [PATCH 2/4] Last build before the final relase # THIS IS A DEV BUILD AND BECAUSE OF THIS CAN BE FULL OF BUGS! ## New features - Changed the shop info menu, now more user friendly and with a "Delete" button - Now the Inventory icon in the shop menu won't work at all if the shop is an adminshop - Now if the shop does not exists but the NPC is still here if a player interact with the NPC it will die and an error message will be despawned - Now you can set a limit of NPCs for every shop and a bypass list - Added a "shop name filter" system: Shop names automoderation is finally here! - Now the /sk rename command will work! ## TODO - Book with credits write and some info when /sk info or with a button in sk info menu --- default-config.yml | 20 +++++ plugin.yml | 4 +- src/FoxWorn3365/Shopkeepers/ConfigManager.php | 6 ++ src/FoxWorn3365/Shopkeepers/Core.php | 86 +++++++++++++++---- src/FoxWorn3365/Shopkeepers/EntityManager.php | 22 ++++- .../Shopkeepers/Menu/EditItemMenu.php | 4 +- .../Shopkeepers/Menu/ShopInfoMenu.php | 48 +++++++---- .../Shopkeepers/entity/Shopkeeper.php | 2 +- src/FoxWorn3365/Shopkeepers/utils/Factory.php | 7 ++ src/FoxWorn3365/Shopkeepers/utils/Utils.php | 15 ++++ 10 files changed, 176 insertions(+), 38 deletions(-) create mode 100644 default-config.yml diff --git a/default-config.yml b/default-config.yml new file mode 100644 index 0000000..f05e018 --- /dev/null +++ b/default-config.yml @@ -0,0 +1,20 @@ +# +# Shopkeepers v0.9.1 by FoxWorm3365 +# (C) 2023-now FoxWorn3365 +# +# Relased under the GPL-3.0 license +# https://github.com/FoxWorn3365/Shopkeepers/blob/main/LICENSE +# + +enabled: true + +# Max shopkeeper's entities for one player (PER SHOP) +max-entities-for-player: 5 +# Player that can bypass this limitation +max-entities-bypass: + - YourMinecraftUsername + +# Moderation settings - THIS IS A CONTAIN CONDITION so if you set 'pro' also names like 'apron', 'prototypus', 'proto', 'pro' and it's case INSENSITIVE +banned-shop-names: # Banned shop names, array + - hitler + - nazi \ No newline at end of file diff --git a/plugin.yml b/plugin.yml index c37bcaa..ec4282f 100644 --- a/plugin.yml +++ b/plugin.yml @@ -1,5 +1,5 @@ name: Shopkeepers -version: 0.9.0 +version: 0.9.1 api: 5.0.0 main: FoxWorn3365\Shopkeepers\Core @@ -10,7 +10,7 @@ description: Add shopkeepers to your PocketMine server! commands: shopkeepers: description: The main shopkeepers command - usage: "/shopkeepers [list|create|summon|rename|edit|info|inventory] " + usage: "/shopkeepers [list|create|summon|rename|edit|info] " aliases: - sk - shopk diff --git a/src/FoxWorn3365/Shopkeepers/ConfigManager.php b/src/FoxWorn3365/Shopkeepers/ConfigManager.php index b868b84..6df6aa6 100644 --- a/src/FoxWorn3365/Shopkeepers/ConfigManager.php +++ b/src/FoxWorn3365/Shopkeepers/ConfigManager.php @@ -62,6 +62,12 @@ public function set(string $key, mixed $value) : void { $this->update($config); } + public function remove(string $key) : void { + $config = $this->get(); + unset($config->{$key}); + $this->update($config); + } + public function setSingleKey(string $key) : void { $this->key = $key; } diff --git a/src/FoxWorn3365/Shopkeepers/Core.php b/src/FoxWorn3365/Shopkeepers/Core.php index 1b89022..04d2ea5 100644 --- a/src/FoxWorn3365/Shopkeepers/Core.php +++ b/src/FoxWorn3365/Shopkeepers/Core.php @@ -75,11 +75,13 @@ class Core extends PluginBase implements Listener { protected object $trades; protected object $tradeQueue; + protected string $defaultConfig = "IwojIFNob3BrZWVwZXJzIHYwLjkuMSBieSBGb3hXb3JtMzM2NQojIChDKSAyMDIzLW5vdyBGb3hXb3JuMzM2NQojIAojIFJlbGFzZWQgdW5kZXIgdGhlIEdQTC0zLjAgbGljZW5zZSAKIyBodHRwczovL2dpdGh1Yi5jb20vRm94V29ybjMzNjUvU2hvcGtlZXBlcnMvYmxvYi9tYWluL0xJQ0VOU0UKIwoKZW5hYmxlZDogdHJ1ZQoKIyBNYXggc2hvcGtlZXBlcidzIGVudGl0aWVzIGZvciBvbmUgcGxheWVyIChQRVIgU0hPUCkKbWF4LWVudGl0aWVzLWZvci1wbGF5ZXI6IDUKIyBQbGF5ZXIgdGhhdCBjYW4gYnlwYXNzIHRoaXMgbGltaXRhdGlvbgptYXgtZW50aXRpZXMtYnlwYXNzOgogIC0gWW91ck1pbmVjcmFmdFVzZXJuYW1lCgojIE1vZGVyYXRpb24gc2V0dGluZ3MgICAtIFRISVMgSVMgQSBDT05UQUlOIENPTkRJVElPTiBzbyBpZiB5b3Ugc2V0ICdwcm8nIGFsc28gbmFtZXMgbGlrZSAnYXByb24nLCAncHJvdG90eXB1cycsICdwcm90bycsICdwcm8nIGFuZCBpdCdzIGNhc2UgSU5TRU5TSVRJVkUKYmFubmVkLXNob3AtbmFtZXM6CiAgLSBoaXRsZXIKICAtIG5hemkKCiMgQmFubmVkIHNob3AgaXRlbSBuYW1lcyBzbyB0aGV5IGNhbid0IGJlIHNvbGQgb3IgYm91Z2h0CmJhbm5lZC1pdGVtLW5hbWVzOgogIC0gZGlhbW9uZF9heGUKCiMgQmFubmVkIGl0ZW0gSURzIApiYW5uZWQtaXRlbS1pZHM6CiAgLSAyNTU="; + protected float $server = 5.0; protected const NOT_PERM_MSG = "§cSorry but you don't have permissions to use this command!\nPlease contact your server administrator"; public const AUTHOR = "FoxWorn3365"; - public const VERSION = "0.9-pre"; + public const VERSION = "0.9.1-pre"; public function onLoad() : void { $this->menu = new \stdClass; @@ -105,6 +107,19 @@ public function onEnable() : void { // Register event listener $this->getServer()->getPluginManager()->registerEvents($this, $this); + + // Load the config + if (!file_exists($this->getDataFolder() . "config.yml")) { + file_put_contents($this->getDataFolder() . "config.yml", base64_decode($this->defaultConfig)); + } + + // Open the config + $this->config = new Config($this->getDataFolder() . "config.yml", Config::YAML); + + // Shall we need to disable the plugin? + if (!$this->config->get('enabled', true)) { + $this->getServer()->getPluginManager()->disablePlugin($this); // F + } } public function onPlayerJoin(PlayerJoinEvent $event) { @@ -122,18 +137,23 @@ public function onPlayerEntityInteract(Interaction $event) : void { $entity = $event->getEntity(); if ($entity instanceof Shopkeeper) { $data = $entity->getConfig(); - if ($data->author === $event->getPlayer()->getName() && !$event->getPlayer()->isSneaking()) { + $cm = new ConfigManager($data->author, $this->getDataFolder()); + $cm->setSingleKey($data->shop); + if (@$cm->get()->{$data->shop} === null) { + // Oh no, no config! + $event->getPlayer()->sendMessage("§cSorry but this shop does not exists anymore!"); + // Remove the shop + $this->entities->remove($this->entities->generateEntityHash($event->getEntity())); + $event->getEntity()->kill(); + return; + } elseif ($data->author === $event->getPlayer()->getName() && !$event->getPlayer()->isSneaking()) { // Open the shopkeeper's ~~inventory~~ info page RN! - $cm = new ConfigManager($data->author, $this->getDataFolder()); - $cm->setSingleKey($data->shop); - $menu = new ShopInfoMenu($cm); + $menu = new ShopInfoMenu($cm, true); $menu->create()->send($event->getPlayer()); } else { // It's a shopkeeper! // BEAUTIFUL! // Now let's open the shopkeeper interface - $cm = new ConfigManager($data->author, $this->getDataFolder()); - $cm->setSingleKey($data->shop); $manager = new Manager($cm); $this->trades->{$event->getPlayer()->getName()} = new \stdClass; $this->trades->{$event->getPlayer()->getName()}->config = $data; @@ -146,6 +166,21 @@ public function onEntitySpawn(EntitySpawnEvent $event) : void { if ($event->getEntity() instanceof Shopkeeper) { // Add the shopkeeper to entity interface if (!$event->getEntity()->hasCustomShopkeeperEntityId()) { + // FIRST, check if the limit is not trepassed + $name = $event->getEntity()->getConfig()->shop; + $author = $event->getEntity()->getConfig()->author; + if (@$this->entities->list->{$author}->{$name} !== null) { + if ($this->entities->list->{$author}->{$name} + 1 > $this->config->get('max-entities-for-player', 3) && !in_array($author, $this->config->get('max-entities-bypass', []))) { + // Do not consent + $event->getEntity()->getWorld()->getServer()->getPlayerExact($author)->sendMessage("§cSorry but you have reached the max shopkeepers entity for the shop {$name}\n§rUsed: " . $this->entities->list->{$author}->{$name} ."/" . $this->config->get('max-entities-for-player', 3)); + $event->getEntity()->kill(); + return; + } else { + $this->entities->list->{$author}->{$name}++; + } + } else { + $this->entities->list->{$author}->{$name} = 1; + } $entity = $event->getEntity(); $entity->setCustomShopkeeperEntityId(Utils::randomizer(10)); $this->entities->add($event->getEntity()); @@ -194,6 +229,15 @@ public function onCommand(CommandSender $sender, Command $command, $label, array if (empty($name = $args[1])) { $name = $this->generateRandomString(7); } + + foreach ($this->config->get('banned-shop-names', []) as $banned) { + if (strpos($name, $banned) !== false) { + // Oh crap, this is banned! + $sender->sendMessage("§cSorry but this name is banned!\n§rPlase contact your server administrator"); + return false; + } + } + // Create the config // OOOO why are u running? before, check if there's also an existing name if (@$shop->get()?->{$name} !== null) { @@ -255,31 +299,42 @@ public function onCommand(CommandSender $sender, Command $command, $label, array $shopdata = new \stdClass; $shopdata->author = $sender->getName(); $shopdata->shop = $name; - $villager = new Shopkeeper($pos); + $villager = new Shopkeeper($pos, $shopdata); $villager->setNameTag($name); $villager->setNameTagAlwaysVisible($shop->get()->{$name}->namevisible); - $villager->setConfig($shopdata); $villager->spawnToAll(); // Will be managed by EntitySpawnEvent $this->entities->add($villager); return true; } elseif ($args[0] === "remove" || $args[0] === "despawn") { $sender->sendMessage("To remove a shopkeeper just hit it!"); return true; - } elseif (empty($args[0])) { - if (!$sender->hasPermission("shopkeepers.shop.defaultGUI")) { + } elseif ($args[0] === "rename" && !empty($args[1]) && !empty($args[2])) { + if (!$sender->hasPermission("shopkeepers.shop.rename")) { $sender->sendMessage(self::NOT_PERM_MSG); } - $menu = new InfoMenu(); - $menu->create($sender, $this->getDataFolder())->send($sender); + $name = $args[1]; + if (@$shop->get()?->{$name} === null) { + $sender->sendMessage("You don't have a shop called {$name}!"); + return false; + } + + // Fix name + $shop->set($args[2], $shop->get()->{$name}); + $shop->remove($name); + + $sender->sendMessage("Shop {$name} successfully renamed!"); return true; - } else { + } elseif (empty($args[0])) { if (!$sender->hasPermission("shopkeepers.shop.defaultGUI")) { $sender->sendMessage(self::NOT_PERM_MSG); } $menu = new InfoMenu(); $menu->create($sender, $this->getDataFolder())->send($sender); + return true; + } else { + return false; } return false; } @@ -319,7 +374,6 @@ public function onPacket(DataPacketReceiveEvent $event) : void { $event->getOrigin()->getPlayer()->sendMessage("§cYour inventory is full!"); return; } else { - print_r($result); if ($result->getId() === 25266) { // Is a custom item $item = NbtManager::decode(Utils::comparator($this->trades->{$event->getOrigin()->getPlayer()->getName()}->item, $result->getCount(), $cm->get()->{$cm->getSingleKey()}->items)); @@ -499,9 +553,11 @@ public function onEntityDamage(Damage $event) { if ($event->getDamager() instanceof Player) { if ($event->getEntity()->getConfig()->author === $event->getDamager()->getName() && $event->getDamager()->hasPermission("shopkeepers.shop.remove")) { $this->entities->remove($this->entities->generateEntityHash($event->getEntity())); + $this->entities->list->{$event->getEntity()->getConfig()->author}->{$event->getEntity()->getConfig()->shop}--; $event->getEntity()->kill(); } elseif ($event->getEntity()->getConfig()->author === $event->getDamager()->getName() && $event->getDamager()->hasPermission("shopkeepers.shop.kill")) { $this->entities->remove($this->entities->generateEntityHash($event->getEntity())); + $this->entities->list->{$event->getEntity()->getConfig()->author}->{$event->getEntity()->getConfig()->shop}--; $event->getEntity()->kill(); } else { $event->getDamager()->sendMessage("§cYou can't damage a shopkeeper!"); diff --git a/src/FoxWorn3365/Shopkeepers/EntityManager.php b/src/FoxWorn3365/Shopkeepers/EntityManager.php index a929433..b1571b1 100644 --- a/src/FoxWorn3365/Shopkeepers/EntityManager.php +++ b/src/FoxWorn3365/Shopkeepers/EntityManager.php @@ -29,10 +29,12 @@ class EntityManager { protected string $base; protected array $elements = []; public array $entities = []; + public object $list; function __construct(string $base) { $this->base = $base; $this->retrive(); + $this->list = new \stdClass; } protected function update() : void { @@ -95,7 +97,6 @@ public function remove(string $hash) : void { foreach ($this->elements as $element) { if ($element == $hash) { $this->elements[$count] = null; - unset($this->elements[$count]); $this->update(); return; } @@ -104,9 +105,26 @@ public function remove(string $hash) : void { } public function loadPlayer(Player $player) : void { + if (@$this->list->{$player->getName()} === null) { + $this->list->{$player->getName()} = new \stdClass; + } + $server = $player->getServer(); foreach ($this->elements as $shop) { - self::createEntity($shop, $player->getServer())->spawnTo($player); + if ($shop !== null) { + $entity = self::createEntity($shop, $player->getServer()); + if (@$this->list->{$entity->getConfig()->author} === null) { + $this->list->{$entity->getConfig()->author} = new \stdClass; + $this->list->{$entity->getConfig()->author}->{$entity->getConfig()->shop} = 1; + } else { + if (@$this->list->{$entity->getConfig()->author}->{$entity->getConfig()->shop} !== null) { + $this->list->{$entity->getConfig()->author}->{$entity->getConfig()->shop}++; + } else { + $this->list->{$entity->getConfig()->author}->{$entity->getConfig()->shop} = 1; + } + } + $entity->spawnTo($player); + } } } diff --git a/src/FoxWorn3365/Shopkeepers/Menu/EditItemMenu.php b/src/FoxWorn3365/Shopkeepers/Menu/EditItemMenu.php index c701dce..892d3d2 100644 --- a/src/FoxWorn3365/Shopkeepers/Menu/EditItemMenu.php +++ b/src/FoxWorn3365/Shopkeepers/Menu/EditItemMenu.php @@ -139,11 +139,9 @@ function edit() : InvMenu { // Oh crap, we need to delete this! $config->items[$index] = null; $cm->set($cm->getSingleKey(), $config); - return $transaction->discard(); - /* $retmenu = new EditMenu($cm, $cm->getSingleKey()); $retmenu->create()->send($transaction->getPlayer()); - */ + return $transaction->discard(); break; case 1: $item = $inventory->getItem(10); diff --git a/src/FoxWorn3365/Shopkeepers/Menu/ShopInfoMenu.php b/src/FoxWorn3365/Shopkeepers/Menu/ShopInfoMenu.php index 6f53c3c..82dd58d 100644 --- a/src/FoxWorn3365/Shopkeepers/Menu/ShopInfoMenu.php +++ b/src/FoxWorn3365/Shopkeepers/Menu/ShopInfoMenu.php @@ -28,6 +28,7 @@ use FoxWorn3365\Shopkeepers\utils\Utils; use FoxWorn3365\Shopkeepers\utils\Draw; use FoxWorn3365\Shopkeepers\utils\Factory; +use FoxWorn3365\Shopkeepers\utils\NbtManager; use FoxWorn3365\Shopkeepers\ConfigManager; use FoxWorn3365\Shopkeepers\entity\Shopkeeper; @@ -36,13 +37,15 @@ class ShopInfoMenu { protected InvMenu $menu; protected ConfigManager $cm; protected object $config; + protected bool $local; protected const NOT_PERM_MSG = "§cSorry but you don't have permissions to use this command!\nPlease contact your server administrator"; - function __construct(ConfigManager $cm) { + function __construct(ConfigManager $cm, bool $local = false) { $this->menu = InvMenu::create(InvMenu::TYPE_CHEST); $this->cm = $cm; $this->config = $cm->get()->{$cm->getSingleKey()}; + $this->local = $local; } public function create() : InvMenu { @@ -57,30 +60,36 @@ public function create() : InvMenu { $inventory->setItem(4, Factory::egg($this->cm->getSingleKey())); // Now set the informations - $inventory->setItem(10, Factory::item(377, 0, 'Shop config')); + $inventory->setItem(10, Factory::item(377, 0, '§lConfig')); // Villager inventory if (!$this->config->admin) { - $inventory->setItem(13, Factory::item(54, 0, "Shop inventory")); + $inventory->setItem(12, Factory::item(54, 0, "§lInventory")); } else { - $inventory->setItem(13, Factory::barrier("§cShop inventory\n§rDisabled!\n§oThis is an admin shop!")); // ID: -161 Meta: 0 BRID: 10390 + $inventory->setItem(12, Factory::barrier("§l§cShop inventory\n§rDisabled!\n§oThis is an admin shop!")); // ID: -161 Meta: 0 BRID: 10390 } + // Shop discounts announcer for v1.0 + $inventory->setItem(20, Factory::item(388, 0, "§o§lSales\n\n§r§oThis function will be implemented with the §bSales & Shops §r§oupdate or §lv1.0")); + // Summon option - $inventory->setItem(21, Factory::egg("Summon")); + $inventory->setItem(22, Factory::nbt("0a0000010005436f756e74010800044e616d65000f6d696e6563726166743a736b756c6c02000644616d616765000304000f504d4d504461746156657273696f6e000000000000000100", "§lSummon")); // Misteryous option - $inventory->setItem(23, Factory::barrier("§oUnknown\n\nv1.0")); + $inventory->setItem(24, Factory::barrier("§oUnknown\n\nThis function will be implemented with the §bSales & Shops §r§oupdate or §lv1.0")); // Edit Shopkeepers trades $st = Utils::getItem("minecraft:smithing_table"); - $st->setCustomName("§rEdit shop trades"); - $inventory->setItem(16, $st); + $st->setCustomName("§r§lTrades"); + $inventory->setItem(14, $st); + + $inventory->setItem(16, Factory::item(35, 14, "§c§lDelete")); $cm = $this->cm; $config = $this->config; + $local = $this->local; - $this->menu->setListener(function($transaction) use ($cm, $config) { + $this->menu->setListener(function($transaction) use ($cm, $config, $local) { $slot = $transaction->getAction()->getSlot(); switch ($slot) { case 10: @@ -88,17 +97,20 @@ public function create() : InvMenu { $menu = new ShopConfigMenu($cm); $menu->create()->send($transaction->getPlayer()); break; - case 13: + case 12: // Shop inventory - if (!$transaction->getPlayer()->hasPermission("shopkeepers.shop.allowRemoteInventoryOpen")) { + if (!$transaction->getPlayer()->hasPermission("shopkeepers.shop.allowRemoteInventoryOpen") && !$local) { $transaction->getPlayer()->removeCurrentWindow(); $transaction->getPlayer()->sendMessage(self::NOT_PERM_MSG); break; } - $menu = new ShopInventoryMenu($cm); - $menu->create()->send($transaction->getPlayer()); + + if (!$config->admin) { + $menu = new ShopInventoryMenu($cm); + $menu->create()->send($transaction->getPlayer()); + } break; - case 16: + case 14: if (!$transaction->getPlayer()->hasPermission("shopkeepers.shop.edit")) { $transaction->getPlayer()->removeCurrentWindow(); $transaction->getPlayer()->sendMessage(self::NOT_PERM_MSG); @@ -107,7 +119,13 @@ public function create() : InvMenu { $edit = new EditMenu($cm, $cm->getSingleKey()); $edit->create()->send($transaction->getPlayer()); break; - case 21: + case 16: + // F, we need to delete this + $cm->remove($cm->getSingleKey()); + $transaction->getPlayer()->removeCurrentWindow(); + $transaction->getPlayer()->sendMessage("Your shop named {$cm->getSingleKey()} has been §cdeleted§r with success!"); + break; + case 22: if (!$transaction->getPlayer()->hasPermission("shopkeepers.shop.summon")) { $transaction->getPlayer()->removeCurrentWindow(); $transaction->getPlayer()->sendMessage(self::NOT_PERM_MSG); diff --git a/src/FoxWorn3365/Shopkeepers/entity/Shopkeeper.php b/src/FoxWorn3365/Shopkeepers/entity/Shopkeeper.php index a9dc164..8c6c909 100644 --- a/src/FoxWorn3365/Shopkeepers/entity/Shopkeeper.php +++ b/src/FoxWorn3365/Shopkeepers/entity/Shopkeeper.php @@ -58,7 +58,7 @@ public function getConfig() : object { } public function setCustomShopkeeperEntityId(int $id) : void { - $this->setCustomShopkeeperEntityId = $id; + $this->customShopkeeperEntityId = $id; } public function getCustomShopkeeperEntityId() : ?int { diff --git a/src/FoxWorn3365/Shopkeepers/utils/Factory.php b/src/FoxWorn3365/Shopkeepers/utils/Factory.php index 74a076d..821fadc 100644 --- a/src/FoxWorn3365/Shopkeepers/utils/Factory.php +++ b/src/FoxWorn3365/Shopkeepers/utils/Factory.php @@ -63,4 +63,11 @@ public static function barrier(string $name, int $count = 1) : ?Item { $barrier->setCount($count); return $barrier; } + + public static function nbt(string $nbt, string $name, int $count = 1) { + $item = NbtManager::decode($nbt); + $item->setCustomName("§r{$name}"); + $item->setCount($count); + return $item; + } } \ No newline at end of file diff --git a/src/FoxWorn3365/Shopkeepers/utils/Utils.php b/src/FoxWorn3365/Shopkeepers/utils/Utils.php index cf47cf3..1a1710c 100644 --- a/src/FoxWorn3365/Shopkeepers/utils/Utils.php +++ b/src/FoxWorn3365/Shopkeepers/utils/Utils.php @@ -70,6 +70,11 @@ public static function integrityChecker(string $data_dir) : void { self::shopTypeChecker($data_dir, json_decode($content), $file); } } + + // Now remove empty values from the .entities.json + if (file_exists("{$data_dir}.entities.json")) { + file_put_contents("{$data_dir}.entities.json", json_encode(self::clearArray(json_decode(file_get_contents("{$data_dir}.entities.json"))))); + } // Perfect, ready to go! } @@ -134,4 +139,14 @@ public static function randomizer(int $lenght) : int { } return (int)$buffer; } + + public static function clearArray(array $array) : array { + $return = []; + foreach ($array as $element) { + if ($element !== null) { + $return[] = $element; + } + } + return $return; + } } \ No newline at end of file From fb2a7a1138884380be7866b970985f3599049371 Mon Sep 17 00:00:00 2001 From: FoxWorn3365 Date: Mon, 26 Jun 2023 20:24:11 +0200 Subject: [PATCH 3/4] Updated the readme and the shopkeeper info menu --- README.md | 11 ++++++++++- src/FoxWorn3365/Shopkeepers/Menu/ShopInfoMenu.php | 4 ++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ba721cd..60984d2 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@

--- -

Shopkeepers for PocketMine-MP 5

+

Shopkeepers v0.9.1 for PocketMine-MP 5


**⚠️ We are not in any way related to the [Shopkeepers plugin](https://dev.bukkit.org/projects/shopkeepers) for Bukkit!** @@ -38,6 +38,15 @@ > The Shopkeepers version for PocketMine-MP 4 is available exclusively here on GitHub since InvMenu has versions that are not compatible with each other! > The branch can be found [here](https://github.com/FoxWorn3365/Shopkeepers/tree/pmmp4) +## Configuration +The configuration of **Shopkeepers** allows you to customize some values to make it suitable for all servers. +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| enabled | bool | true | Is the plugin enabled? | +| max-entities-for-player | int | 5 | Max shopkeeper's entities for one player (PER SHOP) | +| max-entities-bypass | array | [] | Player that can bypass this limitation | +| banned-shop-names | array | [] | List of banned names | + ## Commands The base command is `/shopkeepers` but you can also use `/sk`, `/skeepers` and `/shopk` as aliases. Here a list of all commands that you can use: diff --git a/src/FoxWorn3365/Shopkeepers/Menu/ShopInfoMenu.php b/src/FoxWorn3365/Shopkeepers/Menu/ShopInfoMenu.php index 82dd58d..26b0df0 100644 --- a/src/FoxWorn3365/Shopkeepers/Menu/ShopInfoMenu.php +++ b/src/FoxWorn3365/Shopkeepers/Menu/ShopInfoMenu.php @@ -70,13 +70,13 @@ public function create() : InvMenu { } // Shop discounts announcer for v1.0 - $inventory->setItem(20, Factory::item(388, 0, "§o§lSales\n\n§r§oThis function will be implemented with the §bSales & Shops §r§oupdate or §lv1.0")); + $inventory->setItem(20, Factory::item(388, 0, "§o§lSales\n\n§r§oThis function will be implemented with the §bSales & Shops §r§oupdate AKA §lv1.0")); // Summon option $inventory->setItem(22, Factory::nbt("0a0000010005436f756e74010800044e616d65000f6d696e6563726166743a736b756c6c02000644616d616765000304000f504d4d504461746156657273696f6e000000000000000100", "§lSummon")); // Misteryous option - $inventory->setItem(24, Factory::barrier("§oUnknown\n\nThis function will be implemented with the §bSales & Shops §r§oupdate or §lv1.0")); + $inventory->setItem(24, Factory::barrier("§oUnknown\n\nThis function will be implemented with the §bSales & Shops §r§oupdate AKA §lv1.0")); // Edit Shopkeepers trades $st = Utils::getItem("minecraft:smithing_table"); From ce6e7665c321f2af379404f1c53fba42340896a8 Mon Sep 17 00:00:00 2001 From: FoxWorn3365 Date: Mon, 26 Jun 2023 20:26:00 +0200 Subject: [PATCH 4/4] Final build without InvMenu because is a Virion --- src/muqsit/invmenu/InvMenu.php | 182 -------------- src/muqsit/invmenu/InvMenuEventHandler.php | 97 -------- src/muqsit/invmenu/InvMenuHandler.php | 46 ---- .../invmenu/inventory/InvMenuInventory.php | 23 -- .../inventory/SharedInvMenuSynchronizer.php | 32 --- .../inventory/SharedInventoryNotifier.php | 31 --- .../inventory/SharedInventorySynchronizer.php | 28 --- src/muqsit/invmenu/session/InvMenuInfo.php | 17 -- src/muqsit/invmenu/session/PlayerManager.php | 64 ----- src/muqsit/invmenu/session/PlayerSession.php | 102 -------- .../network/NetworkStackLatencyEntry.php | 21 -- .../invmenu/session/network/PlayerNetwork.php | 230 ------------------ .../handler/ClosurePlayerNetworkHandler.php | 22 -- .../network/handler/PlayerNetworkHandler.php | 13 - .../handler/PlayerNetworkHandlerRegistry.php | 39 --- .../DeterministicInvMenuTransaction.php | 60 ----- .../transaction/InvMenuTransaction.php | 43 ---- .../transaction/InvMenuTransactionResult.php | 48 ---- .../transaction/SimpleInvMenuTransaction.php | 57 ----- .../invmenu/type/ActorFixedInvMenuType.php | 44 ---- .../type/BlockActorFixedInvMenuType.php | 54 ---- .../invmenu/type/BlockFixedInvMenuType.php | 41 ---- ...ublePairableBlockActorFixedInvMenuType.php | 70 ------ src/muqsit/invmenu/type/FixedInvMenuType.php | 18 -- src/muqsit/invmenu/type/InvMenuType.php | 17 -- src/muqsit/invmenu/type/InvMenuTypeIds.php | 12 - .../invmenu/type/InvMenuTypeRegistry.php | 72 ------ .../type/graphic/ActorInvMenuGraphic.php | 71 ------ .../type/graphic/BlockActorInvMenuGraphic.php | 70 ------ .../type/graphic/BlockInvMenuGraphic.php | 59 ----- .../invmenu/type/graphic/InvMenuGraphic.php | 28 --- .../type/graphic/MultiBlockInvMenuGraphic.php | 65 ----- .../type/graphic/PositionedInvMenuGraphic.php | 12 - .../ActorInvMenuGraphicNetworkTranslator.php | 22 -- .../BlockInvMenuGraphicNetworkTranslator.php | 33 --- .../InvMenuGraphicNetworkTranslator.php | 14 -- .../MultiInvMenuGraphicNetworkTranslator.php | 25 -- ...dowTypeInvMenuGraphicNetworkTranslator.php | 20 -- .../invmenu/type/util/InvMenuTypeBuilders.php | 29 --- .../invmenu/type/util/InvMenuTypeHelper.php | 52 ---- .../builder/ActorFixedInvMenuTypeBuilder.php | 38 --- .../builder/ActorInvMenuTypeBuilderTrait.php | 45 ---- ...imationDurationInvMenuTypeBuilderTrait.php | 19 -- .../BlockActorFixedInvMenuTypeBuilder.php | 35 --- .../builder/BlockFixedInvMenuTypeBuilder.php | 22 -- .../builder/BlockInvMenuTypeBuilderTrait.php | 22 -- ...rableBlockActorFixedInvMenuTypeBuilder.php | 35 --- .../builder/FixedInvMenuTypeBuilderTrait.php | 21 -- ...orkTranslatableInvMenuTypeBuilderTrait.php | 37 --- .../type/util/builder/InvMenuTypeBuilder.php | 12 - 50 files changed, 2269 deletions(-) delete mode 100644 src/muqsit/invmenu/InvMenu.php delete mode 100644 src/muqsit/invmenu/InvMenuEventHandler.php delete mode 100644 src/muqsit/invmenu/InvMenuHandler.php delete mode 100644 src/muqsit/invmenu/inventory/InvMenuInventory.php delete mode 100644 src/muqsit/invmenu/inventory/SharedInvMenuSynchronizer.php delete mode 100644 src/muqsit/invmenu/inventory/SharedInventoryNotifier.php delete mode 100644 src/muqsit/invmenu/inventory/SharedInventorySynchronizer.php delete mode 100644 src/muqsit/invmenu/session/InvMenuInfo.php delete mode 100644 src/muqsit/invmenu/session/PlayerManager.php delete mode 100644 src/muqsit/invmenu/session/PlayerSession.php delete mode 100644 src/muqsit/invmenu/session/network/NetworkStackLatencyEntry.php delete mode 100644 src/muqsit/invmenu/session/network/PlayerNetwork.php delete mode 100644 src/muqsit/invmenu/session/network/handler/ClosurePlayerNetworkHandler.php delete mode 100644 src/muqsit/invmenu/session/network/handler/PlayerNetworkHandler.php delete mode 100644 src/muqsit/invmenu/session/network/handler/PlayerNetworkHandlerRegistry.php delete mode 100644 src/muqsit/invmenu/transaction/DeterministicInvMenuTransaction.php delete mode 100644 src/muqsit/invmenu/transaction/InvMenuTransaction.php delete mode 100644 src/muqsit/invmenu/transaction/InvMenuTransactionResult.php delete mode 100644 src/muqsit/invmenu/transaction/SimpleInvMenuTransaction.php delete mode 100644 src/muqsit/invmenu/type/ActorFixedInvMenuType.php delete mode 100644 src/muqsit/invmenu/type/BlockActorFixedInvMenuType.php delete mode 100644 src/muqsit/invmenu/type/BlockFixedInvMenuType.php delete mode 100644 src/muqsit/invmenu/type/DoublePairableBlockActorFixedInvMenuType.php delete mode 100644 src/muqsit/invmenu/type/FixedInvMenuType.php delete mode 100644 src/muqsit/invmenu/type/InvMenuType.php delete mode 100644 src/muqsit/invmenu/type/InvMenuTypeIds.php delete mode 100644 src/muqsit/invmenu/type/InvMenuTypeRegistry.php delete mode 100644 src/muqsit/invmenu/type/graphic/ActorInvMenuGraphic.php delete mode 100644 src/muqsit/invmenu/type/graphic/BlockActorInvMenuGraphic.php delete mode 100644 src/muqsit/invmenu/type/graphic/BlockInvMenuGraphic.php delete mode 100644 src/muqsit/invmenu/type/graphic/InvMenuGraphic.php delete mode 100644 src/muqsit/invmenu/type/graphic/MultiBlockInvMenuGraphic.php delete mode 100644 src/muqsit/invmenu/type/graphic/PositionedInvMenuGraphic.php delete mode 100644 src/muqsit/invmenu/type/graphic/network/ActorInvMenuGraphicNetworkTranslator.php delete mode 100644 src/muqsit/invmenu/type/graphic/network/BlockInvMenuGraphicNetworkTranslator.php delete mode 100644 src/muqsit/invmenu/type/graphic/network/InvMenuGraphicNetworkTranslator.php delete mode 100644 src/muqsit/invmenu/type/graphic/network/MultiInvMenuGraphicNetworkTranslator.php delete mode 100644 src/muqsit/invmenu/type/graphic/network/WindowTypeInvMenuGraphicNetworkTranslator.php delete mode 100644 src/muqsit/invmenu/type/util/InvMenuTypeBuilders.php delete mode 100644 src/muqsit/invmenu/type/util/InvMenuTypeHelper.php delete mode 100644 src/muqsit/invmenu/type/util/builder/ActorFixedInvMenuTypeBuilder.php delete mode 100644 src/muqsit/invmenu/type/util/builder/ActorInvMenuTypeBuilderTrait.php delete mode 100644 src/muqsit/invmenu/type/util/builder/AnimationDurationInvMenuTypeBuilderTrait.php delete mode 100644 src/muqsit/invmenu/type/util/builder/BlockActorFixedInvMenuTypeBuilder.php delete mode 100644 src/muqsit/invmenu/type/util/builder/BlockFixedInvMenuTypeBuilder.php delete mode 100644 src/muqsit/invmenu/type/util/builder/BlockInvMenuTypeBuilderTrait.php delete mode 100644 src/muqsit/invmenu/type/util/builder/DoublePairableBlockActorFixedInvMenuTypeBuilder.php delete mode 100644 src/muqsit/invmenu/type/util/builder/FixedInvMenuTypeBuilderTrait.php delete mode 100644 src/muqsit/invmenu/type/util/builder/GraphicNetworkTranslatableInvMenuTypeBuilderTrait.php delete mode 100644 src/muqsit/invmenu/type/util/builder/InvMenuTypeBuilder.php diff --git a/src/muqsit/invmenu/InvMenu.php b/src/muqsit/invmenu/InvMenu.php deleted file mode 100644 index 4e49b1b..0000000 --- a/src/muqsit/invmenu/InvMenu.php +++ /dev/null @@ -1,182 +0,0 @@ -get($identifier), ...$args); - } - - /** - * @param (Closure(DeterministicInvMenuTransaction) : void)|null $listener - * @return Closure(InvMenuTransaction) : InvMenuTransactionResult - */ - public static function readonly(?Closure $listener = null) : Closure{ - return static function(InvMenuTransaction $transaction) use($listener) : InvMenuTransactionResult{ - $result = $transaction->discard(); - if($listener !== null){ - $listener(new DeterministicInvMenuTransaction($transaction, $result)); - } - return $result; - }; - } - - readonly public InvMenuType $type; - protected ?string $name = null; - protected ?Closure $listener = null; - protected ?Closure $inventory_close_listener = null; - protected Inventory $inventory; - protected ?SharedInvMenuSynchronizer $synchronizer = null; - - public function __construct(InvMenuType $type, ?Inventory $custom_inventory = null){ - if(!InvMenuHandler::isRegistered()){ - throw new LogicException("Tried creating menu before calling " . InvMenuHandler::class . "::register()"); - } - $this->type = $type; - $this->inventory = $this->type->createInventory(); - $this->setInventory($custom_inventory); - } - - /** - * @deprecated Access {@see InvMenu::$type} directly - * @return InvMenuType - */ - public function getType() : InvMenuType{ - return $this->type; - } - - public function getName() : ?string{ - return $this->name; - } - - public function setName(?string $name) : self{ - $this->name = $name; - return $this; - } - - /** - * @param (Closure(InvMenuTransaction) : InvMenuTransactionResult)|null $listener - * @return self - */ - public function setListener(?Closure $listener) : self{ - $this->listener = $listener; - return $this; - } - - /** - * @param (Closure(Player, Inventory) : void)|null $listener - * @return self - */ - public function setInventoryCloseListener(?Closure $listener) : self{ - $this->inventory_close_listener = $listener; - return $this; - } - - /** - * @param Player $player - * @param string|null $name - * @param (Closure(bool) : void)|null $callback - */ - final public function send(Player $player, ?string $name = null, ?Closure $callback = null) : void{ - $player->removeCurrentWindow(); - - $session = InvMenuHandler::getPlayerManager()->get($player); - $network = $session->network; - - // Avoid players from spamming InvMenu::send() and other similar - // requests and filling up queued tasks in memory. - // It would be better if this check were implemented by plugins, - // however I suppose it is more convenient if done within InvMenu... - if($network->getPending() >= 8){ - $network->dropPending(); - }else{ - $network->dropPendingOfType(PlayerNetwork::DELAY_TYPE_OPERATION); - } - - $network->waitUntil(PlayerNetwork::DELAY_TYPE_OPERATION, 0, function(bool $success) use($player, $session, $name, $callback) : bool{ - if(!$success){ - if($callback !== null){ - $callback(false); - } - return false; - } - - $graphic = $this->type->createGraphic($this, $player); - if($graphic !== null){ - $session->setCurrentMenu(new InvMenuInfo($this, $graphic, $name), static function(bool $success) use($callback) : void{ - if($callback !== null){ - $callback($success); - } - }); - }else{ - if($callback !== null){ - $callback(false); - } - } - return false; - }); - } - - public function getInventory() : Inventory{ - return $this->inventory; - } - - public function setInventory(?Inventory $custom_inventory) : void{ - if($this->synchronizer !== null){ - $this->synchronizer->destroy(); - $this->synchronizer = null; - } - - if($custom_inventory !== null){ - $this->synchronizer = new SharedInvMenuSynchronizer($this, $custom_inventory); - } - } - - /** - * @internal use InvMenu::send() instead. - * - * @param Player $player - * @return bool - */ - public function sendInventory(Player $player) : bool{ - return $player->setCurrentWindow($this->getInventory()); - } - - public function handleInventoryTransaction(Player $player, Item $out, Item $in, SlotChangeAction $action, InventoryTransaction $transaction) : InvMenuTransactionResult{ - $inv_menu_txn = new SimpleInvMenuTransaction($player, $out, $in, $action, $transaction); - return $this->listener !== null ? ($this->listener)($inv_menu_txn) : $inv_menu_txn->continue(); - } - - public function onClose(Player $player) : void{ - if($this->inventory_close_listener !== null){ - ($this->inventory_close_listener)($player, $this->getInventory()); - } - - InvMenuHandler::getPlayerManager()->get($player)->removeCurrentMenu(); - } -} diff --git a/src/muqsit/invmenu/InvMenuEventHandler.php b/src/muqsit/invmenu/InvMenuEventHandler.php deleted file mode 100644 index ea48f69..0000000 --- a/src/muqsit/invmenu/InvMenuEventHandler.php +++ /dev/null @@ -1,97 +0,0 @@ -getPacket(); - if($packet instanceof NetworkStackLatencyPacket){ - $player = $event->getOrigin()->getPlayer(); - if($player !== null){ - $this->player_manager->getNullable($player)?->network->notify($packet->timestamp); - } - } - } - - /** - * @param InventoryCloseEvent $event - * @priority MONITOR - */ - public function onInventoryClose(InventoryCloseEvent $event) : void{ - $player = $event->getPlayer(); - $session = $this->player_manager->getNullable($player); - if($session === null){ - return; - } - - $current = $session->getCurrent(); - if($current !== null && $event->getInventory() === $current->menu->getInventory()){ - $current->menu->onClose($player); - } - $session->network->waitUntil(PlayerNetwork::DELAY_TYPE_ANIMATION_WAIT, 325, static fn(bool $success) : bool => false); - } - - /** - * @param InventoryTransactionEvent $event - * @priority NORMAL - */ - public function onInventoryTransaction(InventoryTransactionEvent $event) : void{ - $transaction = $event->getTransaction(); - $player = $transaction->getSource(); - - $player_instance = $this->player_manager->get($player); - $current = $player_instance->getCurrent(); - if($current === null){ - return; - } - - $inventory = $current->menu->getInventory(); - $network_stack_callbacks = []; - foreach($transaction->getActions() as $action){ - if(!($action instanceof SlotChangeAction) || $action->getInventory() !== $inventory){ - continue; - } - - $result = $current->menu->handleInventoryTransaction($player, $action->getSourceItem(), $action->getTargetItem(), $action, $transaction); - $network_stack_callback = $result->post_transaction_callback; - if($network_stack_callback !== null){ - $network_stack_callbacks[] = $network_stack_callback; - } - if($result->cancelled){ - $event->cancel(); - break; - } - } - - if(count($network_stack_callbacks) > 0){ - $player_instance->network->wait(PlayerNetwork::DELAY_TYPE_ANIMATION_WAIT, static function(bool $success) use($player, $network_stack_callbacks) : bool{ - if($success){ - foreach($network_stack_callbacks as $callback){ - $callback($player); - } - } - return false; - }); - } - } -} diff --git a/src/muqsit/invmenu/InvMenuHandler.php b/src/muqsit/invmenu/InvMenuHandler.php deleted file mode 100644 index 9c5cc9a..0000000 --- a/src/muqsit/invmenu/InvMenuHandler.php +++ /dev/null @@ -1,46 +0,0 @@ -getName()} attempted to register " . self::class . " twice."); - } - - self::$registrant = $plugin; - self::$type_registry = new InvMenuTypeRegistry(); - self::$player_manager = new PlayerManager(self::getRegistrant()); - Server::getInstance()->getPluginManager()->registerEvents(new InvMenuEventHandler(self::getPlayerManager()), $plugin); - } - - public static function isRegistered() : bool{ - return self::$registrant instanceof Plugin; - } - - public static function getRegistrant() : Plugin{ - return self::$registrant ?? throw new LogicException("Cannot obtain registrant before registration"); - } - - public static function getTypeRegistry() : InvMenuTypeRegistry{ - return self::$type_registry; - } - - public static function getPlayerManager() : PlayerManager{ - return self::$player_manager; - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/inventory/InvMenuInventory.php b/src/muqsit/invmenu/inventory/InvMenuInventory.php deleted file mode 100644 index d13b1fa..0000000 --- a/src/muqsit/invmenu/inventory/InvMenuInventory.php +++ /dev/null @@ -1,23 +0,0 @@ -holder = new Position(0, 0, 0, null); - } - - public function getHolder() : Position{ - return $this->holder; - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/inventory/SharedInvMenuSynchronizer.php b/src/muqsit/invmenu/inventory/SharedInvMenuSynchronizer.php deleted file mode 100644 index 7609b8e..0000000 --- a/src/muqsit/invmenu/inventory/SharedInvMenuSynchronizer.php +++ /dev/null @@ -1,32 +0,0 @@ -inventory = $inventory; - - $menu_inventory = $menu->getInventory(); - $this->synchronizer = new SharedInventorySynchronizer($menu_inventory); - $inventory->getListeners()->add($this->synchronizer); - - $this->notifier = new SharedInventoryNotifier($this->inventory, $this->synchronizer); - $menu_inventory->setContents($inventory->getContents()); - $menu_inventory->getListeners()->add($this->notifier); - } - - public function destroy() : void{ - $this->synchronizer->getSynchronizingInventory()->getListeners()->remove($this->notifier); - $this->inventory->getListeners()->remove($this->synchronizer); - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/inventory/SharedInventoryNotifier.php b/src/muqsit/invmenu/inventory/SharedInventoryNotifier.php deleted file mode 100644 index 0bf39d9..0000000 --- a/src/muqsit/invmenu/inventory/SharedInventoryNotifier.php +++ /dev/null @@ -1,31 +0,0 @@ -inventory->getListeners()->remove($this->synchronizer); - $this->inventory->setContents($inventory->getContents()); - $this->inventory->getListeners()->add($this->synchronizer); - } - - public function onSlotChange(Inventory $inventory, int $slot, Item $old_item) : void{ - if($slot < $inventory->getSize()){ - $this->inventory->getListeners()->remove($this->synchronizer); - $this->inventory->setItem($slot, $inventory->getItem($slot)); - $this->inventory->getListeners()->add($this->synchronizer); - } - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/inventory/SharedInventorySynchronizer.php b/src/muqsit/invmenu/inventory/SharedInventorySynchronizer.php deleted file mode 100644 index d41d992..0000000 --- a/src/muqsit/invmenu/inventory/SharedInventorySynchronizer.php +++ /dev/null @@ -1,28 +0,0 @@ -inventory; - } - - public function onContentChange(Inventory $inventory, array $old_contents) : void{ - $this->inventory->setContents($inventory->getContents()); - } - - public function onSlotChange(Inventory $inventory, int $slot, Item $old_item) : void{ - $this->inventory->setItem($slot, $inventory->getItem($slot)); - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/session/InvMenuInfo.php b/src/muqsit/invmenu/session/InvMenuInfo.php deleted file mode 100644 index b9c1915..0000000 --- a/src/muqsit/invmenu/session/InvMenuInfo.php +++ /dev/null @@ -1,17 +0,0 @@ -network_handler_registry = new PlayerNetworkHandlerRegistry(); - - $plugin_manager = Server::getInstance()->getPluginManager(); - $plugin_manager->registerEvent(PlayerLoginEvent::class, function(PlayerLoginEvent $event) : void{ - $this->create($event->getPlayer()); - }, EventPriority::MONITOR, $registrant); - $plugin_manager->registerEvent(PlayerQuitEvent::class, function(PlayerQuitEvent $event) : void{ - $this->destroy($event->getPlayer()); - }, EventPriority::MONITOR, $registrant); - } - - private function create(Player $player) : void{ - $this->sessions[$player->getId()] = new PlayerSession($player, new PlayerNetwork( - $player->getNetworkSession(), - $this->network_handler_registry->get($player->getPlayerInfo()->getExtraData()["DeviceOS"] ?? -1) - )); - } - - private function destroy(Player $player) : void{ - if(isset($this->sessions[$player_id = $player->getId()])){ - $this->sessions[$player_id]->finalize(); - unset($this->sessions[$player_id]); - } - } - - public function get(Player $player) : PlayerSession{ - return $this->sessions[$player->getId()]; - } - - public function getNullable(Player $player) : ?PlayerSession{ - return $this->sessions[$player->getId()] ?? null; - } - - /** - * @deprecated Access {@see PlayerManager::$network_handler_registry} directly - * @return PlayerNetworkHandlerRegistry - */ - public function getNetworkHandlerRegistry() : PlayerNetworkHandlerRegistry{ - return $this->network_handler_registry; - } -} diff --git a/src/muqsit/invmenu/session/PlayerSession.php b/src/muqsit/invmenu/session/PlayerSession.php deleted file mode 100644 index d546e8d..0000000 --- a/src/muqsit/invmenu/session/PlayerSession.php +++ /dev/null @@ -1,102 +0,0 @@ -current !== null){ - $this->current->graphic->remove($this->player); - $this->player->removeCurrentWindow(); - } - $this->network->finalize(); - } - - public function getCurrent() : ?InvMenuInfo{ - return $this->current; - } - - /** - * @internal use InvMenu::send() instead. - * - * @param InvMenuInfo|null $current - * @param (Closure(bool) : void)|null $callback - */ - public function setCurrentMenu(?InvMenuInfo $current, ?Closure $callback = null) : void{ - if($this->current !== null){ - $this->current->graphic->remove($this->player); - } - - $this->current = $current; - - if($this->current !== null){ - $current_id = spl_object_id($this->current); - $this->current->graphic->send($this->player, $this->current->graphic_name); - $this->network->waitUntil(PlayerNetwork::DELAY_TYPE_OPERATION, $this->current->graphic->getAnimationDuration(), function(bool $success) use($callback, $current_id) : bool{ - $current = $this->current; - if($current !== null && spl_object_id($current) === $current_id){ - if($success){ - $this->network->onBeforeSendMenu($this, $current); - $result = $current->graphic->sendInventory($this->player, $current->menu->getInventory()); - if($result){ - if($callback !== null){ - $callback(true); - } - return false; - } - } - - $this->removeCurrentMenu(); - } - if($callback !== null){ - $callback(false); - } - return false; - }); - }else{ - $this->network->wait(PlayerNetwork::DELAY_TYPE_ANIMATION_WAIT, static function(bool $success) use($callback) : bool{ - if($callback !== null){ - $callback($success); - } - return false; - }); - } - } - - /** - * @deprecated Access {@see PlayerSession::$network} directly - * @return PlayerNetwork - */ - public function getNetwork() : PlayerNetwork{ - return $this->network; - } - - /** - * @internal use Player::removeCurrentWindow() instead - * @return bool - */ - public function removeCurrentMenu() : bool{ - if($this->current !== null){ - $this->setCurrentMenu(null); - return true; - } - return false; - } -} diff --git a/src/muqsit/invmenu/session/network/NetworkStackLatencyEntry.php b/src/muqsit/invmenu/session/network/NetworkStackLatencyEntry.php deleted file mode 100644 index 21eef61..0000000 --- a/src/muqsit/invmenu/session/network/NetworkStackLatencyEntry.php +++ /dev/null @@ -1,21 +0,0 @@ -timestamp = $timestamp; - $this->then = $then; - $this->network_timestamp = $network_timestamp ?? $timestamp; - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/session/network/PlayerNetwork.php b/src/muqsit/invmenu/session/network/PlayerNetwork.php deleted file mode 100644 index 0e905c3..0000000 --- a/src/muqsit/invmenu/session/network/PlayerNetwork.php +++ /dev/null @@ -1,230 +0,0 @@ -|null) */ - private Closure $container_open_callback; - - private ?NetworkStackLatencyEntry $current = null; - private int $graphic_wait_duration = 200; - - /** @var SplQueue */ - private SplQueue $queue; - - /** @var array */ - private array $entry_types = []; - - public function __construct( - readonly private NetworkSession $network_session, - readonly private PlayerNetworkHandler $handler - ){ - $this->queue = new SplQueue(); - $this->nullifyContainerOpenCallback(); - } - - public function finalize() : void{ - $this->dropPending(); - $this->network_session->getInvManager()?->getContainerOpenCallbacks()->remove($this->container_open_callback); - $this->nullifyContainerOpenCallback(); - } - - public function getGraphicWaitDuration() : int{ - return $this->graphic_wait_duration; - } - - /** - * Duration (in milliseconds) to wait between sending the graphic (block) - * and sending the inventory. - * - * @param int $graphic_wait_duration - */ - public function setGraphicWaitDuration(int $graphic_wait_duration) : void{ - if($graphic_wait_duration < 0){ - throw new InvalidArgumentException("graphic_wait_duration must be >= 0, got {$graphic_wait_duration}"); - } - - $this->graphic_wait_duration = $graphic_wait_duration; - } - - public function getPending() : int{ - return $this->queue->count(); - } - - public function dropPending() : void{ - foreach($this->queue as $entry){ - ($entry->then)(false); - } - $this->queue = new SplQueue(); - $this->entry_types = []; - $this->setCurrent(null); - } - - /** - * @param self::DELAY_TYPE_* $type - */ - public function dropPendingOfType(int $type) : void{ - $previous = $this->queue; - $this->queue = new SplQueue(); - foreach($previous as $entry){ - if($this->entry_types[$id = spl_object_id($entry)] === $type){ - ($entry->then)(false); - unset($this->entry_types[$id]); - }else{ - $this->queue->enqueue($entry); - } - } - } - - /** - * @param self::DELAY_TYPE_* $type - * @param Closure(bool) : bool $then - */ - public function wait(int $type, Closure $then) : void{ - $entry = $this->handler->createNetworkStackLatencyEntry($then); - if($this->current !== null){ - $this->queue->enqueue($entry); - $this->entry_types[spl_object_id($entry)] = $type; - }else{ - $this->setCurrent($entry); - } - } - - /** - * Waits at least $wait_ms before calling $then(true). - * - * @param self::DELAY_TYPE_* $type - * @param int $wait_ms - * @param Closure(bool) : bool $then - */ - public function waitUntil(int $type, int $wait_ms, Closure $then) : void{ - if($wait_ms <= 0 && $this->queue->isEmpty()){ - $then(true); - return; - } - - $elapsed_ms = 0.0; - $this->wait($type, function(bool $success) use($wait_ms, $then, &$elapsed_ms) : bool{ - if($this->current === null){ - $then(false); - return false; - } - - $elapsed_ms += (microtime(true) * 1000) - $this->current->sent_at; - if(!$success || $elapsed_ms >= $wait_ms){ - $then($success); - return false; - } - - return true; - }); - } - - private function setCurrent(?NetworkStackLatencyEntry $entry) : void{ - if($this->current !== null){ - $this->processCurrent(false); - } - - $this->current = $entry; - if($entry !== null){ - unset($this->entry_types[spl_object_id($entry)]); - if($this->network_session->sendDataPacket(NetworkStackLatencyPacket::create($entry->network_timestamp, true))){ - $entry->sent_at = microtime(true) * 1000; - }else{ - $this->processCurrent(false); - } - } - } - - private function processCurrent(bool $success) : void{ - if($this->current !== null){ - $current = $this->current; - $repeat = ($current->then)($success); - $this->current = null; - if($repeat && $success){ - $this->setCurrent($current); - }elseif(!$this->queue->isEmpty()){ - $this->setCurrent($this->queue->dequeue()); - } - } - } - - public function notify(int $timestamp) : void{ - if($this->current !== null && $timestamp === $this->current->timestamp){ - $this->processCurrent(true); - } - } - - public function onBeforeSendMenu(PlayerSession $session, InvMenuInfo $info) : void{ - $translator = $info->graphic->getNetworkTranslator(); - if($translator === null){ - return; - } - - $callbacks = $this->network_session->getInvManager()?->getContainerOpenCallbacks(); - if($callbacks === null){ - return; - } - - $callbacks->remove($this->container_open_callback); - - // Take priority over other container open callbacks. - // PocketMine's default container open callback disallows any BlockInventory - // from having a custom callback - $previous = $callbacks->toArray(); - $callbacks->clear(); - $callbacks->add($this->container_open_callback = function(int $window_id, Inventory $inventory) use($info, $session, $translator, $previous, $callbacks) : ?array{ - $callbacks->remove($this->container_open_callback); - $this->nullifyContainerOpenCallback(); - if($inventory === $info->menu->getInventory()){ - $packets = null; - foreach($previous as $callback){ - $packets = $callback($window_id, $inventory); - if($packets !== null){ - break; - } - } - - $packets ??= [ContainerOpenPacket::blockInv( - $window_id, - WindowTypes::CONTAINER, - $inventory instanceof BlockInventory ? BlockPosition::fromVector3($inventory->getHolder()) : new BlockPosition(0, 0, 0) - )]; - - foreach($packets as $packet){ - if($packet instanceof ContainerOpenPacket){ - $translator->translate($session, $info, $packet); - } - } - return $packets; - } - return null; - }, ...$previous); - } - - private function nullifyContainerOpenCallback() : void{ - $this->container_open_callback = static fn(int $window_id, Inventory $inventory) : ?array => null; - } -} diff --git a/src/muqsit/invmenu/session/network/handler/ClosurePlayerNetworkHandler.php b/src/muqsit/invmenu/session/network/handler/ClosurePlayerNetworkHandler.php deleted file mode 100644 index 6b2314d..0000000 --- a/src/muqsit/invmenu/session/network/handler/ClosurePlayerNetworkHandler.php +++ /dev/null @@ -1,22 +0,0 @@ -creator)($then); - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/session/network/handler/PlayerNetworkHandler.php b/src/muqsit/invmenu/session/network/handler/PlayerNetworkHandler.php deleted file mode 100644 index fc38d87..0000000 --- a/src/muqsit/invmenu/session/network/handler/PlayerNetworkHandler.php +++ /dev/null @@ -1,13 +0,0 @@ -registerDefault(new ClosurePlayerNetworkHandler(static function(Closure $then) : NetworkStackLatencyEntry{ - return new NetworkStackLatencyEntry(mt_rand() * 1000 /* TODO: remove this hack */, $then); - })); - $this->register(DeviceOS::PLAYSTATION, new ClosurePlayerNetworkHandler(static function(Closure $then) : NetworkStackLatencyEntry{ - $timestamp = mt_rand(); - return new NetworkStackLatencyEntry($timestamp, $then, $timestamp * 1000); - })); - } - - public function registerDefault(PlayerNetworkHandler $handler) : void{ - $this->default = $handler; - } - - public function register(int $os_id, PlayerNetworkHandler $handler) : void{ - $this->game_os_handlers[$os_id] = $handler; - } - - public function get(int $os_id) : PlayerNetworkHandler{ - return $this->game_os_handlers[$os_id] ?? $this->default; - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/transaction/DeterministicInvMenuTransaction.php b/src/muqsit/invmenu/transaction/DeterministicInvMenuTransaction.php deleted file mode 100644 index 8a0371e..0000000 --- a/src/muqsit/invmenu/transaction/DeterministicInvMenuTransaction.php +++ /dev/null @@ -1,60 +0,0 @@ -result->then($callback); - } - - public function getPlayer() : Player{ - return $this->inner->getPlayer(); - } - - public function getOut() : Item{ - return $this->inner->getOut(); - } - - public function getIn() : Item{ - return $this->inner->getIn(); - } - - public function getItemClicked() : Item{ - return $this->inner->getItemClicked(); - } - - public function getItemClickedWith() : Item{ - return $this->inner->getItemClickedWith(); - } - - public function getAction() : SlotChangeAction{ - return $this->inner->getAction(); - } - - public function getTransaction() : InventoryTransaction{ - return $this->inner->getTransaction(); - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/transaction/InvMenuTransaction.php b/src/muqsit/invmenu/transaction/InvMenuTransaction.php deleted file mode 100644 index 7db7694..0000000 --- a/src/muqsit/invmenu/transaction/InvMenuTransaction.php +++ /dev/null @@ -1,43 +0,0 @@ -cancelled; - } - - /** - * Notify when we have escaped from the event stack trace and the - * client's network stack trace. - * Useful for sending forms and other stuff that cant be sent right - * after closing inventory. - * - * @param (Closure(Player) : void)|null $callback - * @return self - */ - public function then(?Closure $callback) : self{ - $this->post_transaction_callback = $callback; - return $this; - } - - /** - * @deprecated Access {@see InvMenuTransactionResult::$post_transaction_callback} directly - * @return (Closure(Player) : void)|null - */ - public function getPostTransactionCallback() : ?Closure{ - return $this->post_transaction_callback; - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/transaction/SimpleInvMenuTransaction.php b/src/muqsit/invmenu/transaction/SimpleInvMenuTransaction.php deleted file mode 100644 index 59dcb48..0000000 --- a/src/muqsit/invmenu/transaction/SimpleInvMenuTransaction.php +++ /dev/null @@ -1,57 +0,0 @@ -player; - } - - public function getOut() : Item{ - return $this->out; - } - - public function getIn() : Item{ - return $this->in; - } - - public function getItemClicked() : Item{ - return $this->getOut(); - } - - public function getItemClickedWith() : Item{ - return $this->getIn(); - } - - public function getAction() : SlotChangeAction{ - return $this->action; - } - - public function getTransaction() : InventoryTransaction{ - return $this->transaction; - } - - public function continue() : InvMenuTransactionResult{ - return new InvMenuTransactionResult(false); - } - - public function discard() : InvMenuTransactionResult{ - return new InvMenuTransactionResult(true); - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/ActorFixedInvMenuType.php b/src/muqsit/invmenu/type/ActorFixedInvMenuType.php deleted file mode 100644 index d4b5f74..0000000 --- a/src/muqsit/invmenu/type/ActorFixedInvMenuType.php +++ /dev/null @@ -1,44 +0,0 @@ - $actor_metadata - * @param int $size - * @param InvMenuGraphicNetworkTranslator|null $network_translator - */ - public function __construct( - readonly private string $actor_identifier, - readonly private int $actor_runtime_identifier, - readonly private array $actor_metadata, - readonly private int $size, - readonly private ?InvMenuGraphicNetworkTranslator $network_translator = null - ){} - - public function getSize() : int{ - return $this->size; - } - - public function createGraphic(InvMenu $menu, Player $player) : ?InvMenuGraphic{ - return new ActorInvMenuGraphic($this->actor_identifier, $this->actor_runtime_identifier, $this->actor_metadata, $this->network_translator); - } - - public function createInventory() : Inventory{ - return new InvMenuInventory($this->size); - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/BlockActorFixedInvMenuType.php b/src/muqsit/invmenu/type/BlockActorFixedInvMenuType.php deleted file mode 100644 index 8303f94..0000000 --- a/src/muqsit/invmenu/type/BlockActorFixedInvMenuType.php +++ /dev/null @@ -1,54 +0,0 @@ -size; - } - - public function createGraphic(InvMenu $menu, Player $player) : ?InvMenuGraphic{ - $position = $player->getPosition(); - $origin = $position->addVector(InvMenuTypeHelper::getBehindPositionOffset($player))->floor(); - if(!InvMenuTypeHelper::isValidYCoordinate($origin->y)){ - return null; - } - - $graphics = [new BlockActorInvMenuGraphic($this->block, $origin, BlockActorInvMenuGraphic::createTile($this->tile_id, $menu->getName()), $this->network_translator, $this->animation_duration)]; - foreach(InvMenuTypeHelper::findConnectedBlocks("Chest", $position->getWorld(), $origin, Facing::HORIZONTAL) as $side){ - $graphics[] = new BlockInvMenuGraphic(VanillaBlocks::BARRIER(), $side); - } - - return count($graphics) > 1 ? new MultiBlockInvMenuGraphic($graphics) : $graphics[0]; - } - - public function createInventory() : Inventory{ - return new InvMenuInventory($this->size); - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/BlockFixedInvMenuType.php b/src/muqsit/invmenu/type/BlockFixedInvMenuType.php deleted file mode 100644 index e29d291..0000000 --- a/src/muqsit/invmenu/type/BlockFixedInvMenuType.php +++ /dev/null @@ -1,41 +0,0 @@ -size; - } - - public function createGraphic(InvMenu $menu, Player $player) : ?InvMenuGraphic{ - $origin = $player->getPosition()->addVector(InvMenuTypeHelper::getBehindPositionOffset($player))->floor(); - if(!InvMenuTypeHelper::isValidYCoordinate($origin->y)){ - return null; - } - - return new BlockInvMenuGraphic($this->block, $origin, $this->network_translator); - } - - public function createInventory() : Inventory{ - return new InvMenuInventory($this->size); - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/DoublePairableBlockActorFixedInvMenuType.php b/src/muqsit/invmenu/type/DoublePairableBlockActorFixedInvMenuType.php deleted file mode 100644 index fd8ccb6..0000000 --- a/src/muqsit/invmenu/type/DoublePairableBlockActorFixedInvMenuType.php +++ /dev/null @@ -1,70 +0,0 @@ -size; - } - - public function createGraphic(InvMenu $menu, Player $player) : ?InvMenuGraphic{ - $position = $player->getPosition(); - $origin = $position->addVector(InvMenuTypeHelper::getBehindPositionOffset($player))->floor(); - if(!InvMenuTypeHelper::isValidYCoordinate($origin->y)){ - return null; - } - - $graphics = []; - $menu_name = $menu->getName(); - $world = $position->getWorld(); - foreach([ - [$origin, $origin->east(), [Facing::NORTH, Facing::SOUTH, Facing::WEST]], - [$origin->east(), $origin, [Facing::NORTH, Facing::SOUTH, Facing::EAST]] - ] as [$origin_pos, $pair_pos, $connected_sides]){ - $graphics[] = new BlockActorInvMenuGraphic( - $this->block, - $origin_pos, - BlockActorInvMenuGraphic::createTile($this->tile_id, $menu_name) - ->setInt(Chest::TAG_PAIRX, $pair_pos->x) - ->setInt(Chest::TAG_PAIRZ, $pair_pos->z), - $this->network_translator, - $this->animation_duration - ); - foreach(InvMenuTypeHelper::findConnectedBlocks("Chest", $world, $origin_pos, $connected_sides) as $side){ - $graphics[] = new BlockInvMenuGraphic(VanillaBlocks::BARRIER(), $side); - } - } - - return count($graphics) > 1 ? new MultiBlockInvMenuGraphic($graphics) : $graphics[0]; - } - - public function createInventory() : Inventory{ - return new InvMenuInventory($this->size); - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/FixedInvMenuType.php b/src/muqsit/invmenu/type/FixedInvMenuType.php deleted file mode 100644 index 7f6a5cc..0000000 --- a/src/muqsit/invmenu/type/FixedInvMenuType.php +++ /dev/null @@ -1,18 +0,0 @@ - */ - private array $types = []; - - /** @var array */ - private array $identifiers = []; - - public function __construct(){ - $this->register(InvMenuTypeIds::TYPE_CHEST, InvMenuTypeBuilders::BLOCK_ACTOR_FIXED() - ->setBlock(VanillaBlocks::CHEST()) - ->setSize(27) - ->setBlockActorId("Chest") - ->build()); - - $this->register(InvMenuTypeIds::TYPE_DOUBLE_CHEST, InvMenuTypeBuilders::DOUBLE_PAIRABLE_BLOCK_ACTOR_FIXED() - ->setBlock(VanillaBlocks::CHEST()) - ->setSize(54) - ->setBlockActorId("Chest") - ->setAnimationDuration(75) - ->build()); - - $this->register(InvMenuTypeIds::TYPE_HOPPER, InvMenuTypeBuilders::BLOCK_ACTOR_FIXED() - ->setBlock(VanillaBlocks::HOPPER()) - ->setSize(5) - ->setBlockActorId("Hopper") - ->setNetworkWindowType(WindowTypes::HOPPER) - ->build()); - } - - public function register(string $identifier, InvMenuType $type) : void{ - if(isset($this->types[$identifier])){ - unset($this->identifiers[spl_object_id($this->types[$identifier])], $this->types[$identifier]); - } - - $this->types[$identifier] = $type; - $this->identifiers[spl_object_id($type)] = $identifier; - } - - public function exists(string $identifier) : bool{ - return isset($this->types[$identifier]); - } - - public function get(string $identifier) : InvMenuType{ - return $this->types[$identifier]; - } - - public function getIdentifier(InvMenuType $type) : string{ - return $this->identifiers[spl_object_id($type)]; - } - - public function getOrNull(string $identifier) : ?InvMenuType{ - return $this->types[$identifier] ?? null; - } - - /** - * @return array - */ - public function getAll() : array{ - return $this->types; - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/graphic/ActorInvMenuGraphic.php b/src/muqsit/invmenu/type/graphic/ActorInvMenuGraphic.php deleted file mode 100644 index 89c8e81..0000000 --- a/src/muqsit/invmenu/type/graphic/ActorInvMenuGraphic.php +++ /dev/null @@ -1,71 +0,0 @@ - $actor_metadata - * @param InvMenuGraphicNetworkTranslator|null $network_translator - * @param int $animation_duration - */ - public function __construct( - readonly private string $actor_identifier, - readonly private int $actor_runtime_identifier, - readonly private array $actor_metadata, - readonly private ?InvMenuGraphicNetworkTranslator $network_translator = null, - readonly private int $animation_duration = 0 - ){} - - public function send(Player $player, ?string $name) : void{ - $metadata = $this->actor_metadata; - if($name !== null){ - $metadata[EntityMetadataProperties::NAMETAG] = new StringMetadataProperty($name); - } - $player->getNetworkSession()->sendDataPacket(AddActorPacket::create( - $this->actor_runtime_identifier, - $this->actor_runtime_identifier, - $this->actor_identifier, - $player->getPosition()->asVector3(), - null, - 0.0, - 0.0, - 0.0, - 0.0, - [], - $metadata, - new PropertySyncData([], []), - [] - )); - } - - public function sendInventory(Player $player, Inventory $inventory) : bool{ - return $player->setCurrentWindow($inventory); - } - - public function remove(Player $player) : void{ - $player->getNetworkSession()->sendDataPacket(RemoveActorPacket::create($this->actor_runtime_identifier)); - } - - public function getNetworkTranslator() : ?InvMenuGraphicNetworkTranslator{ - return $this->network_translator; - } - - public function getAnimationDuration() : int{ - return $this->animation_duration; - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/graphic/BlockActorInvMenuGraphic.php b/src/muqsit/invmenu/type/graphic/BlockActorInvMenuGraphic.php deleted file mode 100644 index 34ef106..0000000 --- a/src/muqsit/invmenu/type/graphic/BlockActorInvMenuGraphic.php +++ /dev/null @@ -1,70 +0,0 @@ -setString(Tile::TAG_ID, $tile_id); - if($name !== null){ - $tag->setString(Nameable::TAG_CUSTOM_NAME, $name); - } - return $tag; - } - - readonly private BlockInvMenuGraphic $block_graphic; - readonly private Vector3 $position; - readonly private CompoundTag $tile; - readonly private ?InvMenuGraphicNetworkTranslator $network_translator; - readonly private int $animation_duration; - - public function __construct(Block $block, Vector3 $position, CompoundTag $tile, ?InvMenuGraphicNetworkTranslator $network_translator = null, int $animation_duration = 0){ - $this->block_graphic = new BlockInvMenuGraphic($block, $position); - $this->position = $position; - $this->tile = $tile; - $this->network_translator = $network_translator; - $this->animation_duration = $animation_duration; - } - - public function getPosition() : Vector3{ - return $this->position; - } - - public function send(Player $player, ?string $name) : void{ - $this->block_graphic->send($player, $name); - if($name !== null){ - $this->tile->setString(Nameable::TAG_CUSTOM_NAME, $name); - } - $player->getNetworkSession()->sendDataPacket(BlockActorDataPacket::create(BlockPosition::fromVector3($this->position), new CacheableNbt($this->tile))); - } - - public function sendInventory(Player $player, Inventory $inventory) : bool{ - return $player->setCurrentWindow($inventory); - } - - public function remove(Player $player) : void{ - $this->block_graphic->remove($player); - } - - public function getNetworkTranslator() : ?InvMenuGraphicNetworkTranslator{ - return $this->network_translator; - } - - public function getAnimationDuration() : int{ - return $this->animation_duration; - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/graphic/BlockInvMenuGraphic.php b/src/muqsit/invmenu/type/graphic/BlockInvMenuGraphic.php deleted file mode 100644 index 3a8003b..0000000 --- a/src/muqsit/invmenu/type/graphic/BlockInvMenuGraphic.php +++ /dev/null @@ -1,59 +0,0 @@ -position; - } - - public function send(Player $player, ?string $name) : void{ - $player->getNetworkSession()->sendDataPacket(UpdateBlockPacket::create(BlockPosition::fromVector3($this->position), TypeConverter::getInstance()->getBlockTranslator()->internalIdToNetworkId($this->block->getStateId()), UpdateBlockPacket::FLAG_NETWORK, UpdateBlockPacket::DATA_LAYER_NORMAL)); - } - - public function sendInventory(Player $player, Inventory $inventory) : bool{ - return $player->setCurrentWindow($inventory); - } - - public function remove(Player $player) : void{ - $network = $player->getNetworkSession(); - $world = $player->getWorld(); - $runtime_block_mapping = TypeConverter::getInstance(); - $block = $world->getBlockAt($this->position->x, $this->position->y, $this->position->z); - $network->sendDataPacket(UpdateBlockPacket::create(BlockPosition::fromVector3($this->position), $runtime_block_mapping->getBlockTranslator()->internalIdToNetworkId($block->getStateId()), UpdateBlockPacket::FLAG_NETWORK, UpdateBlockPacket::DATA_LAYER_NORMAL), true); - - $tile = $world->getTileAt($this->position->x, $this->position->y, $this->position->z); - if($tile instanceof Spawnable){ - $network->sendDataPacket(BlockActorDataPacket::create(BlockPosition::fromVector3($this->position), $tile->getSerializedSpawnCompound()), true); - } - } - - public function getNetworkTranslator() : ?InvMenuGraphicNetworkTranslator{ - return $this->network_translator; - } - - public function getAnimationDuration() : int{ - return $this->animation_duration; - } -} diff --git a/src/muqsit/invmenu/type/graphic/InvMenuGraphic.php b/src/muqsit/invmenu/type/graphic/InvMenuGraphic.php deleted file mode 100644 index 8c263d7..0000000 --- a/src/muqsit/invmenu/type/graphic/InvMenuGraphic.php +++ /dev/null @@ -1,28 +0,0 @@ -graphics); - if($first === false){ - throw new LogicException("Tried sending inventory from a multi graphic consisting of zero entries"); - } - - return $first; - } - - public function send(Player $player, ?string $name) : void{ - foreach($this->graphics as $graphic){ - $graphic->send($player, $name); - } - } - - public function sendInventory(Player $player, Inventory $inventory) : bool{ - return $this->first()->sendInventory($player, $inventory); - } - - public function remove(Player $player) : void{ - foreach($this->graphics as $graphic){ - $graphic->remove($player); - } - } - - public function getNetworkTranslator() : ?InvMenuGraphicNetworkTranslator{ - return $this->first()->getNetworkTranslator(); - } - - public function getPosition() : Vector3{ - return $this->first()->getPosition(); - } - - public function getAnimationDuration() : int{ - $max = 0; - foreach($this->graphics as $graphic){ - $duration = $graphic->getAnimationDuration(); - if($duration > $max){ - $max = $duration; - } - } - return $max; - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/graphic/PositionedInvMenuGraphic.php b/src/muqsit/invmenu/type/graphic/PositionedInvMenuGraphic.php deleted file mode 100644 index 8b3c83d..0000000 --- a/src/muqsit/invmenu/type/graphic/PositionedInvMenuGraphic.php +++ /dev/null @@ -1,12 +0,0 @@ -actorUniqueId = $this->actor_runtime_id; - $packet->blockPosition = new BlockPosition(0, 0, 0); - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/graphic/network/BlockInvMenuGraphicNetworkTranslator.php b/src/muqsit/invmenu/type/graphic/network/BlockInvMenuGraphicNetworkTranslator.php deleted file mode 100644 index 3406800..0000000 --- a/src/muqsit/invmenu/type/graphic/network/BlockInvMenuGraphicNetworkTranslator.php +++ /dev/null @@ -1,33 +0,0 @@ -graphic; - if(!($graphic instanceof PositionedInvMenuGraphic)){ - throw new InvalidArgumentException("Expected " . PositionedInvMenuGraphic::class . ", got " . get_class($graphic)); - } - - $pos = $graphic->getPosition(); - $packet->blockPosition = new BlockPosition((int) $pos->x, (int) $pos->y, (int) $pos->z); - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/graphic/network/InvMenuGraphicNetworkTranslator.php b/src/muqsit/invmenu/type/graphic/network/InvMenuGraphicNetworkTranslator.php deleted file mode 100644 index 5ead44f..0000000 --- a/src/muqsit/invmenu/type/graphic/network/InvMenuGraphicNetworkTranslator.php +++ /dev/null @@ -1,14 +0,0 @@ -translators as $translator){ - $translator->translate($session, $current, $packet); - } - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/graphic/network/WindowTypeInvMenuGraphicNetworkTranslator.php b/src/muqsit/invmenu/type/graphic/network/WindowTypeInvMenuGraphicNetworkTranslator.php deleted file mode 100644 index af389da..0000000 --- a/src/muqsit/invmenu/type/graphic/network/WindowTypeInvMenuGraphicNetworkTranslator.php +++ /dev/null @@ -1,20 +0,0 @@ -windowType = $this->window_type; - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/util/InvMenuTypeBuilders.php b/src/muqsit/invmenu/type/util/InvMenuTypeBuilders.php deleted file mode 100644 index a749a14..0000000 --- a/src/muqsit/invmenu/type/util/InvMenuTypeBuilders.php +++ /dev/null @@ -1,29 +0,0 @@ -getDirectionVector(); - $size = $player->size; - $offset->x *= -(1 + $size->getWidth()); - $offset->y *= -(1 + $size->getHeight()); - $offset->z *= -(1 + $size->getWidth()); - return $offset; - } - - public static function isValidYCoordinate(float $y) : bool{ - return $y >= self::NETWORK_WORLD_Y_MIN && $y <= self::NETWORK_WORLD_Y_MAX; - } - - /** - * @param string $tile_id - * @param World $world - * @param Vector3 $position - * @param list $sides - * @return Generator - */ - public static function findConnectedBlocks(string $tile_id, World $world, Vector3 $position, array $sides) : Generator{ - if($tile_id === "Chest"){ - // setting a single chest at the spot of a pairable chest sends the client a double chest - // https://github.com/Muqsit/InvMenu/issues/207 - foreach($sides as $side){ - $pos = $position->getSide($side); - $tile = $world->getTileAt($pos->x, $pos->y, $pos->z); - if($tile instanceof Chest && $tile->getPair() !== null){ - yield $pos; - } - } - } - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/util/builder/ActorFixedInvMenuTypeBuilder.php b/src/muqsit/invmenu/type/util/builder/ActorFixedInvMenuTypeBuilder.php deleted file mode 100644 index a43d4f5..0000000 --- a/src/muqsit/invmenu/type/util/builder/ActorFixedInvMenuTypeBuilder.php +++ /dev/null @@ -1,38 +0,0 @@ -getActorMetadata(); - $metadata->setFloat(EntityMetadataProperties::BOUNDING_BOX_HEIGHT, 0.01); - $metadata->setFloat(EntityMetadataProperties::BOUNDING_BOX_WIDTH, 0.01); - $metadata->setGenericFlag(EntityMetadataFlags::INVISIBLE, true); - } - - public function setNetworkWindowType(int $window_type) : self{ - $this->parentSetNetworkWindowType($window_type); - $this->getActorMetadata()->setByte(EntityMetadataProperties::CONTAINER_TYPE, $window_type); - return $this; - } - - public function setSize(int $size) : self{ - $this->parentSetSize($size); - $this->getActorMetadata()->setInt(EntityMetadataProperties::CONTAINER_BASE_SIZE, $size); - return $this; - } - - public function build() : ActorFixedInvMenuType{ - return new ActorFixedInvMenuType($this->getActorIdentifier(), $this->getActorRuntimeIdentifier(), $this->getActorMetadata()->getAll(), $this->getSize(), $this->getGraphicNetworkTranslator()); - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/util/builder/ActorInvMenuTypeBuilderTrait.php b/src/muqsit/invmenu/type/util/builder/ActorInvMenuTypeBuilderTrait.php deleted file mode 100644 index 1face00..0000000 --- a/src/muqsit/invmenu/type/util/builder/ActorInvMenuTypeBuilderTrait.php +++ /dev/null @@ -1,45 +0,0 @@ -actor_runtime_identifier ?? $this->setActorRuntimeIdentifier(Entity::nextRuntimeId())->getActorRuntimeIdentifier(); - } - - public function setActorRuntimeIdentifier(int $actor_runtime_identifier) : self{ - $this->actor_runtime_identifier = $actor_runtime_identifier; - $this->addGraphicNetworkTranslator(new ActorInvMenuGraphicNetworkTranslator($this->actor_runtime_identifier)); - return $this; - } - - public function getActorMetadata() : EntityMetadataCollection{ - return $this->actor_metadata ?? $this->setActorMetadata(new EntityMetadataCollection())->getActorMetadata(); - } - - public function setActorMetadata(EntityMetadataCollection $actor_metadata) : self{ - $this->actor_metadata = $actor_metadata; - return $this; - } - - public function getActorIdentifier() : string{ - return $this->actor_identifier ?? $this->setActorIdentifier(EntityIds::CHEST_MINECART)->getActorIdentifier(); - } - - public function setActorIdentifier(string $actor_identifier) : self{ - $this->actor_identifier = $actor_identifier; - return $this; - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/util/builder/AnimationDurationInvMenuTypeBuilderTrait.php b/src/muqsit/invmenu/type/util/builder/AnimationDurationInvMenuTypeBuilderTrait.php deleted file mode 100644 index e062297..0000000 --- a/src/muqsit/invmenu/type/util/builder/AnimationDurationInvMenuTypeBuilderTrait.php +++ /dev/null @@ -1,19 +0,0 @@ -animation_duration = $animation_duration; - return $this; - } - - protected function getAnimationDuration() : int{ - return $this->animation_duration; - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/util/builder/BlockActorFixedInvMenuTypeBuilder.php b/src/muqsit/invmenu/type/util/builder/BlockActorFixedInvMenuTypeBuilder.php deleted file mode 100644 index e3cb3fb..0000000 --- a/src/muqsit/invmenu/type/util/builder/BlockActorFixedInvMenuTypeBuilder.php +++ /dev/null @@ -1,35 +0,0 @@ -addGraphicNetworkTranslator(BlockInvMenuGraphicNetworkTranslator::instance()); - } - - public function setBlockActorId(string $block_actor_id) : self{ - $this->block_actor_id = $block_actor_id; - return $this; - } - - private function getBlockActorId() : string{ - return $this->block_actor_id ?? throw new LogicException("No block actor ID was specified"); - } - - public function build() : BlockActorFixedInvMenuType{ - return new BlockActorFixedInvMenuType($this->getBlock(), $this->getSize(), $this->getBlockActorId(), $this->getGraphicNetworkTranslator(), $this->getAnimationDuration()); - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/util/builder/BlockFixedInvMenuTypeBuilder.php b/src/muqsit/invmenu/type/util/builder/BlockFixedInvMenuTypeBuilder.php deleted file mode 100644 index afef7a2..0000000 --- a/src/muqsit/invmenu/type/util/builder/BlockFixedInvMenuTypeBuilder.php +++ /dev/null @@ -1,22 +0,0 @@ -addGraphicNetworkTranslator(BlockInvMenuGraphicNetworkTranslator::instance()); - } - - public function build() : BlockFixedInvMenuType{ - return new BlockFixedInvMenuType($this->getBlock(), $this->getSize(), $this->getGraphicNetworkTranslator()); - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/util/builder/BlockInvMenuTypeBuilderTrait.php b/src/muqsit/invmenu/type/util/builder/BlockInvMenuTypeBuilderTrait.php deleted file mode 100644 index 26ad398..0000000 --- a/src/muqsit/invmenu/type/util/builder/BlockInvMenuTypeBuilderTrait.php +++ /dev/null @@ -1,22 +0,0 @@ -block = $block; - return $this; - } - - protected function getBlock() : Block{ - return $this->block ?? throw new LogicException("No block was provided"); - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/util/builder/DoublePairableBlockActorFixedInvMenuTypeBuilder.php b/src/muqsit/invmenu/type/util/builder/DoublePairableBlockActorFixedInvMenuTypeBuilder.php deleted file mode 100644 index a66dd3a..0000000 --- a/src/muqsit/invmenu/type/util/builder/DoublePairableBlockActorFixedInvMenuTypeBuilder.php +++ /dev/null @@ -1,35 +0,0 @@ -addGraphicNetworkTranslator(BlockInvMenuGraphicNetworkTranslator::instance()); - } - - public function setBlockActorId(string $block_actor_id) : self{ - $this->block_actor_id = $block_actor_id; - return $this; - } - - private function getBlockActorId() : string{ - return $this->block_actor_id ?? throw new LogicException("No block actor ID was specified"); - } - - public function build() : DoublePairableBlockActorFixedInvMenuType{ - return new DoublePairableBlockActorFixedInvMenuType($this->getBlock(), $this->getSize(), $this->getBlockActorId(), $this->getGraphicNetworkTranslator(), $this->getAnimationDuration()); - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/util/builder/FixedInvMenuTypeBuilderTrait.php b/src/muqsit/invmenu/type/util/builder/FixedInvMenuTypeBuilderTrait.php deleted file mode 100644 index a46a26a..0000000 --- a/src/muqsit/invmenu/type/util/builder/FixedInvMenuTypeBuilderTrait.php +++ /dev/null @@ -1,21 +0,0 @@ -size = $size; - return $this; - } - - protected function getSize() : int{ - return $this->size ?? throw new LogicException("No size was provided"); - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/util/builder/GraphicNetworkTranslatableInvMenuTypeBuilderTrait.php b/src/muqsit/invmenu/type/util/builder/GraphicNetworkTranslatableInvMenuTypeBuilderTrait.php deleted file mode 100644 index 31b0d64..0000000 --- a/src/muqsit/invmenu/type/util/builder/GraphicNetworkTranslatableInvMenuTypeBuilderTrait.php +++ /dev/null @@ -1,37 +0,0 @@ -graphic_network_translators[] = $translator; - return $this; - } - - public function setNetworkWindowType(int $window_type) : self{ - $this->addGraphicNetworkTranslator(new WindowTypeInvMenuGraphicNetworkTranslator($window_type)); - return $this; - } - - protected function getGraphicNetworkTranslator() : ?InvMenuGraphicNetworkTranslator{ - if(count($this->graphic_network_translators) === 0){ - return null; - } - - if(count($this->graphic_network_translators) === 1){ - return $this->graphic_network_translators[array_key_first($this->graphic_network_translators)]; - } - - return new MultiInvMenuGraphicNetworkTranslator($this->graphic_network_translators); - } -} \ No newline at end of file diff --git a/src/muqsit/invmenu/type/util/builder/InvMenuTypeBuilder.php b/src/muqsit/invmenu/type/util/builder/InvMenuTypeBuilder.php deleted file mode 100644 index ae07040..0000000 --- a/src/muqsit/invmenu/type/util/builder/InvMenuTypeBuilder.php +++ /dev/null @@ -1,12 +0,0 @@ -