Skip to content

Commit

Permalink
Merge pull request #8 from FoxWorn3365/pmmp5-dev
Browse files Browse the repository at this point in the history
Updated the stable version from the dev branch
  • Loading branch information
FoxWorn3365 authored Jun 26, 2023
2 parents e9227bf + ce6e766 commit 9749565
Show file tree
Hide file tree
Showing 15 changed files with 383 additions and 65 deletions.
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
</p>

---
<h1 align="center">Shopkeepers for PocketMine-MP 5</h1>
<h1 align="center">Shopkeepers v0.9.1 for PocketMine-MP 5</h1>
<br>

**⚠️ We are not in any way related to the [Shopkeepers plugin](https://dev.bukkit.org/projects/shopkeepers) for Bukkit!**
Expand All @@ -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:
Expand Down
20 changes: 20 additions & 0 deletions default-config.yml
Original file line number Diff line number Diff line change
@@ -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
4 changes: 2 additions & 2 deletions plugin.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: Shopkeepers
version: 0.8.2
version: 0.9.1
api: 5.0.0

main: FoxWorn3365\Shopkeepers\Core
Expand All @@ -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] <NAME>"
usage: "/shopkeepers [list|create|summon|rename|edit|info] <NAME>"
aliases:
- sk
- shopk
Expand Down
6 changes: 6 additions & 0 deletions src/FoxWorn3365/Shopkeepers/ConfigManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
134 changes: 102 additions & 32 deletions src/FoxWorn3365/Shopkeepers/Core.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -74,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";
protected const AUTHOR = "FoxWorn3365";
protected const VERSION = "0.8.2-pre-relase";
public const AUTHOR = "FoxWorn3365";
public const VERSION = "0.9.1-pre";

public function onLoad() : void {
$this->menu = new \stdClass;
Expand All @@ -104,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) {
Expand All @@ -121,26 +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()) {
// Open the shopkeeper's inventory 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());
}
$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!
$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;
Expand All @@ -149,7 +162,33 @@ 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()) {
// 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());
}
}
}

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;
Expand Down Expand Up @@ -190,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) {
Expand Down Expand Up @@ -251,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();
$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!");
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;
}
Expand Down Expand Up @@ -315,13 +374,19 @@ public function onPacket(DataPacketReceiveEvent $event) : void {
$event->getOrigin()->getPlayer()->sendMessage("§cYour inventory is full!");
return;
} else {
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();
Expand Down Expand Up @@ -354,14 +419,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;
}
}
}
Expand Down Expand Up @@ -485,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!");
Expand Down
Loading

0 comments on commit 9749565

Please sign in to comment.