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 @@
-